Commit 6d8d9617 by Jeroen Weener Committed by GitHub

Support iOS 17 calendar permissions (iOS) (#1220)

* - 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

* Separate iOS changes

* Group calendar keys in `Info.plist`

---------

Co-authored-by: milosKarakas <milos.karakas@codebluestudio.com>
Co-authored-by: Miloš Karakaš <34490121+MilosKarakas@users.noreply.github.com>
Co-authored-by: TimHoogstrate <tim566@hotmail.com>
parent 4e0d95f6
## 9.2.0
* Adds the support for `Permission.calendarWriteOnly` and `Permission.calendarFullAccess` permissions which are introduced in iOS 17+.
## 9.1.4 ## 9.1.4
* Adds checking whether Bluetooth service is enabled through `Permission.bluetooth.serviceStatus`. * Adds checking whether Bluetooth service is enabled through `Permission.bluetooth.serviceStatus`.
......
...@@ -47,6 +47,9 @@ post_install do |installer| ...@@ -47,6 +47,9 @@ post_install do |installer|
## dart: PermissionGroup.calendar ## dart: PermissionGroup.calendar
'PERMISSION_EVENTS=1', 'PERMISSION_EVENTS=1',
## dart: PermissionGroup.calendarFullAccess
'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>
......
...@@ -5,15 +5,15 @@ ...@@ -5,15 +5,15 @@
// Created by Razvan Lung on 15/02/2019. // Created by Razvan Lung on 15/02/2019.
// //
// ios: PermissionGroupCalendar // ios: [PermissionGroupCalendar, PermissionGroupCalendarWriteOnly]
// Info.plist: NSCalendarsUsageDescription // Info.plist: [NSCalendarsUsageDescription, NSCalendarWriteOnlyAccessUsageDescription]
// dart: PermissionGroup.calendar // dart: PermissionGroup.calendar
#ifndef PERMISSION_EVENTS #ifndef PERMISSION_EVENTS
#define PERMISSION_EVENTS 0 #define PERMISSION_EVENTS 0
#endif #endif
// ios: PermissionGroupReminders // ios: PermissionGroupReminders
// Info.plist: NSRemindersUsageDescription // Info.plist: NSRemindersFullAccessUsageDescription
// dart: PermissionGroup.reminders // dart: PermissionGroup.reminders
#ifndef PERMISSION_REMINDERS #ifndef PERMISSION_REMINDERS
#define PERMISSION_REMINDERS 0 #define PERMISSION_REMINDERS 0
...@@ -110,6 +110,13 @@ ...@@ -110,6 +110,13 @@
#define PERMISSION_CRITICAL_ALERTS 0 #define PERMISSION_CRITICAL_ALERTS 0
#endif #endif
// ios: PermissionGroupCalendarFullAccess
// Info.plist: [NSCalendarFullAccessUsageDescription]
// dart: PermissionGroup.calendarFullAccess
#ifndef PERMISSION_EVENTS_FULL_ACCESS
#define PERMISSION_EVENTS_FULL_ACCESS 0
#endif
typedef NS_ENUM(int, PermissionGroup) { typedef NS_ENUM(int, PermissionGroup) {
PermissionGroupCalendar = 0, PermissionGroupCalendar = 0,
PermissionGroupCamera, PermissionGroupCamera,
...@@ -146,7 +153,9 @@ typedef NS_ENUM(int, PermissionGroup) { ...@@ -146,7 +153,9 @@ typedef NS_ENUM(int, PermissionGroup) {
PermissiongroupVideos, PermissiongroupVideos,
PermissionGroupAudio, PermissionGroupAudio,
PermissionGroupScheduleExactAlarm, PermissionGroupScheduleExactAlarm,
PermissionGroupSensorsAlways PermissionGroupSensorsAlways,
PermissionGroupCalendarWriteOnly,
PermissionGroupCalendarFullAccess
}; };
typedef NS_ENUM(int, PermissionStatus) { typedef NS_ENUM(int, PermissionStatus) {
......
...@@ -98,6 +98,8 @@ ...@@ -98,6 +98,8 @@
+ (id)createPermissionStrategy:(PermissionGroup)permission { + (id)createPermissionStrategy:(PermissionGroup)permission {
switch (permission) { switch (permission) {
case PermissionGroupCalendar: case PermissionGroupCalendar:
case PermissionGroupCalendarWriteOnly:
case PermissionGroupCalendarFullAccess:
return [EventPermissionStrategy new]; return [EventPermissionStrategy new];
case PermissionGroupCamera: case PermissionGroupCamera:
return [AudioVideoPermissionStrategy new]; return [AudioVideoPermissionStrategy new];
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "PermissionStrategy.h" #import "PermissionStrategy.h"
#if PERMISSION_EVENTS | PERMISSION_REMINDERS #if PERMISSION_EVENTS | PERMISSION_EVENTS_FULL_ACCESS | PERMISSION_REMINDERS
#import <EventKit/EventKit.h> #import <EventKit/EventKit.h>
......
...@@ -5,22 +5,12 @@ ...@@ -5,22 +5,12 @@
#import "EventPermissionStrategy.h" #import "EventPermissionStrategy.h"
#if PERMISSION_EVENTS | PERMISSION_REMINDERS #if PERMISSION_EVENTS | PERMISSION_EVENTS_FULL_ACCESS | PERMISSION_REMINDERS
@implementation EventPermissionStrategy @implementation EventPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission { - (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
if (permission == PermissionGroupCalendar) { return [EventPermissionStrategy permissionStatus:permission];
#if PERMISSION_EVENTS
return [EventPermissionStrategy permissionStatus:EKEntityTypeEvent];
#endif
} else if (permission == PermissionGroupReminders) {
#if PERMISSION_REMINDERS
return [EventPermissionStrategy permissionStatus:EKEntityTypeReminder];
#endif
}
return PermissionStatusDenied;
} }
- (void)checkServiceStatus:(PermissionGroup)permission completionHandler:(ServiceStatusHandler)completionHandler { - (void)checkServiceStatus:(PermissionGroup)permission completionHandler:(ServiceStatusHandler)completionHandler {
...@@ -34,55 +24,124 @@ ...@@ -34,55 +24,124 @@
completionHandler(permissionStatus); completionHandler(permissionStatus);
return; return;
} }
EKEntityType entityType; if (permission == PermissionGroupCalendar || permission == PermissionGroupCalendarFullAccess) {
if (@available(iOS 17.0, *)) {
if (permission == PermissionGroupCalendar) { #if !PERMISSION_EVENTS_FULL_ACCESS
#if PERMISSION_EVENTS completionHandler(PermissionStatusDenied);
entityType = EKEntityTypeEvent; return;
#else #endif
} else {
#if !PERMISSION_EVENTS
completionHandler(PermissionStatusDenied);
return;
#endif
}
} else if (permission == PermissionGroupCalendarWriteOnly) {
#if !PERMISSION_EVENTS && !PERMISSION_EVENTS_FULL_ACCESS
completionHandler(PermissionStatusDenied); completionHandler(PermissionStatusDenied);
return; return;
#endif #endif
} else if (permission == PermissionGroupReminders) { } else if (permission == PermissionGroupReminders) {
#if PERMISSION_REMINDERS #if !PERMISSION_REMINDERS
entityType = EKEntityTypeReminder;
#else
completionHandler(PermissionStatusDenied); completionHandler(PermissionStatusDenied);
return; return;
#endif #endif
} else {
completionHandler(PermissionStatusPermanentlyDenied);
return;
} }
EKEventStore *eventStore = [[EKEventStore alloc] init]; EKEventStore *eventStore = [[EKEventStore alloc] init];
[eventStore requestAccessToEntityType:entityType completion:^(BOOL granted, NSError *error) {
if (granted) { if (@available(iOS 17.0, *)) {
completionHandler(PermissionStatusGranted); if (permission == PermissionGroupCalendar || permission == PermissionGroupCalendarFullAccess) {
} else { [eventStore requestFullAccessToEventsWithCompletion:^(BOOL granted, NSError *error) {
completionHandler(PermissionStatusPermanentlyDenied); if (granted) {
completionHandler(PermissionStatusGranted);
} else {
completionHandler(PermissionStatusPermanentlyDenied);
}
}];
} else if (permission == PermissionGroupCalendarWriteOnly) {
[eventStore requestWriteOnlyAccessToEventsWithCompletion:^(BOOL granted, NSError *error) {
if (granted) {
completionHandler(PermissionStatusGranted);
} else {
completionHandler(PermissionStatusPermanentlyDenied);
}
}];
} else if (permission == PermissionGroupReminders) {
[eventStore requestFullAccessToRemindersWithCompletion:^(BOOL granted, NSError *error) {
if (granted) {
completionHandler(PermissionStatusGranted);
} else {
completionHandler(PermissionStatusPermanentlyDenied);
}
}];
} }
}]; } else {
EKEntityType entityType = [EventPermissionStrategy getEntityType:permission];
[eventStore requestAccessToEntityType:entityType completion:^(BOOL granted, NSError *error) {
if (granted) {
completionHandler(PermissionStatusGranted);
} else {
completionHandler(PermissionStatusPermanentlyDenied);
}
}];
}
} }
+ (PermissionStatus)permissionStatus:(EKEntityType)entityType { + (PermissionStatus)permissionStatus:(PermissionGroup)permission {
EKEntityType entityType = [EventPermissionStrategy getEntityType:permission];
EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:entityType]; EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:entityType];
switch (status) { if (@available(iOS 17.0, *)) {
case EKAuthorizationStatusNotDetermined: switch (status) {
return PermissionStatusDenied; case EKAuthorizationStatusNotDetermined:
case EKAuthorizationStatusRestricted: return PermissionStatusDenied;
return PermissionStatusRestricted; case EKAuthorizationStatusRestricted:
case EKAuthorizationStatusDenied: return PermissionStatusRestricted;
return PermissionStatusPermanentlyDenied; case EKAuthorizationStatusDenied:
case EKAuthorizationStatusAuthorized: return PermissionStatusPermanentlyDenied;
return PermissionStatusGranted; case EKAuthorizationStatusFullAccess:
return PermissionStatusGranted;
case EKAuthorizationStatusWriteOnly:
if (permission == PermissionGroupCalendarWriteOnly) {
return PermissionStatusGranted;
}
return PermissionStatusDenied;
}
} else {
switch (status) {
case EKAuthorizationStatusNotDetermined:
return PermissionStatusDenied;
case EKAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case EKAuthorizationStatusDenied:
return PermissionStatusPermanentlyDenied;
case EKAuthorizationStatusAuthorized:
return PermissionStatusGranted;
case EKAuthorizationStatusWriteOnly:
//not available on iOS 16 and below
break;
}
} }
return PermissionStatusDenied; return PermissionStatusDenied;
} }
+ (EKEntityType)getEntityType:(PermissionGroup)permission {
if (permission == PermissionGroupCalendar || permission == PermissionGroupCalendarFullAccess || permission == PermissionGroupCalendarWriteOnly) {
return EKEntityTypeEvent;
} else if (permission == PermissionGroupReminders) {
return EKEntityTypeReminder;
}
return nil;
}
@end @end
#else #else
......
...@@ -2,7 +2,7 @@ name: permission_handler_apple ...@@ -2,7 +2,7 @@ name: permission_handler_apple
description: Permission plugin for Flutter. This plugin provides the iOS API to request and check permissions. description: Permission plugin for Flutter. This plugin provides the iOS 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: 9.1.4 version: 9.2.0
environment: environment:
sdk: ">=2.15.0 <4.0.0" sdk: ">=2.15.0 <4.0.0"
...@@ -18,7 +18,7 @@ flutter: ...@@ -18,7 +18,7 @@ flutter:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
permission_handler_platform_interface: ^3.11.2 permission_handler_platform_interface: ^4.0.0
dev_dependencies: dev_dependencies:
flutter_lints: ^1.0.4 flutter_lints: ^1.0.4
......
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