React-native: PermissionsAndroid.request never resolves

Created on 14 Feb 2018  ·  40Comments  ·  Source: facebook/react-native

Is this a bug report?

Yes

Have you read the Contributing Guidelines?

Yes.

Environment

Environment:
OS: macOS Sierra 10.12.6
Node: 9.4.0
Yarn: 1.3.2
npm: 5.6.0
Watchman: 4.9.0
Xcode: Xcode 9.2 Build version 9C40b
Android Studio: 3.0 AI-171.4443003

Packages: (wanted => installed)
react: 16.2.0 => 16.2.0
react-native: 0.53.0 => 0.53.0

Edit: according to @MateRyze, it still happens on react-native 0.55.4.

Target Platform: Android 6.0.1

Steps to Reproduce

We have a Camera component and it should check for the Camera permission before mounting.

In my app's AndroidManifest.xml I have the line, along with many other permissions:

<uses-permission android:name="android.permission.CAMERA"/>

In our component's componentDidMount() we call a function that should return true if we have permission and false if we do not have, here is the relevant snippet of the function:

if (Platform.OS === 'android') {
const isGranted = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.CAMERA);
      if (isGranted) {
        return true;
      }
      try {
        console.log('before request');
        const granted = await PermissionsAndroid.request(
          PermissionsAndroid.PERMISSIONS.CAMERA,
          {
            title: 'Dialog Title',
            message: 'Dialog Message',
          }
        );
        console.log('after request');
        return granted === PermissionsAndroid.RESULTS.GRANTED;
      } catch (err) {
        console.log('error');
        console.log(err);
      }
}

Expected Behavior

A dialog with my title and message should appear, if the user clicks on "Allow", the promise should resolve and my component should render as expected.

Actual Behavior

A dialog with a different message and title appears. I click on "Allow" and the promise is never resolved or rejected.

In my logs, only the "before request" log appears. Neitherconsole.log('after request') or console.log('error') is logged, so I presume the code is stuck in the await.

I am following this doc.

Bug Locked

Most helpful comment

After debugging and trying a few cases. If the request is called with the rationale parameter as undefined the request permission works correctly.
When the rationale object is provided permissions are not requested.

All 40 comments

up :(

Yup encountering the same behavior... seems like it will only resolve if the device is < Android 6.0

Up again. This error happens in one of our apps in production, we tried to make a workaround for it multiple times but nothing works. Even if we ask for the permission when the app starts, it still hangs and never resolves.

@aryo, will try to confirm what you said, thanks

Would love any follow up

The alert asking for permission is shown as expected, but sometimes in case of denial the promise do not resolves and because of this the app flow stops. If the permission is granted the flow goes as expected, the promise resolves.

This is happening to us, appears to most reliably happen on one of our testers' Nexus 6; doesn't repro on some other Android devices. For us no matter if the permission is granted or denied, it can lead to the unresolving promise it seems.
react-native-cli: 2.0.1
react-native: 0.51.0
platform: android
builds: at least release builds

It happens with different android versions and different devices for us.
First we hoped it would be because of the old react native version 0.38 it is, but i don't think this is the case after your comment jslz.
We tried different build tool versions and target/compile versions. The issue still remains the same.

Thanks for posting this! It looks like your issue may refer to an older version of React Native. Can you reproduce the issue on the latest release, v0.55?

Thank you for your contributions.

We are trying to upgrade to 0.54, we generally avoid being on the bleeding edge of RN for stability reasons. It would be helpful to know if there's been an explicit fix ever done for this issue. :-)

I have a similar problem with PERMISSIONS.ACCESS_FINE_LOCATION: the dialog doesn't appear and the promise is also not resolved.
I am using code from docs.
react-native version: 0.55.4

@MateRyze as an aside & by the by, apparently some Android permissions are not considered "dangerous" and so I guess those ones do not put up an extra dialog box from Android OS itself?

https://stackoverflow.com/questions/34808769/android-6-0-what-is-the-difference-between-dangerous-and-special-permissions

(That's separate from the promise-never-resolving issue.)

@jgfidelis Are you using react-native-navigation?

I have the same issue you have, and I think it is because the onRequestPermissionsResult method in the MainActivity never get's called due to NavigationActivity.

@rcidt, yes fwiw we are using wix rnn.

@jslz I am 99% sure that is the reason the promise never resolves. I am opening a ticket with them, maybe they can help.

@jslz but the location permission is dangerous. Moreover it doesn't resolve :(

@MateRyze oh dang. Thanks for pointing that out.

We have the "not resolving" issue in a project without any navigation
library.

jslz notifications@github.com ezt írta (időpont: 2018. máj. 24., Cs
22:12):

@MateRyze https://github.com/MateRyze oh dang. Thanks for pointing that
out.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/facebook/react-native/issues/17985#issuecomment-391843574,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AP4R9jLAe1tTX4ZPCAWBrOq3Oro2G6F2ks5t1xQQgaJpZM4SFz46
.

@rcidt No, we do not use react-native-navigation on the app we have this issue.

I am seeing this happen 90% of the time. A few times the promise actually resolves, but that's like 10% of the time.

This issue is making our android app basically unusable :(

Updated to RN 0.55 and I have no more issues with PermissionsAndroid

Confirmed, upgrading to the following versions fixes the issue:

    "react": "16.4.0",
    "react-native": "0.55.4",

Using following versions:
"react": "16.4.0",
"react-native": "0.55.4",
No other modules installed.

Problem: no dialog and the request doesn't resolve. :(
I am using the code from https://facebook.github.io/react-native/docs/permissionsandroid.htm

async function requestLocationPermission() {
  try {
    const granted = await PermissionsAndroid.request(
      PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
      {
        'title': 'Cool Photo App Camera Permission',
        'message': 'Cool Photo App needs access to your camera ' +
          'so you can take awesome pictures.'
      }
    )
    if (granted === PermissionsAndroid.RESULTS.GRANTED) {
      console.log("You can use the location service")
    } else {
      console.log("Location permission denied")
    }
  } catch (err) {
    console.warn(err)
  }
}

@MateRyze before you installed:

"react": "16.4.0",
"react-native": "0.55.4",

did you also do a rm -rf ./node_modules package-lock.json?

The only difference might be that I'm using the "promise/then" syntax in lieu of "async/await", ex:

    requestAndroidPermissions() {
        if (Platform.OS === 'android') {
            var permissions = [
                PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
                PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION
            ];

            try {
                PermissionsAndroid.requestMultiple(permissions).then(granted => {
                    // Object.entries(granted).map(([key, value]) => {
                    // });
                    this.nextAction();
                });
            } catch (err) {
                console.warn(err);
            }
        } else if (Platform.OS === 'ios') {
            this.nextAction();
        }
    }

which _shouldn't_ matter, but perhaps it does.

@MateRyze also using

PermissionsAndroid.requestMultiple()

@MateRyze this is a long shot, but can you try changing your code to use then rather then awai/async just to see if the bug still happens? I don't think it will make any difference, but lets try anything...

We fixed it by requesting the permission on app startup.

After debugging and trying a few cases. If the request is called with the rationale parameter as undefined the request permission works correctly.
When the rationale object is provided permissions are not requested.

I just wrapped it in another promise, seems to work well for me.

getPermissions() {
  return new Promise(async(resolve, reject) => {
    const permissions = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE);
    if (permissions === PermissionsAndroid.RESULTS.GRANTED) resolve(true);
    else reject(false);
  });
}

@Asleepace so PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE) works because the rationale is undefined at least in the version that was on react-native-camera (react-native version: ^0.55.2).
What happens if you pass rationale as the second parameters?

@kanekotic still works with the rationale for me as well, using RN version 0.55.4

still the issue persists. I'm using RN v0.53. Any workaround, as I don't want to upgrade my RN version

Here's perfectly working example for fresh 0.57 and Android 27 on physical phone:

class App extends Component {
  _requestPermissions = async () => {
    if (Platform.OS === 'android') { 
      const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA)
      return result === PermissionsAndroid.RESULTS.GRANTED || result === true
    }
    return true
  }

  componentDidMount = () => {
    async ({ _, status }) => {
      if (status !== 'PERMISSION_GRANTED') {
        await this._requestPermissions()
      }
    }
  }

  render() {
    return (
      <View style={styles.container}>
        <RNCamera style={styles.preview} type={RNCamera.Constants.Type.back} />
      </View>
    )
  }
}

