react-native-permissions icon indicating copy to clipboard operation
react-native-permissions copied to clipboard

Permissions are not asked again (marked as denied) if disabled manually in Settings (Android 12)

Open Martinocom opened this issue 2 years ago • 4 comments

Bug summary

Permissions are prompt only once on Android 12. The status of the permission is only denied, still the popup does not appear with request nor requestMultiple. Permission is flagged as denied and the second time the permissions are asked the method freezes the app with both async-await and then-catch approaches (no errors are thrown). This happens when once granted, I go into the settings and manually deny one of the permissions.

The output of await checkMultiple(permissions_to_check) is in my case: "android.permission.ACCESS_FINE_LOCATION": "granted", "android.permission.BLUETOOTH_ADVERTISE": "denied", "android.permission.BLUETOOTH_CONNECT": "denied", "android.permission.BLUETOOTH_SCAN": "denied", "android.permission.CAMERA": "denied", "android.permission.READ_EXTERNAL_STORAGE": "granted", "android.permission.RECORD_AUDIO": "granted", "android.permission.WRITE_EXTERNAL_STORAGE": "granted"}

But still the BLUETOOTH and CAMERA permissions are not requested anymore in the app.

On LogCat I can see this: 2022-07-27 10:34:53.338 12792-12792/? V/GrantPermissionsViewModel: Permission grant result requestId=121482546543853**** callingUid=10*** callingPackage=**** permission=android.permission.CAMERA isImplicit=false result=2

Library version

3.6.0

Environment info

System:
    OS: Windows 10 10.0.19044
    CPU: (8) x64 Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
    Memory: 5.20 GB / 15.87 GB
  Binaries:
    Node: 14.18.1 - C:\Users\MARCIN~1.PAB\AppData\Local\Temp\yarn--1658909889296-0.6736994793267819\node.CMD
    Yarn: 1.22.15 - C:\Users\MARCIN~1.PAB\AppData\Local\Temp\yarn--1658909889296-0.6736994793267819\yarn.CMD
    npm: 6.14.15 - C:\Program Files\nodejs\npm.CMD
    Watchman: Not Found
  SDKs:
    Android SDK: Not Found
    Windows SDK: Not Found
  IDEs:
    Android Studio: Version     2020.3.0.0 AI-203.7717.56.2031.7784292
    Visual Studio: 16.3.29519.87 (Visual Studio Community 2019)
  Languages:
    Java: javac 11
    Python: 3.10.0
  npmPackages:
    @react-native-community/cli: Not Found
    react: 17.0.2 => 17.0.2
    react-native: 0.63.4 => 0.63.4
    react-native-windows: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps to reproduce

Happening on my personal device (Mi A2), custom ROM Streak Project (w/ root), based on Android 12.1.

  1. Into App.tsx insert some logic to check and require permission on a one-shot useEffect(() => { <see example code> }, [])
  2. Ask for permissions and grant them. Launch the app normally and then close it.
  3. Go into settings of Android, deny manually one of the required permissions.
  4. Reopen the app: no permission dialog will be shown.

Reproducible sample code

