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

iOS 17: Calendar permission denied when permission manually set to "Write only" (should be "blocked") #889

Closed flochtililoch closed 1 month ago

flochtililoch commented 2 months ago

Before submitting a new issue

Bug summary

On iOS, I use the check method to determine whether or not a specific permission was previously prompted. This gives me the opportunity to render the correct UI to either prompt the permission "in-app" or just redirect to Settings app.

When requesting the calendar permission (PERMISSIONS.IOS.CALENDARS), the initial in-app prompt let me pick the following two options: "Don't Allow" and "Full Access".

I can select either, then go in the Settings app and manually change the permission to "Add Events Only". When I come back into the app, the next call to check will return the string denied (enum key: RNPermissionStatusNotDetermined). However, a subsequent call to request will not show the in-app prompt again, I assume because the permission was already prompted / set.

I feel like the current handling is incorrect: in this situation the check method should return blocked (enum key: RNPermissionStatusDenied). because technically, the calendar permission was already prompted and is no longer requestable in-app. Following the iOS flow chart and this table, the status "denied" implies that the permission is still requestable.

Maybe I'm missing something on why this was coded this way, and can certainly build a workaround on my end, but curious whether this should be changed at the library level.

If you agree that this is a bug, I think the change can be as simple as updating this switch case statement to this - I tested it and it yields (what I assume to be) the correct behavior.

Library version

4.1.5

Environment info

System:
    OS: macOS 14.5
    CPU: (10) arm64 Apple M1 Pro
    Memory: 223.36 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.11.1 - ~/.nvm/versions/node/v20.11.1/bin/node
    Yarn: 1.22.22 - ~/.nvm/versions/node/v20.11.1/bin/yarn
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.1/bin/npm
    Watchman: 2024.01.22.00 - /opt/homebrew/bin/watchman
  Managers:
    CocoaPods: 1.15.2 - /Users/florent/.rbenv/shims/pod
  SDKs:
    iOS SDK:
      Platforms: DriverKit 23.5, iOS 17.5, macOS 14.5, tvOS 17.5, visionOS 1.2, watchOS 10.5
    Android SDK:
      API Levels: 26, 30, 31, 33, 34
      Build Tools: 30.0.2, 30.0.3, 34.0.0
      System Images: android-29 | Google APIs ARM 64 v8a, android-31 | Google APIs ARM 64 v8a, android-33 | Google APIs ARM 64 v8a, android-34 | Google APIs ARM 64 v8a
      Android NDK: Not Found
  IDEs:
    Android Studio: Not Found
    Xcode: 15.4/15F31d - /usr/bin/xcodebuild
  Languages:
    Java: 17.0.10 - /opt/homebrew/opt/openjdk@17/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 17.0.2 => 17.0.2
    react-native: 0.67.4 => 0.67.4
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps to reproduce

Reproducible sample code

import ReactNativePermissions, { PERMISSIONS } from 'react-native-permissions';

await ReactNativePermissions.request(PERMISSIONS.IOS.CALENDARS);

// go to settings app to change permission state then change the line above to:

const status = await ReactNativePermissions.check(PERMISSIONS.IOS.CALENDARS);

// status = RESULTS.BLOCKED
zoontek commented 2 months ago

This is actually not that simple, as CALENDARS_WRITE_ONLY also exists. If you request it before requesting CALENDARS, this is possible to escalade from write to read & write. blocked doesn't work in this case, see:

https://github.com/user-attachments/assets/2827a113-34f2-48b9-8df0-d756bd86b121

But there's indeed an issue. In that case, CALENDARS should return DENIED, then BLOCKED.

flochtililoch commented 2 months ago

I see - if I understand correctly, there's no way to know right now with Apple's APIs whether the in-app prompt to "escalate" from write only to read write is available.

zoontek commented 2 months ago

@flochtililoch This is not an issue anymore in v5.0.0. As on Android, it's impossible to know before requesting if the status is DENIED or BLOCKED, check now returns a boolean (granted, or not).

  1. check(PERMISSIONS.IOS.CALENDARS_WRITE_ONLY) -> false
  2. request(PERMISSIONS.IOS.CALENDARS_WRITE_ONLY) -> granted
  3. check(PERMISSIONS.IOS.CALENDARS) -> false (write is allowed, read isn't)
  4. request(PERMISSIONS.IOS.CALENDARS) -> granted
zoontek commented 1 month ago

This is fixed in v5.0.0.