zoontek / react-native-permissions

An unified permissions API for React Native on iOS, Android and Windows.
MIT License
4.1k stars 836 forks source link

[Android] 'Don't Allow' permission option always returns denied as permission status and doesn't request the permission again #870

Closed DaliaElhefny closed 7 months ago

DaliaElhefny commented 7 months ago

Before submitting a new issue

Bug summary

I'm requesting location permission in my app ACCESS_FINE_LOCATION and faced unexpected behavior When requesting the location permission the OS alert appears and then I select Don't allow option

Expected:

Actual:

Library version

4.1.5

Environment info

System:
    OS: macOS 14.4
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    Memory: 17.24 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.0.0 - ~/.nvm/versions/node/v18.0.0/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 8.6.0 - ~/.nvm/versions/node/v18.0.0/bin/npm
    Watchman: 2023.03.20.00 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.11.3 - /Users/my-user/.rbenv/shims/pod
  SDKs:
    iOS SDK:
      Platforms: DriverKit 23.4, iOS 17.4, macOS 14.4, tvOS 17.4, visionOS 1.1, watchOS 10.4
    Android SDK: Not Found
  IDEs:
    Android Studio: 2023.1 AI-231.9392.1.2311.11076708
    Xcode: 15.3/15E204a - /usr/bin/xcodebuild
  Languages:
    Java: 11.0.15 - /Library/Java/JavaVirtualMachines/jdk-11.0.15.jdk/Contents/Home/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 18.2.0 => 18.2.0 
    react-native: 0.71.14 => 0.71.14 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps to reproduce

  1. Use the code below in an empty screen
  2. You'll see a button and a text showing the status of the permission with denied
  3. Click on the button to request location, an OS alert will appear then choose Don't Allow option
  4. Kill the app and re-open it again then navigate to the screen that contains this code
  5. You'll find the status shown with 'denied'
  6. Click on the button to request location, nothing happens (although the status is denied, the OS alert won't be displayed again)

Reproducible sample code

import React, { useEffect, useState } from 'react'

import { Pressable, Text, View } from 'react-native'
import { request, check } from 'react-native-permissions'

const DeviceSettings = () => {
  const [status, setStatus] = useState('')

  useEffect(() => {
    getLocationPermissionStatus()
  }, [])

  const getLocationPermissionStatus = async () => {
    const result = await check('android.permission.ACCESS_FINE_LOCATION')
    setStatus(result)
  }

  const requestLocationPermission = async () => {
    const result = await request('android.permission.ACCESS_FINE_LOCATION')
    console.log('location permission request result', result)
  }

  return (
    <View
      style={{
        flex: 1,
        backgroundColor: 'white',
        alignItems: 'center',
        justifyContent: 'center'
      }}
    >
      <View style={{ flexDirection: 'row', margin: 20 }}>
        <Text style={{ fontSize: 16 }}>Location permission status: </Text>
        <Text style={{ fontWeight: 'bold', fontSize: 16, color: 'red' }}>
          {status}
        </Text>
      </View>
      <Pressable
        style={{
          borderRadius: 6,
          borderWidth: 1,
          padding: 20,
          backgroundColor: 'black'
        }}
        onPress={requestLocationPermission}
      >
        <Text style={{ color: 'white', fontWeight: 'bold', fontSize: 16 }}>
          Request location permission
        </Text>
      </Pressable>
    </View>
  )
}

export default DeviceSettings
zoontek commented 7 months ago

ACCESS_FINE_LOCATION should be required with ACCESS_COARSE_LOCATION (using requestMultiple): https://developer.android.com/develop/sensors-and-location/location/permissions#approximate-request

DaliaElhefny commented 7 months ago

@zoontek but this issue also happens with READ_PHONE_STATE permission

To clarify my issue more: When requesting a permission and then choose Don't Allow option, the returned result is 'blocked' but when call check() to get the status it returns denied from what I understand denied status means that it is requestable but it is not

Also try this steps on the above code to undrstand the conflict more:

  1. Make sure in your device settings that the location permission access is Ask every time
  2. Open the screen that contains the code, you'll find the status denied
  3. Click on Request location permission button, the OS alert will appear then choose Don't Allow and check your terminal for logs you can search with location permission request result in your terminal, you'll find the logged result is denied (which means that it is requestable)
  4. Click on Request location permission button again, the OS alert will appear then choose Don't Allow again and check your terminal for logs you'll find the logged result is blocked (which means that it is not requestable)
  5. Kill the app and relaunch it again then go to the screen that contains the code, you'll find the status is denied (the output of check() function) which means that it should be requestable
  6. Click on Request location permission button again, no OS alert appears and check your terminal for logs you'll find the logged result is blocked (which means that it is not requestable) which is logical but the check() function doesn't reflect this

These steps show that request() and check() return different statuses for the permission and that I can't rely on check() to know the correct status of the permission

zoontek commented 7 months ago

To clarify my issue more: When requesting a permission and then choose Don't Allow option, the returned result is 'blocked' but when call check() to get the status it returns denied from what I understand denied status means that it is requestable but it is not

Ah yes, way more clear! This is 100% normal on Android (check the flow) It's impossible on Android to know if a permission is blocked before requesting it. That's also why check on PermissionsAndroid can only resolves a boolean - but request can resolve a PermissionStatus

Duplicate: https://github.com/zoontek/react-native-permissions/issues/828#issuecomment-1842456998