const checkAndRequirePermissions = async (): Promise<void> => {
    const required = [PERMISSIONS.ANDROID.CAMERA, PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE, PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE]

    // First check if permissions are all requestable
    console.log("Checking permissions...");
    const permissionStatus = await checkMultiple(required);
    // This will print permissions (denied the second time)
    console.log(permissionStatus );
    const unavailablePermissions: string[] = [];
    Object.keys(permissionStatus).forEach((key) => {
        if (
          permissionStatus[key] === RESULTS.BLOCKED ||
          permissionStatus[key] === RESULTS.UNAVAILABLE ||
          permissionStatus[key] === RESULTS.LIMITED
        ) {
            unavailablePermissions.push(key);
          }    
    });
    if (unavailablePermissions.length > 0) { throw false }

    // Then request them (this will be the point on which app freezes)
    console.log("Asking permissions...");
    const requestPermissionStatus = await requestMultiple(required);
    // This won't print the second time (app freezed)
    console.log(requestPermissionStatus);
    const notGrantedPermissions: string[] = [];

    Object.keys(requestPermissionStatus).forEach((key) => {
        if (requestPermissionStatus[key] !== RESULTS.GRANTED) {
            notGrantedPermissions.push(key);
    });

    if (notGrantedPermissions.length > 0) { throw false }

    return;
}

useEffect(() => {
    checkAndRequestPermissions()
     .then(() => {
          console.log("yay!");
      })
     .catch((error) => {
          console.log("nay :(", error);
      })
});

// Launch the app, everything will work. Go to settings, deny one of the permissions, the permission won't be prompt again.

Martinocom avatar Jul 27 '22 08:07 Martinocom

@Martinocom HI! I tried using the emulator (Android 13), my Pixel 4a (Android 12) and my Xiaomi A2 (stock, Android 10) and I cannot reproduce this behaviour (at least on React Native 0.69).

Did you tried with something else than a custom ROM / the latest RN version (ex: the example app)?

zoontek avatar Jul 27 '22 14:07 zoontek

Haven't tested this on any other device nor project. In my free time I'll try to build on another phone (stock Android 11) and with a new clean fresh project on RN 0.63/0.69 only asking for permissions. I'll update you if I get something new.

We planned to use this library for permissions, since we cannot update at this time from 0.63 to 0.69, and we need to manage new Android bluetooth requests not implemented in the PermissionAndroid in RN 0.63.

Martinocom avatar Jul 27 '22 14:07 Martinocom

Hey! I was experiencing something similar, notably was trying to get Background geo permissions and it kept returning as denied.

I'm not 100% sure that its related to your issue, but in our case it was just about the order of the permissions.

Making sure to ask for location first, then geolocation after fixed it for us! Maybe something similar could be done on the code shared above.

Just sharing in case it helps anyone:)

jeanrobatto avatar Jul 27 '22 16:07 jeanrobatto

I am also experiencing the same issue. I am using Samsung Galaxy S20 FE, Android 12. I am requesting only 1 permission in Android (android.permission.WRITE_EXTERNAL_STORAGE), but I am using requestMultiple and checkMultiple because in iOS, I need 2 permissions (ios.permission.PHOTO_LIBRARY, ios.permission.PHOTO_LIBRARY_ADD_ONLY)

I initially reject / deny the request in Android. After that, both requestMultiple and checkMultiple will return denied status in Android, without showing the request popup

In iOS, it still matches the description in ReadMe, initially the checkMultiple will return denied and will return blocked or granted or limited in requestMultiple

williamliangwl avatar Aug 04 '22 04:08 williamliangwl

I can reproduce this issue in android emulator using the repo example: Emulator : Android -12, API-31

Request permission throws: blocked check permission throws: denied

Screenshot_1660133459 Screenshot_1660133465

ravi-poonia-lib avatar Aug 10 '22 12:08 ravi-poonia-lib

@ravi-poonia-lib What your describe is "normal". Check the Android flow. You have to request the permission to know if it's blocked.

Before, this library relied on SharedPreferences to store the result in order to return blocked on check, but we don't do it anymore since it breaks some permissions features on Android 11+ (ex: Going to the app settings and replace "Denied" by "Ask next time" - the storage was not reset and the lib continue to return blocked. Only switching to "Grant" in settings worked). More infos in the v3.4.0 release note.

That's also why the built-in PermissionsAndroid check method return a boolean (as we can't know if it's blocked). This library still use statuses because unavailable can be returned too - and to keep a multi platform API.

Consider this:

  • Arriving on the screen, checking the permission
  • The permission is denied
  • Display a button to request permission
  • After pressing the button, it returns blocked
  • Prompt the user to got to app settings (with Alert, a nice explanation and an openSettings call)

It works on all platforms without special platform conditions, expect of course the permission arg passed to request.

@Martinocom @williamliangwl Maybe I don't get your problem well, but is it what your are also talking about? @Martinocom When you said "Marked as denied", did you mean after a request or after a check?

EDIT: I added a warning in the README. The Android flow diagram wasn't enough.

zoontek avatar Aug 10 '22 18:08 zoontek

As there is no feedback, I guess it was that.

zoontek avatar Sep 06 '22 16:09 zoontek