diff --git a/permission_handler_apple/CHANGELOG.md b/permission_handler_apple/CHANGELOG.md index 20a65108a..fe0d49fea 100644 --- a/permission_handler_apple/CHANGELOG.md +++ b/permission_handler_apple/CHANGELOG.md @@ -1,5 +1,7 @@ -## 9.4.6 +## 9.4.7 +* Adds `PermissionStatus.undetermined` to handle notification permission when the iOS app is moved to the background while the permission dialog is open, previously is returning `PermissionStatus.permanentlyDenied`. +## 9.4.6 * Adds the ability to handle `CNAuthorizationStatusLimited` introduced in ios18 ## 9.4.5 diff --git a/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h b/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h index c153dc500..352a18f85 100644 --- a/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h +++ b/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h @@ -173,6 +173,7 @@ typedef NS_ENUM(int, PermissionStatus) { PermissionStatusLimited = 3, PermissionStatusPermanentlyDenied = 4, PermissionStatusProvisional = 5, + PermissionStatusUndetermined = 6 }; typedef NS_ENUM(int, ServiceStatus) { diff --git a/permission_handler_apple/ios/Classes/strategies/NotificationPermissionStrategy.m b/permission_handler_apple/ios/Classes/strategies/NotificationPermissionStrategy.m index 41d4bcdda..d935f2077 100644 --- a/permission_handler_apple/ios/Classes/strategies/NotificationPermissionStrategy.m +++ b/permission_handler_apple/ios/Classes/strategies/NotificationPermissionStrategy.m @@ -22,11 +22,11 @@ - (void)checkServiceStatus:(PermissionGroup)permission completionHandler:(Servic - (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler errorHandler:(PermissionErrorHandler)errorHandler { PermissionStatus status = [self checkPermissionStatus:permission]; if (@available(iOS 12.0, *)) { - if (status != PermissionStatusDenied && status != PermissionStatusProvisional) { + if (status != PermissionStatusDenied && status != PermissionStatusProvisional && status != PermissionStatusUndetermined) { completionHandler(status); return; } - } else if (status != PermissionStatusDenied) { + } else if (status != PermissionStatusDenied && status != PermissionStatusUndetermined) { completionHandler(status); return; } @@ -38,12 +38,18 @@ - (void)requestPermission:(PermissionGroup)permission completionHandler:(Permiss authorizationOptions += UNAuthorizationOptionAlert; authorizationOptions += UNAuthorizationOptionBadge; [center requestAuthorizationWithOptions:(authorizationOptions) completionHandler:^(BOOL granted, NSError * _Nullable error) { - if (error != nil || !granted) { - completionHandler(PermissionStatusPermanentlyDenied); - return; - } - dispatch_async(dispatch_get_main_queue(), ^{ + if (error == nil && !granted) { + UIApplicationState state = [UIApplication sharedApplication].applicationState; + if (state != UIApplicationStateActive) { + completionHandler(PermissionStatusUndetermined); + return; + } + } + if (error != nil || !granted) { + completionHandler(PermissionStatusPermanentlyDenied); + return; + } [[UIApplication sharedApplication] registerForRemoteNotifications]; completionHandler(PermissionStatusGranted); }); @@ -73,7 +79,7 @@ + (PermissionStatus)permissionStatus { } else if (settings.authorizationStatus == UNAuthorizationStatusDenied) { permissionStatus = PermissionStatusPermanentlyDenied; } else if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) { - permissionStatus = PermissionStatusDenied; + permissionStatus = PermissionStatusUndetermined; } dispatch_semaphore_signal(sem); }]; diff --git a/permission_handler_apple/pubspec.yaml b/permission_handler_apple/pubspec.yaml index c0a3fb49f..1093cb05e 100644 --- a/permission_handler_apple/pubspec.yaml +++ b/permission_handler_apple/pubspec.yaml @@ -2,7 +2,7 @@ name: permission_handler_apple description: Permission plugin for Flutter. This plugin provides the iOS API to request and check permissions. repository: https://github.com/baseflow/flutter-permission-handler issue_tracker: https://github.com/Baseflow/flutter-permission-handler/issues -version: 9.4.6 +version: 9.4.7 environment: sdk: ">=2.15.0 <4.0.0" diff --git a/permission_handler_platform_interface/CHANGELOG.md b/permission_handler_platform_interface/CHANGELOG.md index 825a49ee8..c1c374ed4 100644 --- a/permission_handler_platform_interface/CHANGELOG.md +++ b/permission_handler_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.3.1 + +- Fixes an issue where the request for notification permission returns `permanentlyDenied` when the iOS app is moved to the background while the permission dialog is open. + ## 4.3.0 - Updates project dependencies. diff --git a/permission_handler_platform_interface/lib/src/permission_status.dart b/permission_handler_platform_interface/lib/src/permission_status.dart index 29e9c94f9..f6f3464dc 100644 --- a/permission_handler_platform_interface/lib/src/permission_status.dart +++ b/permission_handler_platform_interface/lib/src/permission_status.dart @@ -41,6 +41,9 @@ enum PermissionStatus { /// /// *Only supported on iOS (iOS12+).* provisional, + + /// The user does not perform any actions to the requested feature. + undetermined, } /// Conversion extension methods for the [PermissionStatus] type. @@ -60,6 +63,8 @@ extension PermissionStatusValue on PermissionStatus { return 4; case PermissionStatus.provisional: return 5; + case PermissionStatus.undetermined: + return 6; } } @@ -72,6 +77,7 @@ extension PermissionStatusValue on PermissionStatus { PermissionStatus.limited, PermissionStatus.permanentlyDenied, PermissionStatus.provisional, + PermissionStatus.undetermined, ][value]; } } @@ -117,6 +123,9 @@ extension PermissionStatusGetters on PermissionStatus { /// /// *Only supported on iOS (iOS12+).* bool get isProvisional => this == PermissionStatus.provisional; + + /// If the user has not perform any action to the requested feature. + bool get isUndetermined => this == PermissionStatus.undetermined; } /// Utility getter extensions for the `Future` type. @@ -160,4 +169,7 @@ extension FuturePermissionStatusGetters on Future { /// /// *Only supported on iOS (iOS12+).* Future get isProvisional async => (await this).isProvisional; + + /// If the user has not perform any action to the requested feature. + Future get isUndetermined async => (await this).isUndetermined; } diff --git a/permission_handler_platform_interface/pubspec.yaml b/permission_handler_platform_interface/pubspec.yaml index 586671633..6dce893af 100644 --- a/permission_handler_platform_interface/pubspec.yaml +++ b/permission_handler_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the permission_handler plugin. homepage: https://github.com/baseflow/flutter-permission-handler/tree/master/permission_handler_platform_interface # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 4.3.0 +version: 4.3.1 environment: sdk: ^3.5.0 diff --git a/permission_handler_platform_interface/test/src/permission_status_test.dart b/permission_handler_platform_interface/test/src/permission_status_test.dart index d26ee6b32..5a9053d7e 100644 --- a/permission_handler_platform_interface/test/src/permission_status_test.dart +++ b/permission_handler_platform_interface/test/src/permission_status_test.dart @@ -3,10 +3,10 @@ import 'package:permission_handler_platform_interface/permission_handler_platfor void main() { group('PermissionStatus', () { - test('PermissionStatus should contain 6 options', () { + test('PermissionStatus should contain 7 options', () { const values = PermissionStatus.values; - expect(values.length, 6); + expect(values.length, 7); }); test('PermissionStatus enum should have items in correct index', () { @@ -18,6 +18,7 @@ void main() { expect(values[3], PermissionStatus.limited); expect(values[4], PermissionStatus.permanentlyDenied); expect(values[5], PermissionStatus.provisional); + expect(values[6], PermissionStatus.undetermined); }); }); @@ -29,6 +30,7 @@ void main() { expect(PermissionStatus.limited.value, 3); expect(PermissionStatus.permanentlyDenied.value, 4); expect(PermissionStatus.provisional.value, 5); + expect(PermissionStatus.undetermined.value, 6); }); test( @@ -44,6 +46,8 @@ void main() { PermissionStatus.permanentlyDenied); expect( PermissionStatusValue.statusByValue(5), PermissionStatus.provisional); + expect(PermissionStatusValue.statusByValue(6), + PermissionStatus.undetermined); }); }); @@ -55,6 +59,7 @@ void main() { expect(PermissionStatus.limited.isLimited, true); expect(PermissionStatus.permanentlyDenied.isPermanentlyDenied, true); expect(PermissionStatus.provisional.isProvisional, true); + expect(PermissionStatus.undetermined.isUndetermined, true); }); test('Getters should return false if statement is not met', () { @@ -64,6 +69,7 @@ void main() { expect(PermissionStatus.limited.isDenied, false); expect(PermissionStatus.permanentlyDenied.isDenied, false); expect(PermissionStatus.provisional.isDenied, false); + expect(PermissionStatus.undetermined.isDenied, false); }); }); @@ -81,6 +87,8 @@ void main() { true); expect( await mockFuture(PermissionStatus.provisional).isProvisional, true); + expect( + await mockFuture(PermissionStatus.undetermined).isUndetermined, true); }); test('Getters should return false if statement is not met', () async { @@ -91,6 +99,8 @@ void main() { expect( await mockFuture(PermissionStatus.permanentlyDenied).isDenied, false); expect(await mockFuture(PermissionStatus.provisional).isDenied, false); + expect( + await mockFuture(PermissionStatus.provisional).isUndetermined, false); }); });