NathanaelA / nativescript-permissions

Wraps up the entire Android 6 permissions system in a easy to use plugin.
MIT License
46 stars 22 forks source link

Android Permissions are firing weirdly #29

Closed WebDevBren closed 6 years ago

WebDevBren commented 6 years ago

I have written a plugin that basically acts as a thin wrap around your plugin and adds IOS Permission requesting... (while attempting to keep a consistent API between the two, so some 'vanity' methods have been added)

you can see it here: https://www.npmjs.com/package/@spartadigital/nativescript-permissions

we've noticed some strange behaviour from the promises, it seems that they are being fired twice, once when the dialog is opened and once when the permission is granted/rejected, and i believe that the issue is with your plugin

Here is the implementation script

let hasLocationPermissionsI = false;
let hasCameraPermissionsI = false;

let amountOfTimesFired = 0;

console.log('Requesting Location Permissions');
Permissions.requestLocationPermission().then((isLocationEnabled) => {
  hasLocationPermissionsI = isLocationEnabled;

  console.log('Requesting Camera Permissions');
  return Permissions.requestCameraPermission();
}).then((isCameraEnabled: boolean) => {
  hasCameraPermissionsI = isCameraEnabled;

  return Promise.resolve([hasLocationPermissionsI, hasCameraPermissionsI])
}).then(([hasLocationPermissions, hasCameraPermissions]) => {
  console.log(` hasLocationPermission: ${hasLocationPermissions ? 'Yes': 'No'} `);
  console.log(` hasCameraPermissions: ${hasCameraPermissions ? 'Yes': 'No'} `);
  amountOfTimesFired++;
  console.log(`Amount of Times this has been fired: ${amountOfTimesFired}`);

  const promises = [];

  if (!hasLocationPermissions) {
    promises.push(this.dialog.alert('You cannot use this app without location access', 'Access to Location is Required!'));
  }

  if (!hasCameraPermissions) {
    promises.push(this.dialog.alert('Access to the Camera is required to use this application, Please go to your settings and enable Camera Permissions', 'Access to the Camera is Required!'));
  }

  if (hasLocationPermissions && hasCameraPermissions) {
    resolve(true);
  } else {
    Promise.all(promises).then(() => {
      this.store.dispatch(new AuthActions.LogoutAction());
      Permissions.openAppSettings();
      resolve(false);
    });
  }
});

which results in the following log

JS: Requesting Location Permissions // first request
JS: [@SpartaDigital/nativescript-permissions]  #requestLocationPermission failed
JS: [@SpartaDigital/nativescript-permissions]  -- Has Args?  true
JS: [@SpartaDigital/nativescript-permissions]  -- {
JS:     "android.permission.ACCESS_FINE_LOCATION": false
JS: }
JS: Requesting Camera Permissions
JS: [@SpartaDigital/nativescript-permissions]  #requestCameraPermission failed
JS: [@SpartaDigital/nativescript-permissions]  -- Has Args? true
JS: [@SpartaDigital/nativescript-permissions]  -- {
JS:     "android.permission.CAMERA": false
JS: }
JS:  hasLocationPermission: No
JS:  hasCameraPermissions: No
JS: Amount of Times this has been fired: 1
JS: [@SpartaDigital/nativescript-permissions]  #requestLocationPermission success
JS: [@SpartaDigital/nativescript-permissions]  -- Has Args?  true
JS: [@SpartaDigital/nativescript-permissions]  -- {
JS:     "android.permission.ACCESS_FINE_LOCATION": true
JS: }
JS: Requesting Camera Permissions
ActivityManager: START u0 {act=android.content.pm.action.REQUEST_PERMISSIONS pkg=com.google.android.packageinstaller cmp=com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity (has extras)} from uid 10491 pid 17880
JS: [@SpartaDigital/nativescript-permissions]  #requestCameraPermission success
JS: [@SpartaDigital/nativescript-permissions]  -- Has Args? true
JS: [@SpartaDigital/nativescript-permissions]  -- {
JS:     "android.permission.CAMERA": true
JS: }
JS:  hasLocationPermission: Yes
JS:  hasCameraPermissions: Yes
JS: Amount of Times this has been fired: 1 // <-- Apparently the first time its been called again? 

Any Ideas?

NathanaelA commented 6 years ago

I think you might be looking in the wrong location. Because the amountOfTimesFired is only 1 in both instances, and it declared is outside the request permissions. This tells me that whatever is calling the beginning of your code is what is looping. Otherwise if the request permissions was causing the loop that counter would be 2.

I bet if you add a console.log("Hi"); where you have the let amountOfTimesFired = 0; you would see "Hi" twice also...

WebDevBren commented 6 years ago

the very first console.log (outputs : JS: Requesting Location Permissions) is outside of the promise chain and only logs once.

WebDevBren commented 6 years ago

also, i should mention that this behaviour only occurs when the application does not already have the permissions. if the user has given the permissions (either by accepting them, or via the application settings) it works as expected.

NathanaelA commented 6 years ago

Sorry, I totally forgot about this bug report until I was cleaning up issues.

I took your code above and modified it to be only talking to this plugin and I cannot duplicate your issue:

       var hasLocationPermissionsI = false;
    var hasCameraPermissionsI = false;
    var amountOfTimesFired = 0;

    viewModel.testTap = function() {
        var that = this;
        console.log('Requesting Location Permissions');
        permissions.requestPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, "I need Location!")
        .then(function (isLocationEnabled) {
            hasLocationPermissionsI = isLocationEnabled;

            console.log('Requesting Camera Permissions');
            return permissions.requestPermission(android.Manifest.permission.CAMERA, "I need Camera!");
        }).catch(function(err) {
            hasLocationPermissionsI = false;
            return permissions.requestPermission(android.Manifest.permission.CAMERA, "I need Camera!");
        })
        .then(function (isCameraEnabled) {
            hasCameraPermissionsI = isCameraEnabled;

            return Promise.resolve([hasLocationPermissionsI, hasCameraPermissionsI]);
        }).catch (function (err) {
            hasCameraPermissionsI = false;
            return Promise.resolve([hasLocationPermissionsI, hasCameraPermissionsI]);
        })
        .then(function (val) {
            var hasLocationPermissions = val[0], hasCameraPermissions = val[1];
            console.log(" hasLocationPermission: ", hasLocationPermissions ? 'Yes' : 'No');
            console.log(" hasCameraPermissions: ", hasCameraPermissions ? 'Yes' : 'No');
            amountOfTimesFired++;
            console.log("Amount of Times this has been fired: ", amountOfTimesFired);

            if (hasLocationPermissions && hasCameraPermissions) {
                that.set("message", "WooHoo you granted me all the permissions!");
            } else {
                that.set("message", "I need moooar permissions!");
            }
        })
        .catch(function(err) {
            console.log("Error", err);
        });
    };

I put this into the demo app; and added a button that fires this. I was unable to get a promise fired more than once. I randomly choose allow or deny; then on fresh runs I would reset the permissions to be unset for the app so it would be a fresh start.

My last time I ran it; I did Deny/Deny, then re-clicked the test button and did Allow/Allow. and it outputted:

JS: Requesting Location Permissions
JS: Requesting Camera Permissions
JS:  hasLocationPermission:  No
JS:  hasCameraPermissions:  No
JS: Amount of Times this has been fired:  1
JS: Requesting Location Permissions
JS: Requesting Camera Permissions
JS:  hasLocationPermission:  Yes
JS:  hasCameraPermissions:  Yes
JS: Amount of Times this has been fired:  2

This was done on an Android 7 emulator.