nativescript-community / perms

An unified permissions API for NativeScript on iOS and Android.
https://nativescript-community.github.io/perms/
Apache License 2.0
12 stars 9 forks source link

[Android] Cannot request multiple permissions at the same time any more #13

Closed sebj54 closed 1 year ago

sebj54 commented 1 year ago

If the demo apps cannot help and there is no issue for your problem, tell us about it

I just updated this plugin and I can't request multiple permissions at the same time. I had version 2.2.11 before and the code below worked as expected:

import { request as requestPermission } from '@nativescript-community/perms'

requestPermission(['bluetoothScan', 'bluetoothConnect'])

Permissions are never requested and requestPermission resolves with these statuses:

{
  "0": "never_ask_again",
  "1": "never_ask_again"
}

The issue seems to only impact Android. I think these lines are causing the issue: https://github.com/nativescript-community/perms/blob/6c9b8c9b8f98181aa76d5baf378f95465d64da33/src/perms/index.android.ts#L380-L382

Maybe there should be a test like this: if (! Array.isArray(permission) to avoid calling Object.keys.

Which platform(s) does your issue occur on?

Please, provide the following version numbers that your issue occurs with:

✔ Component nativescript has 8.4.0 version and is up to date. ✔ Component @nativescript/core has 8.4.4 version and is up to date. ✔ Component @nativescript/ios has 8.4.0 version and is up to date. ✔ Component @nativescript/android has 8.4.0 version and is up to date.

Please, tell us how to recreate the issue in as much detail as possible.

Add these lines in AndroidManifest.xml (in manifest tag):

    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

Request permissions:

import { request as requestPermission } from '@nativescript-community/perms'

requestPermission(['bluetoothScan', 'bluetoothConnect'])

Is there any code involved?

I can provide a demo with logs if needed.

farfromrefug commented 1 year ago

@sebj54 it should have been mentioned in the changelog of v2.2.14 but apparently changelog generation failed :s https://github.com/nativescript-community/perms/commit/0612776f8af4878f3686e5d15e1398b8dedfb54e You now need to pass an object like this requestPermission({bluetoothScan:{}, bluetoothConnect:{}) This was an important change to allow per perm settings

sebj54 commented 1 year ago

I knew I missed something 😅

Do you want me to add a multiple request example in the README file?

farfromrefug commented 1 year ago

@sebj54 that would be awesome ! :D

sebj54 commented 1 year ago

I wasn't sure of every call so I did a test app:

<template>
    <Page>
        <ActionBar>
            <Label text="Home"/>
        </ActionBar>

        <GridLayout>
            <StackLayout>
                <Button @tap="checkSinglePerm">checkSinglePerm</Button>

                <Button @tap="checkMultiplePerms">checkMultiplePerms</Button>

                <Button @tap="requestSinglePerm">requestSinglePerm</Button>

                <Button @tap="requestMultiplePerms">requestMultiplePerms</Button>
            </StackLayout>
        </GridLayout>
    </Page>
</template>

<script>
import {
    check as checkPermission,
    checkMultiple as checkMultiplePermissions,
    request as requestPermission,
} from '@nativescript-community/perms';

export default {
    methods: {
        checkSinglePerm() {
            checkPermission('location', { type: 'always' })
                .then((response) => {
                    console.log('[TCL] ~ file: Home.vue:50 ~ .then ~ response', response)
                });
        },
        checkMultiplePerms() {
            const permissions = {
                location: {},
                contacts: {},
            };
            checkMultiplePermissions(permissions)
                .then((response) => {
                    console.log('[TCL] ~ file: Home.vue:60 ~ .then ~ response', response)
                })
                .catch((error) => {
                    console.log('[TCL] ~ file: Home.vue:63 ~ .catch ~ error', error)
                });
        },
        requestSinglePerm() {
            requestPermission('location', { type: 'always' })
                .then((response) => {
                    console.log('[TCL] ~ file: Home.vue:66 ~ .then ~ response', response)
                });
        },
        requestMultiplePerms() {
            const permissions = {
                location: { type: 'always' },
                contacts: {},
            };
            requestPermission(permissions)
                .then((response) => {
                    console.log('[TCL] ~ file: Home.vue:76 ~ .then ~ response', response)
                });
        },
    },
};
</script>

But is fails on iOS when calling checkMultiple:

  ***** Fatal JavaScript exception - application has been terminated. *****
  NativeScript encountered a fatal error: Uncaught TypeError: permissions.map is not a function
  at
  checkMultiple(file: app/webpack:/test-perms/node_modules/@nativescript-community/perms/permissions.ios.js:784:0)
  at checkMultiplePerms(file: app/webpack:/test-perms/app/components/Home.vue:46:36)
  at invokeWithErrorHandling(file: app/webpack:/test-perms/node_modules/nativescript-vue/dist/index.js:1871:0)
  at invoker(file: app/webpack:/test-perms/node_modules/nativescript-vue/dist/index.js:2525:0)
  at _handleEvent(file: app/webpack:/test-perms/node_modules/@nativescript/core/data/observable/index.js:234:0)
  at notify(file: app/webpack:/test-perms/node_modules/@nativescript/core/data/observable/index.js:216:0)
  at _emit(file: app/webpack:/test-perms/node_modules/@nativescript/core/data/observable/index.js:263:0)
  at TapHandlerImpl.tap(file: app/webpack:/test-perms/node_modules/@nativescript/core/ui/button/index.ios.js:262:0)

I guess checkMultiple should take a permissions object like requestPermission, shouldn't it?

Also, the permissions returned seem inconsistent (at least on Android):

checkMultiple:

[TCL] ~ file: Home.vue:60 ~ .then ~ response {
  "location": [
    "authorized",
    true
  ],
  "contacts": [
    "authorized",
    true
  ]
}

request (multiple):

[TCL] ~ file: Home.vue:76 ~ .then ~ response {
  "android.permission.ACCESS_COARSE_LOCATION": "authorized",
  "android.permission.ACCESS_FINE_LOCATION": "authorized",
  "android.permission.ACCESS_BACKGROUND_LOCATION": "never_ask_again",
  "android.permission.READ_CONTACTS": "authorized"
}

You can see that object keys are not the same and values are arrays in one case and strings in the other.

farfromrefug commented 1 year ago

@sebj54 thanks will fix it!

sebj54 commented 1 year ago

Ok then!

Here is what I started to add to the docs if you'd like to include it with the fix (I'll be happy to do it if you don't have time for this):


Examples

Check a single permission:

import { check as checkPermission } from '@nativescript-community/perms';

checkPermission('location', { type: 'always' })
  .then((response) => {
    if (response[0] === 'authorized') {
      // do something
    } else {
      // show error
    }
  });

Check multiple permissions:

import { checkMultiple as checkMultiplePermissions } from '@nativescript-community/perms';

const permissions = {
  location: { type: 'always' },
  contacts: {},
};
checkMultiplePermissions(permissions)
  .then((response) => {
    const isLocationAuthorized = response.location[0] === 'authorized';
    const areContactsAuthorized = response.contacts[0] === 'authorized';

    // do something based on permission status
  });

Request a single permission:

import { request as requestPermission } from '@nativescript-community/perms';

requestPermission('location', { type: 'always' })
  .then((response) => {
    if (response === 'authorized') {
      // do something
    } else {
      // show error
    }
  });

Request multiple permissions:

import { request as requestPermission } from '@nativescript-community/perms';

const permissions = {
  location: { type: 'always' },
  contacts: {},
};
requestPermission(permissions)
  .then((response) => {
    // Android
    const isLocationAuthorized = response['android.permission.ACCESS_FINE_LOCATION'] === 'authorized';
    const areContactsAuthorized = response['android.permission.READ_CONTACTS'] === 'authorized';

    // iOS

    // do something based on permission status
  });
farfromrefug commented 1 year ago

@sebj54 i released 2.2.22 which shoudl fix checkMultiple. If you could try that would be great. As for the doc if you are happy to do it, then you can add it to packages/perms/blueprint.md. That way you ll now where we modify packages README.md (generated from blueprint.md in most of community packages Thanks again for your help

sebj54 commented 1 year ago

checkMultiple now works as expected, thanks for the quick fix :)

I will commit and push the docs now!

sebj54 commented 1 year ago

I'm sorry there is another issue, with a multiple request this time (still with iOS):

TypeError: Cannot read property 'location' of undefined
  at request (file: app/webpack:/test-perms/node_modules/@nativescript-community/perms/index.ios.js:768:0)
  at VueComponent.requestMultiplePerms (file: app/webpack:/test-perms/app/components/Home.vue:60:29)
  at invokeWithErrorHandling (file: app/webpack:/test-perms/node_modules/nativescript-vue/dist/index.js:1871:0)
  at Object.invoker [as callback] (file: app/webpack:/test-perms/node_modules/nativescript-vue/dist/index.js:2525:0)
  at Function._handleEvent (file: app/webpack:/test-perms/node_modules/@nativescript/core/data/observable/index.js:234:0)
  at Button.notify (file: app/webpack:/test-perms/node_modules/@nativescript/core/data/observable/index.js:216:0)
  at Button._emit (file: app/webpack:/test-perms/node_modules/@nativescript/core/data/observable/index.js:263:0)
  at TapHandlerImpl.tap (file: app/webpack:/test-perms/node_modules/@nativescript/core/ui/button/index.ios.js:262:0)

It is caused by this line: https://github.com/nativescript-community/perms/blob/26b6bedd9652c93c2209fe092ce90eb6aaf381e4/src/perms/index.ios.ts#L763

options[keys[index]] should be replaced with permission[keys[index]] I guess.

farfromrefug commented 1 year ago

@sebj54 it is me who is sorry! I need to do more tests for this. Will fix it for good

sebj54 commented 1 year ago

Don't worry, it happens! Feel free to ask for anything if I can help ;)

sebj54 commented 1 year ago

@farfromrefug Thank you for the update! Unfortunately I can't make it work. In my test app, I can't request any iOS permission (even with a single permission request).

Do you think I did something wrong? No error is thrown, it fails on these lines:

Do you need my test app to reproduce?

farfromrefug commented 1 year ago

@sebj54 sorry for the delay. I tested it all again on iOS an 2.2.24 should fix it all for you

sebj54 commented 1 year ago

I can now confirm that it works for both versions! Thank fou for all the fixes :)

By the way, the error I was getting on iOS was due to the lack of *UsageDescription strings in Info.plist.

farfromrefug commented 1 year ago

@sebj54 yes finding those errors(app simply crashing) is a pain. You have to open the crash report on macos to see the actual error about missing usage. Happy that it all works now!