Commit e3c92e38 by Miloš Karakaš Committed by GitHub

Support Calendar Access Levels (iOS17+) (#1151)

* - Split iOS calendar permission into write only and full access

* - Fixes + adjust readme and bump versions

* - Adjust Changelog.md

* - Support iOS 17+ calendar permissions

* - Update README.md to reflect iOS 17+ calendar permissions

* - Fix PermissionManager.m issue

* - Fix dependencies

* #1108 Adjusted for calendarReadOnly and calendarFullAccess

* #1108 Remove breaking change annotation from changelog

* Switch calendarReadOnly to calendarWriteOnly

* Update permission_handler/CHANGELOG.md

Co-authored-by: TimHoogstrate <tim566@hotmail.com>

* - Adjusted iOS EventPermissionStrategy.m after review

* Added NSCalendarsFullAccessUsageDescription to apple example .plist and podfile

* Fix deprecated calendar permission logic

* Update EventPermissionStrategy.m

* Make small adjustments

* Make small touch-ups

* Updates `Runner.xcodeproj` files

* Update permission_handler/README.md

Co-authored-by: TimHoogstrate <tim566@hotmail.com>

* Update permission_handler/README.md

Co-authored-by: TimHoogstrate <tim566@hotmail.com>

* Replace `calendar` with `contacts` in tests

* Update permission_handler_apple.yaml

* Update permission_handler.yaml

* Update permission_handler.yaml

* Update permission_handler_apple.yaml

---------

Co-authored-by: milosKarakas <milos.karakas@codebluestudio.com>
Co-authored-by: TimHoogstrate <tim566@hotmail.com>
Co-authored-by: Jeroen Weener <JeroenWeener@users.noreply.github.com>
Co-authored-by: Maurits van Beusekom <maurits@baseflow.com>
parent 5b4a5c42
...@@ -22,7 +22,11 @@ jobs: ...@@ -22,7 +22,11 @@ jobs:
name: App facing package name: App facing package
# The type of runner that the job will run on # The type of runner that the job will run on
runs-on: macos-latest #
# TODO(mvanbeusekom): Manually set to macOS 13 to support Xcode 15 and iOS 17 SDKs.
# Currently `macos-latest` is based on macOS 12 and doesn't support iOS 17 SDK. This
# should be moved back to `macos-latest` when GitHub Actions images are updated.
runs-on: macos-13
env: env:
source-directory: ./permission_handler source-directory: ./permission_handler
...@@ -33,6 +37,13 @@ jobs: ...@@ -33,6 +37,13 @@ jobs:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3 - uses: actions/checkout@v3
# Override current Xcode version with version 15.0.1.
#
# TODO(mvanbeusekom): Remove when the macos-latest image supports version 15.0.1
# out of the box (see https://github.com/actions/runner-images/blob/main/README.md).
- name: Select Xcode version
run: sudo xcode-select -s '/Applications/Xcode_15.0.1.app/Contents/Developer'
# Make sure JAVA version 17 is installed on build agent. # Make sure JAVA version 17 is installed on build agent.
- uses: actions/setup-java@v3 - uses: actions/setup-java@v3
with: with:
......
...@@ -22,7 +22,11 @@ jobs: ...@@ -22,7 +22,11 @@ jobs:
name: Apple platform package name: Apple platform package
# The type of runner that the job will run on # The type of runner that the job will run on
runs-on: macos-latest #
# TODO(mvanbeusekom): Manually set to macOS 13 to support Xcode 15 and iOS 17 SDKs.
# Currently `macos-latest` is based on macOS 12 and doesn't support iOS 17 SDK. This
# should be moved back to `macos-latest` when GitHub Actions images are updated.
runs-on: macos-13
env: env:
source-directory: ./permission_handler_apple source-directory: ./permission_handler_apple
...@@ -32,6 +36,13 @@ jobs: ...@@ -32,6 +36,13 @@ jobs:
steps: steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3 - uses: actions/checkout@v3
# Override current Xcode version with version 15.0.1.
#
# TODO(mvanbeusekom): Remove when the macos-latest image supports version 15.0.1
# out of the box (see https://github.com/actions/runner-images/blob/main/README.md).
- name: Select Xcode version
run: sudo xcode-select -s '/Applications/Xcode_15.0.1.app/Contents/Developer'
# Make sure the stable version of Flutter is available # Make sure the stable version of Flutter is available
- uses: subosito/flutter-action@v2 - uses: subosito/flutter-action@v2
......
## 11.1.0
* Adds support for iOS 17+ [Calendar access levels](https://developer.apple.com/documentation/technotes/tn3152-migrating-to-the-latest-calendar-access-levels).
* Deprecates `Permission.calendar`. Use `Permission.calendarWriteOnly` to request a write-only access to the calendar. For full access to calendar use `Permission.calendarFullAccess`.
* For `Permission.calendarFullAccess` on iOS 17+ use `PERMISSION_EVENTS_FULL_ACCESS` in Podfile instead of `PERMISSION_EVENTS`.
* Adds web support by endorsing `permission_handler_html` as the web implementation of the permission handler. Only some permissions are supported at this time.
* Updates `permission_handler_android` dependency to version 12.0.1.
* Updates `permission_handler_apple` dependency to version 9.2.0.
* Updates `permission_handler_windows` dependency to version 0.2.0.
* Updates `permission_handler_platform_interface` dependency to version 4.0.2.
## 11.0.1 ## 11.0.1
* Adds extension methods to the `PermissionStatus` enum allowing developers to register callback methods, which will improve code readability. * Adds extension methods to the `PermissionStatus` enum allowing developers to register callback methods, which will improve code readability.
...@@ -74,7 +84,7 @@ ...@@ -74,7 +84,7 @@
## 9.0.2 ## 9.0.2
* Fixes regression when requesting 'locationAlways' permission on Andriod 9 (Pie) and earlier. * Fixes regression when requesting 'locationAlways' permission on Android 9 (Pie) and earlier.
## 9.0.1 ## 9.0.1
......
...@@ -83,9 +83,12 @@ You must list the permission you want to use in your application: ...@@ -83,9 +83,12 @@ You must list the permission you want to use in your application:
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)', '$(inherited)',
## dart: PermissionGroup.calendar ## dart: [PermissionGroup.calendarWriteOnly, PermissionGroup.calendar (iOS 16 and below)]
# 'PERMISSION_EVENTS=1', # 'PERMISSION_EVENTS=1',
## dart: [PermissionGroup.calendarFullAccess, PermissionGroup.calendar (iOS 17 and above)]
# 'PERMISSION_EVENTS_FULL_ACCESS=1',
## dart: PermissionGroup.reminders ## dart: PermissionGroup.reminders
# 'PERMISSION_REMINDERS=1', # 'PERMISSION_REMINDERS=1',
...@@ -143,22 +146,20 @@ You must list the permission you want to use in your application: ...@@ -143,22 +146,20 @@ You must list the permission you want to use in your application:
e.g. when you don't need camera permission, just delete 'NSCameraUsageDescription' e.g. when you don't need camera permission, just delete 'NSCameraUsageDescription'
The following lists the relationship between `Permission` and `The key of Info.plist`: The following lists the relationship between `Permission` and `The key of Info.plist`:
| Permission | Info.plist | Macro | | Permission | Info.plist | Macro |
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------ | |-------------------------------------------------------------------------------------------| ------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
| PermissionGroup.calendar | NSCalendarsUsageDescription | PERMISSION_EVENTS | | PermissionGroup.calendar (< iOS 17) | NSCalendarsUsageDescription | PERMISSION_EVENTS |
| PermissionGroup.reminders | NSRemindersUsageDescription | PERMISSION_REMINDERS | | PermissionGroup.calendarWriteOnly (iOS 17+) | NSCalendarsWriteOnlyAccessUsageDescription | PERMISSION_EVENTS |
| PermissionGroup.contacts | NSContactsUsageDescription | PERMISSION_CONTACTS | | PermissionGroup.calendarFullAccess (iOS 17+) | NSCalendarsFullAccessUsageDescription | PERMISSION_EVENTS_FULL_ACCESS |
| PermissionGroup.camera | NSCameraUsageDescription | PERMISSION_CAMERA | | PermissionGroup.reminders | NSRemindersUsageDescription | PERMISSION_REMINDERS |
| PermissionGroup.microphone | NSMicrophoneUsageDescription | PERMISSION_MICROPHONE | | PermissionGroup.contacts | NSContactsUsageDescription | PERMISSION_CONTACTS |
| PermissionGroup.speech | NSSpeechRecognitionUsageDescription | PERMISSION_SPEECH_RECOGNIZER | | PermissionGroup.camera | NSCameraUsageDescription | PERMISSION_CAMERA |
| PermissionGroup.photos | NSPhotoLibraryUsageDescription | PERMISSION_PHOTOS | | PermissionGroup.microphone | NSMicrophoneUsageDescription | PERMISSION_MICROPHONE |
| PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse | NSLocationUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription, NSLocationWhenInUseUsageDescription | PERMISSION_LOCATION | | PermissionGroup.speech | NSSpeechRecognitionUsageDescription | PERMISSION_SPEECH_RECOGNIZER |
| PermissionGroup.notification | PermissionGroupNotification | PERMISSION_NOTIFICATIONS | | PermissionGroup.photos | NSPhotoLibraryUsageDescription | PERMISSION_PHOTOS |
| PermissionGroup.mediaLibrary | NSAppleMusicUsageDescription, kTCCServiceMediaLibrary | PERMISSION_MEDIA_LIBRARY | | PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse | NSLocationUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription, NSLocationWhenInUseUsageDescription | PERMISSION_LOCATION |
| PermissionGroup.sensors | NSMotionUsageDescription | PERMISSION_SENSORS | | PermissionGroup.notification | PermissionGroupNotification | PERMISSION_NOTIFICATIONS |
| PermissionGroup.bluetooth | NSBluetoothAlwaysUsageDescription, NSBluetoothPeripheralUsageDescription | PERMISSION_BLUETOOTH | | PermissionGroup.mediaLibrary | NSAppleMusicUsageDescription, kTCCServiceMedia
| PermissionGroup.appTrackingTransparency | NSUserTrackingUsageDescription | PERMISSION_APP_TRACKING_TRANSPARENCY |
| PermissionGroup.criticalAlerts | PermissionGroupCriticalAlerts | PERMISSION_CRITICAL_ALERTS |
4. Clean & Rebuild 4. Clean & Rebuild
......
...@@ -45,8 +45,11 @@ post_install do |installer| ...@@ -45,8 +45,11 @@ post_install do |installer|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)', '$(inherited)',
## dart: PermissionGroup.calendar ## dart: [PermissionGroup.calendarWriteOnly, PermissionGroup.calendar (until iOS 16)]
'PERMISSION_EVENTS=1', 'PERMISSION_EVENTS=1',
## dart: [PermissionGroup.calendarFullAccess, PermissionGroup.calendar (from iOS 17)]
'PERMISSION_EVENTS_FULL_ACCESS=1',
## dart: PermissionGroup.reminders ## dart: PermissionGroup.reminders
'PERMISSION_REMINDERS=1', 'PERMISSION_REMINDERS=1',
......
...@@ -155,7 +155,7 @@ ...@@ -155,7 +155,7 @@
97C146E61CF9000F007C117D /* Project object */ = { 97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1300; LastUpgradeCheck = 1430;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1300" LastUpgradeVersion = "1430"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
......
...@@ -61,6 +61,8 @@ ...@@ -61,6 +61,8 @@
<!-- Permission options for the `calendar` group --> <!-- Permission options for the `calendar` group -->
<key>NSCalendarsUsageDescription</key> <key>NSCalendarsUsageDescription</key>
<string>Calendars</string> <string>Calendars</string>
<key>NSCalendarsFullAccessUsageDescription</key>
<string>Calendar full access</string>
<!-- Permission options for the `camera` group --> <!-- Permission options for the `camera` group -->
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
......
...@@ -2,7 +2,7 @@ name: permission_handler ...@@ -2,7 +2,7 @@ name: permission_handler
description: Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions. description: Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
repository: https://github.com/baseflow/flutter-permission-handler repository: https://github.com/baseflow/flutter-permission-handler
issue_tracker: https://github.com/Baseflow/flutter-permission-handler/issues issue_tracker: https://github.com/Baseflow/flutter-permission-handler/issues
version: 11.0.1 version: 11.1.0
environment: environment:
sdk: ">=2.15.0 <4.0.0" sdk: ">=2.15.0 <4.0.0"
...@@ -15,6 +15,8 @@ flutter: ...@@ -15,6 +15,8 @@ flutter:
default_package: permission_handler_android default_package: permission_handler_android
ios: ios:
default_package: permission_handler_apple default_package: permission_handler_apple
web:
default_package: permission_handler_html
windows: windows:
default_package: permission_handler_windows default_package: permission_handler_windows
...@@ -22,10 +24,11 @@ dependencies: ...@@ -22,10 +24,11 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
meta: ^1.7.0 meta: ^1.7.0
permission_handler_android: ^11.0.0 permission_handler_android: ^12.0.1
permission_handler_apple: ^9.1.4 permission_handler_apple: ^9.2.0
permission_handler_windows: ^0.1.3 permission_handler_html: ^0.1.0+1
permission_handler_platform_interface: ^3.11.5 permission_handler_windows: ^0.2.0
permission_handler_platform_interface: ^4.0.2
dev_dependencies: dev_dependencies:
flutter_lints: ^1.0.4 flutter_lints: ^1.0.4
......
...@@ -17,7 +17,7 @@ void main() { ...@@ -17,7 +17,7 @@ void main() {
}); });
test('PermissionActions on Permission: get status', () async { test('PermissionActions on Permission: get status', () async {
final permissionStatus = await Permission.calendar.status; final permissionStatus = await Permission.contacts.status;
expect(permissionStatus, PermissionStatus.granted); expect(permissionStatus, PermissionStatus.granted);
}); });
...@@ -29,50 +29,50 @@ void main() { ...@@ -29,50 +29,50 @@ void main() {
final mockPermissionHandlerPlatform = PermissionHandlerPlatform.instance; final mockPermissionHandlerPlatform = PermissionHandlerPlatform.instance;
when(mockPermissionHandlerPlatform when(mockPermissionHandlerPlatform
.shouldShowRequestPermissionRationale(Permission.calendar)) .shouldShowRequestPermissionRationale(Permission.contacts))
.thenAnswer((_) => Future.value(true)); .thenAnswer((_) => Future.value(true));
await Permission.calendar.shouldShowRequestRationale; await Permission.contacts.shouldShowRequestRationale;
verify(mockPermissionHandlerPlatform verify(mockPermissionHandlerPlatform
.shouldShowRequestPermissionRationale(Permission.calendar)) .shouldShowRequestPermissionRationale(Permission.contacts))
.called(1); .called(1);
}); });
test('PermissionActions on Permission: request()', () async { test('PermissionActions on Permission: request()', () async {
final permissionRequest = Permission.calendar.request(); final permissionRequest = Permission.contacts.request();
expect(permissionRequest, isA<Future<PermissionStatus>>()); expect(permissionRequest, isA<Future<PermissionStatus>>());
}); });
test('PermissionCheckShortcuts on Permission: get isGranted', () async { test('PermissionCheckShortcuts on Permission: get isGranted', () async {
final isGranted = await Permission.calendar.isGranted; final isGranted = await Permission.contacts.isGranted;
expect(isGranted, true); expect(isGranted, true);
}); });
test('PermissionCheckShortcuts on Permission: get isDenied', () async { test('PermissionCheckShortcuts on Permission: get isDenied', () async {
final isDenied = await Permission.calendar.isDenied; final isDenied = await Permission.contacts.isDenied;
expect(isDenied, false); expect(isDenied, false);
}); });
test('PermissionCheckShortcuts on Permission: get isRestricted', () async { test('PermissionCheckShortcuts on Permission: get isRestricted', () async {
final isRestricted = await Permission.calendar.isRestricted; final isRestricted = await Permission.contacts.isRestricted;
expect(isRestricted, false); expect(isRestricted, false);
}); });
test('PermissionCheckShortcuts on Permission: get isLimited', () async { test('PermissionCheckShortcuts on Permission: get isLimited', () async {
final isLimited = await Permission.calendar.isLimited; final isLimited = await Permission.contacts.isLimited;
expect(isLimited, false); expect(isLimited, false);
}); });
test('PermissionCheckShortcuts on Permission: get isPermanentlyDenied', test('PermissionCheckShortcuts on Permission: get isPermanentlyDenied',
() async { () async {
final isPermanentlyDenied = await Permission.calendar.isPermanentlyDenied; final isPermanentlyDenied = await Permission.contacts.isPermanentlyDenied;
expect(isPermanentlyDenied, false); expect(isPermanentlyDenied, false);
}); });
test('PermissionCheckShortcuts on Permission: get isProvisional', () async { test('PermissionCheckShortcuts on Permission: get isProvisional', () async {
final isProvisional = await Permission.calendar.isProvisional; final isProvisional = await Permission.contacts.isProvisional;
expect(isProvisional, false); expect(isProvisional, false);
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment