React-native-permissions: Permissions.request never resolve if previously requested

Created on 30 Jan 2018  ·  9Comments  ·  Source: zoontek/react-native-permissions

Describe your environment

  • React-Native 0.51.0
  • Platform: iOS,
  • Device IPhone6s
  • OS 11
  • react-native-permissions 1.1.1

How to repeat issue and example

Hello, I use to ask permissions for notifications with another library at app startup, but I wanna do it in a more friendly user way now, however, the first time that I call Permissions.request, it never show the alert (iOS one time ask, so this is normal) but the promise wont return undefined or denied.
The second time I call Permissions.request, because the libs registers 'RNPDidAskForNotification' it does resolve with denied.

I feel like the promise should always return or throw, but not hang.

Solution

Maybe there is a way to catch the "Can't show alert more than one time" and resolve with denied ?

Most helpful comment

I can confirm this and add my observations. This happens when I combine request from react-native-permissions with PushNotificationIOS.requestPermissions from react-natve. This is easily reproducable on iOS:

  1. Install fresh app and run it
  2. Call PushNotificationIOS.requestPermissions()
  3. Call Permissions.request('notification')
  4. Don't allow access
  5. Promise from Permissions.request won't be resolved or rejected

Interesting thing that everything works if don't mix PushNotificationIOS with react-native-permissions, i.e. two subsequent calls PushNotificationIOS.requestPermissions OR Permissions.request('notification') work as expected.

All 9 comments

I can confirm this and add my observations. This happens when I combine request from react-native-permissions with PushNotificationIOS.requestPermissions from react-natve. This is easily reproducable on iOS:

  1. Install fresh app and run it
  2. Call PushNotificationIOS.requestPermissions()
  3. Call Permissions.request('notification')
  4. Don't allow access
  5. Promise from Permissions.request won't be resolved or rejected

Interesting thing that everything works if don't mix PushNotificationIOS with react-native-permissions, i.e. two subsequent calls PushNotificationIOS.requestPermissions OR Permissions.request('notification') work as expected.

Did some further digging and I think this might be related https://github.com/facebook/react-native/issues/14101 - at least on Android for me.

This is a total PITA for Android. I shouldn't have to use both check and request just to request it. It works on the first run but it hangs every time after.

@wbattel4607, just to clarify: do you mean that the following workaround should work?

Permissions.check("camera")
.then(response => {
  return Permissions.request("camera");
})
.then(response => {
  console.log("Permissions for camera now correctly set: " + response);
});

We're seeing a rare Android hang-up at permissions check that we can't reproduce. We currently do the following, which has worked on our test devices:

Permissions.request("camera")
.then(response => {
  console.log("Permissions for camera theoretically correctly set: " + response);
});

No idea if this is the actual problem causing our rare bug, but your confirmation would help give us more confidence that this is our issue.

@sunweiyang
So our cross-platform app has to check for location permissions (our app performs best with 'Always' location permissions, but functions with either so we first try to ask or Always and if that's denied we ask for WhenInUse). The only way to get it to work for Android was to do this ridiculous nesting:

componentDidMount() {

    const continueInit = () => {
        // continue with other app init procedures.
    }

    const noLocation = () => {
        Alert.alert(
            'Location Disabled :(',
            'App does not work without your location...',
            [{text: 'Go to settings', onPress: () => Permissions.openSettings()}],
            {cancelable: false}
        );
    }

    const checkLocationWhenInUse = () => {
        Permissions.check('location', 'whenInUse').then(locationWhenInUseCheck => {
            switch (locationWhenInUseCheck) {
                case 'authorized':
                    this.locationPermission = 'WhenInUse';
                    continueInit();
                    break;
                case 'undetermined':
                    Permissions.request('location', 'whenInUse').then(locationWhenInUseRequest => {
                        if (locationWhenInUseRequest === 'authorized') {
                            this.locationPermission = 'WhenInUse';
                            continueInit();
                        }
                        else
                            noLocation();
                    });
                    break;
                default:
                    noLocation();
                    break;
            }
        });
    }

    const checkLocationAlways = () => {
        Permissions.check('location', 'always').then(locationAlwaysCheck => {
            switch (locationAlwaysCheck) {
                case 'authorized':
                    this.locationPermission = 'Always';
                    continueInit();
                    break;
                case 'undetermined':
                    Permissions.request('location', 'always').then(locationAlwaysRequest => {
                        if (locationAlwaysRequest === 'authorized') {
                            this.locationPermission = 'Always';
                            continueInit();
                        }
                        else
                            checkLocationWhenInUse();
                    });
                    break;
                default:
                    checkLocationWhenInUse();
                    break;
            }
        });
    }

    checkLocationAlways();

}

It's ridiculous but it works flawlessly. We haven't been able to get it working on Android without nesting it like this.

@wbattel4607 All right, we'll proceed with a check first -- worth a shot. 🤷‍♂️

I tried the same with notification but it does not work.

Permissions.check('notification')
            .then((response) => {
                if (response !== 'authorized') {
                    Permissions.request('notification').then((userResponse) => {
                        if (userResponse === 'authorized') {
                            actionA;
                        } else {
                            actionB;
                        }
                    });
                }
            });

If the notification are denied on the 1st time, the dialog that suppose to be visible after this Permissions.request('notification') line is never visible.

React-Native : 0.52.0
Platform: iOS6
react-native-permissions : 1.1.1
Devtools: Atom

@assafb81 that is because on iOS, once a permission is denied, you cannot request it again. The best thing to do is request it, and if it is denied, ask the user to allow it manually via settings, like so:

Permissions.request('notification')
.then((response) => {
    if (response !== 'authorized') {
        Alert.alert(
            'Please allow notifications',
            'This app needs you to authorize notifications in order to work',
            [{text: 'Go to settings', onPress: () => Permissions.openSettings()}],
            {cancelable: false}
        );
    }
});

You should avoid this for permissions that your app doesn't _need_, because Apple does not like it when apps force users to authorize permissions when not necessary,

I am closing this since this issue does not exists anymore with the 2.0.0 release.

Was this page helpful?
0 / 5 - 0 ratings