From 86c440ad5ce9011f4512e8575db89493253e5f34 Mon Sep 17 00:00:00 2001 From: vong3432 Date: Mon, 17 Feb 2025 23:37:33 +0800 Subject: [PATCH 1/2] fix: add undetermined permission status to handle notification permission request when app is moved to background --- permission_handler_apple/CHANGELOG.md | 3 +++ .../ios/Classes/PermissionHandlerEnums.h | 1 + .../NotificationPermissionStrategy.m | 22 ++++++++++++------- permission_handler_apple/pubspec.yaml | 2 +- .../CHANGELOG.md | 3 +++ .../lib/src/permission_status.dart | 12 ++++++++++ .../pubspec.yaml | 2 +- .../test/src/permission_status_test.dart | 14 ++++++++++-- 8 files changed, 47 insertions(+), 12 deletions(-) diff --git a/permission_handler_apple/CHANGELOG.md b/permission_handler_apple/CHANGELOG.md index 05dd219d7..7755f7965 100644 --- a/permission_handler_apple/CHANGELOG.md +++ b/permission_handler_apple/CHANGELOG.md @@ -1,3 +1,6 @@ +## 9.4.6 +* 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.5 * Fixes issue #1002, Xcode warning of the unresponsive of main thread when checking isLocationEnabled. 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 ef6679c56..c0a3fb49f 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.5 +version: 9.4.6 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 6e3b35cc9..cb499d91b 100644 --- a/permission_handler_platform_interface/CHANGELOG.md +++ b/permission_handler_platform_interface/CHANGELOG.md @@ -1,3 +1,6 @@ +## 4.2.4 +* 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.2.3 * Fixes class name references in the API documentation. diff --git a/permission_handler_platform_interface/lib/src/permission_status.dart b/permission_handler_platform_interface/lib/src/permission_status.dart index 59a6278ba..35043d3ec 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; default: throw UnimplementedError(); } @@ -74,6 +79,7 @@ extension PermissionStatusValue on PermissionStatus { PermissionStatus.limited, PermissionStatus.permanentlyDenied, PermissionStatus.provisional, + PermissionStatus.undetermined, ][value]; } } @@ -119,6 +125,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. @@ -162,4 +171,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 ca3aea932..897bc0237 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.2.3 +version: 4.2.4 dependencies: flutter: 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); }); }); From d9b95079ff9ed4ec7da043a4aacc662c124a6909 Mon Sep 17 00:00:00 2001 From: vong3432 Date: Fri, 21 Feb 2025 19:03:12 +0800 Subject: [PATCH 2/2] update `permission_handler_apple` to 9.4.7 --- permission_handler_apple/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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"