zoontek / react-native-permissions

An unified permissions API for React Native on iOS, Android and Windows.
MIT License
4.1k stars 836 forks source link

React Native iOS: "When In Use" Permission Grants "Always" Permission Automatically #893

Closed akankshaingle closed 2 months ago

akankshaingle commented 2 months ago

Before submitting a new issue

Bug summary

I'm encountering an issue with location permissions in my React Native iOS app. When the permission prompt appears, I select "When In Use" for location access, but when I later check the "Always" permission, it's also granted, even though I never selected it.

Here's my code:

if (Platform.OS === 'ios') { console.log('Requesting "When In Use" location permission for iOS...'); const whenInUseStatus = await request(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE); console.log('whenInUseStatus:', whenInUseStatus);

if (whenInUseStatus === RESULTS.GRANTED) {
    // Checking for "Always" permission
    const alwaysStatus = await check(PERMISSIONS.IOS.LOCATION_ALWAYS);
    console.log('alwaysStatus:', alwaysStatus);

    if (alwaysStatus !== RESULTS.GRANTED) {
        Alert.alert(
            'Enable "Always" Location Access',
            'To provide a better experience, please enable "Always" location access in the app settings.',
            [
                {
                    text: 'Go to Settings',
                    onPress: () => {
                        Linking.openURL('app-settings:');
                    },
                },
                { text: 'Cancel', style: 'cancel' },
            ]
        );
    }
}

}

In Info.plist, I have these added:

NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription

The popup shows the correct options for "When In Use", "Only Once" and "Never". However, when I select "When In Use", I’m finding that the app also gets the "Always" permission granted, which is not what I expect.

Has anyone faced a similar issue where selecting "When In Use" also grants the "Always" permission? Why might this be happening, and how can I ensure that "Always" is only granted when explicitly selected?

Any guidance would be appreciated!

I expected that when I selected "When In Use" location permission in the popup, only that permission would be granted. However, after selecting "When In Use", I checked the "Always" permission, and it was also granted, which is not what I expected. I tried checking the status of both permissions using request and check, but I’m still seeing this behavior.

Library version

"^3.3.1"

Environment info

siplaimacs-Mac-mini:project-cerge akansha.ingle$ react-native info
warn Package native-base contains invalid configuration: "dependency.assets" is not allowed. Please verify it's properly linked using "react-native config" command and contact the package maintainers about this.
info Fetching system and libraries information...
(node:80574) Warning: Accessing non-existent property 'padLevels' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
System:
    OS: macOS 14.4.1
    CPU: (8) arm64 Apple M2
    Memory: 286.47 MB / 16.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 18.20.4 - /opt/homebrew/opt/node@18/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 10.7.0 - /opt/homebrew/opt/node@18/bin/npm
    Watchman: 2024.07.15.00 - /opt/homebrew/bin/watchman
  Managers:
    CocoaPods: 1.15.2 - /opt/homebrew/bin/pod
  SDKs:
    iOS SDK:
      Platforms: DriverKit 23.4, iOS 17.4, macOS 14.4, tvOS 17.4, visionOS 1.1, watchOS 10.4
    Android SDK: Not Found
  IDEs:
    Android Studio: 2023.1 AI-231.9392.1.2311.11330709
    Xcode: 15.3/15E204a - /usr/bin/xcodebuild
  Languages:
    Java: 17.0.12 - /opt/homebrew/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 18.2.0 => 18.2.0 
    react-native: 0.71.19 => 0.71.19 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps to reproduce

  1. Request "When In Use" location permission:

Add the following code in your React Native app to request PERMISSIONS.IOS.LOCATION_WHEN_IN_USE using react-native-permissions. Ensure that both NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription are included in the Info.plist. if (Platform.OS === 'ios') { const whenInUseStatus = await request(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE); console.log('When In Use status:', whenInUseStatus); }

  1. Check if "Always" permission is granted:

After the user selects "When In Use" permission in the popup, check for PERMISSIONS.IOS.LOCATION_ALWAYS status. const alwaysStatus = await check(PERMISSIONS.IOS.LOCATION_ALWAYS); console.log('Always permission status:', alwaysStatus);

Reproducible sample code

import { Alert, Platform, Linking, AppState } from 'react-native';
import { request, PERMISSIONS, RESULTS, check } from 'react-native-permissions';

let settingsAlertShown = false;

const requestLocationPermissions = async () => {
    try {
        if (Platform.OS === 'ios') {
            console.log('Requesting "When In Use" location permission for iOS...');

            // Request "When In Use" location permission
            const whenInUseStatus = await request(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
            console.log('whenInUseStatus:', whenInUseStatus);

            // Check if "Always" permission is granted
            if (whenInUseStatus === RESULTS.GRANTED && !settingsAlertShown) {
                const alwaysStatus = await check(PERMISSIONS.IOS.LOCATION_ALWAYS);
                console.log('alwaysStatus:', alwaysStatus);

                if (alwaysStatus !== RESULTS.GRANTED) {
                    Alert.alert(
                        'Enable "Always" Location Access',
                        'Please enable "Always" location access in the app settings.',
                        [
                            {
                                text: 'Go to Settings',
                                onPress: () => {
                                    Linking.openURL('app-settings:');
                                    AppState.addEventListener('change', handleAppStateChange);
                                },
                            },
                            { text: 'Cancel', style: 'cancel' },
                        ]
                    );
                }
            }
        }
    } catch (error) {
        console.error('Error requesting permissions:', error);
    }
};

export default requestLocationPermissions;

Steps to Reproduce:
Add this function to any React Native project.

Install the react-native-permissions package and run pod install for iOS:
npm install react-native-permissions
cd ios && pod install

Invoke the requestLocationPermissions function on app startup or via a button.

Run the app on a physical iOS device or simulator.

Select "When In Use" when prompted for location permission.

Check the console to see if "Always" permission is being granted unexpectedly.
zoontek commented 2 months ago

Check "About iOS LOCATION_ALWAYS permission" in the README.

akankshaingle commented 2 months ago

Check "About iOS LOCATION_ALWAYS permission" in the README.

Thank you for your response. I’ve reviewed the README and understand the behavior described regarding iOS location permissions. However, I’m still encountering an issue and would appreciate any assistance or insights.

Current Scenario: Requesting "Always" Permission: I am directly requesting the PERMISSIONS.IOS.LOCATION_ALWAYS permission. However, despite this, the options presented to users are "Allow Once," "Never," and "When In Use," and not "Always."

Impact on Background Service: My app relies on continuous location updates for background services. When users only grant "When In Use" permission, these services do not function as required, impacting the app's functionality.

I have requested PERMISSIONS.IOS.LOCATION_ALWAYS directly.

Request for Assistance: Could anyone provide guidance on how to ensure that the "Always" location permission option is presented to users? Since I am not able to get the "Always" status directly and handle the scenario where "When In Use" is granted, I’m unable to guide users effectively.

How can I ensure that users are prompted for "Always" permission and manage the situation if only "When In Use" permission is granted to ensure my background services function correctly?

Any help or suggestions would be greatly appreciated.

zoontek commented 2 months ago

You can't have "Always" by default: https://developer.apple.com/documentation/corelocation/cllocationmanager/requestalwaysauthorization()#Request-Always-Authorization-Directly

But you can check for always level and redirect to the app settings to change it if required.