So, basically an error is rather how and what permissions to ask, not React Native related. For example, if we would have used if (status !== 'PENDING_AUTHORIZATION') {, then the app will pop-up only on second run and first run will be promise rejected.

In our case this was happening because our main activity does not extend ReactActivity and we were not properly implementing PermissionAwareActivity on our own.

The symptom we were seeing - permission prompt would show up properly, user could allow/deny, and then... nothing. If the user allowed the permission, subsequent attempts would succeed (promise would resolve), but the first allow never resolved and denies never resolved.

ReactActivity has some glue that handles notifying React Native that a permissions request is finished via PermissionListener. We had to roll this ourselves - when React calls requestPermissions on the activity, save off the provided PermissionListener, and then later call listener.onRequestPermissionsResult when your activity's onRequestPermissionsResult is invoked.

I am running into this problem with PermissionsAndroid.requestMultiple() when permissions are not already granted. If permissions are not already granted when requestMultiple() is called and the dialog has to be shown to the user, the promise never gets fulfilled.

_requestLocationPermission(){ return new Promise(async() => { const permissions = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION); if (permissions === PermissionsAndroid.RESULTS.GRANTED){ alert('access true'); } else{ alert('access false'); } }); }

Happening on RN 0.58.3.

Hello there 👋 this issue has been reported for an old version of React Native. Ideally we'd like everyone to be using 0.59 (see the awesome changes it brought) but we know updating can be a pain. We are going to close this issue because it's from a version before 0.57, which is really old.

But please, if it's actually still an issue with 0.59 please comment below and we can reopen it 😊

Any way to provide rationale to .multipleRequest()?. I want to give the user more insight into why I need the permission for respective request. In short, Customized title and message with multiple requests.

I'm using:

"react": "16.8.3",
"react-native": "0.59.9",

Relevant snippet:

  const askCameraPermission = async () => {
    try {
      const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA);
      console.log(granted)
    } catch {
      (e) => console.log(e)
    };
  };

App info's permissions after -> before running method

pending -> granted BUT promise is not resolved, console.log doesn't show. 👎
granted -> don't ask for permission because is already granted AND promise is resolved, console.log show 'granted' 👍

I have upgraded my project from 0.57 to 0.61 . But the issue still exists. However if I try to create a new project with react-native 0.61 this issue is not there. I am stuck here. Please some one help me

I have upgraded my project from 0.57 to 0.61 . But the issue still exists. However if I try to create a new project with react-native 0.61 this issue is not there. I am stuck here. Please some one help me

Maybe you Override onRequestPermissionsResult in MainActivity extends ReactActivity but forget to call super.onRequestPermissionsResult.

Was this page helpful?
0 / 5 - 0 ratings