Skip to content

Commit 358307d

Browse files
TokenyetMaikuB
andauthored
[flutter_local_notifications] Add provisional notification support for iOS 12+ and macOS 10.14+ (#2022)
* feat: add provisional notification support for ios 12+ * test: fix tests for the provisional notification feature * refactor: use false by default to match the reuqirement in the issue (#1102) * feat: add macos support for provisional permission * test: fix tests for macos * feat: add macOS support and drop wrong code in iOS * fix: revert back the comment * feat: remove provisional permission from example app * docs: improve doc for requestProvisionalPermission * added changelog entry for 15.1.0 * updated 15.1.0 changelog entry with more details on applicable OS versions and casing --------- Co-authored-by: Michael Bui <[email protected]>
1 parent dd71cac commit 358307d

File tree

9 files changed

+67
-7
lines changed

9 files changed

+67
-7
lines changed

flutter_local_notifications/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
# [15.1.0]
2+
3+
# [iOS][macOS] added the ability to request provisional permissions. On iOS, this is only applicable to iOS 12 or newer. On macOS, this property is only applicable to macOS 10.14 or newer. Thanks to the PR from [Tokenyet](https://github.com/MaikuB/flutter_local_notifications/pull/2022)
4+
15
# [15.0.1]
26

3-
* [Android] Fixed issue [2033](https://github.com/MaikuB/flutter_local_notifications/issues/2033) where notifications on scheduled using older version of the plugin would fail to have the next subsequent ones scheduled. This issue started occuring in 14.0 where support for inexact notifications was added using the `ScheduleMode` enum that was added and resulted in the deprecation of `androidAllowWhileIdle`. A mechanism was added to help "migrate" old notifications that had `androidAllowWhileIdle` specified but didn't account for how there are recurring notifications that were scheduled using older versions of the plugin prior to `androidAllowWhile` being added
7+
* [Android] fixed issue [2033](https://github.com/MaikuB/flutter_local_notifications/issues/2033) where notifications on scheduled using older version of the plugin would fail to have the next subsequent ones scheduled. This issue started occuring in 14.0 where support for inexact notifications was added using the `ScheduleMode` enum that was added and resulted in the deprecation of `androidAllowWhileIdle`. A mechanism was added to help "migrate" old notifications that had `androidAllowWhileIdle` specified but didn't account for how there are recurring notifications that were scheduled using older versions of the plugin prior to `androidAllowWhile` being added
48

59
# [15.0.0]
610

flutter_local_notifications/ios/Classes/FlutterLocalNotificationsPlugin.m

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ @implementation FlutterLocalNotificationsPlugin {
4141
NSString *const REQUEST_SOUND_PERMISSION = @"requestSoundPermission";
4242
NSString *const REQUEST_ALERT_PERMISSION = @"requestAlertPermission";
4343
NSString *const REQUEST_BADGE_PERMISSION = @"requestBadgePermission";
44+
NSString *const REQUEST_PROVISIONAL_PERMISSION = @"requestProvisionalPermission";
4445
NSString *const REQUEST_CRITICAL_PERMISSION = @"requestCriticalPermission";
4546
NSString *const DEFAULT_PRESENT_ALERT = @"defaultPresentAlert";
4647
NSString *const DEFAULT_PRESENT_SOUND = @"defaultPresentSound";
@@ -50,6 +51,7 @@ @implementation FlutterLocalNotificationsPlugin {
5051
NSString *const SOUND_PERMISSION = @"sound";
5152
NSString *const ALERT_PERMISSION = @"alert";
5253
NSString *const BADGE_PERMISSION = @"badge";
54+
NSString *const PROVISIONAL_PERMISSION = @"provisional";
5355
NSString *const CRITICAL_PERMISSION = @"critical";
5456
NSString *const CALLBACK_DISPATCHER = @"callbackDispatcher";
5557
NSString *const ON_NOTIFICATION_CALLBACK_DISPATCHER =
@@ -378,6 +380,7 @@ - (void)initialize:(NSDictionary *_Nonnull)arguments
378380
bool requestedSoundPermission = false;
379381
bool requestedAlertPermission = false;
380382
bool requestedBadgePermission = false;
383+
bool requestedProvisionalPermission = false;
381384
bool requestedCriticalPermission = false;
382385
NSMutableDictionary *presentationOptions = [[NSMutableDictionary alloc] init];
383386
if ([self containsKey:DEFAULT_PRESENT_ALERT forDictionary:arguments]) {
@@ -417,6 +420,9 @@ - (void)initialize:(NSDictionary *_Nonnull)arguments
417420
if ([self containsKey:REQUEST_BADGE_PERMISSION forDictionary:arguments]) {
418421
requestedBadgePermission = [arguments[REQUEST_BADGE_PERMISSION] boolValue];
419422
}
423+
if([self containsKey:REQUEST_PROVISIONAL_PERMISSION forDictionary:arguments]) {
424+
requestedProvisionalPermission = [arguments[REQUEST_PROVISIONAL_PERMISSION] boolValue];
425+
}
420426
if ([self containsKey:REQUEST_CRITICAL_PERMISSION forDictionary:arguments]) {
421427
requestedCriticalPermission =
422428
[arguments[REQUEST_CRITICAL_PERMISSION] boolValue];
@@ -437,6 +443,7 @@ - (void)initialize:(NSDictionary *_Nonnull)arguments
437443
[self requestPermissionsImpl:requestedSoundPermission
438444
alertPermission:requestedAlertPermission
439445
badgePermission:requestedBadgePermission
446+
provisionalPermission: requestedProvisionalPermission
440447
criticalPermission:requestedCriticalPermission
441448
result:result];
442449
}];
@@ -449,6 +456,7 @@ - (void)requestPermissions:(NSDictionary *_Nonnull)arguments
449456
bool soundPermission = false;
450457
bool alertPermission = false;
451458
bool badgePermission = false;
459+
bool provisionalPermission = false;
452460
bool criticalPermission = false;
453461
if ([self containsKey:SOUND_PERMISSION forDictionary:arguments]) {
454462
soundPermission = [arguments[SOUND_PERMISSION] boolValue];
@@ -459,19 +467,24 @@ - (void)requestPermissions:(NSDictionary *_Nonnull)arguments
459467
if ([self containsKey:BADGE_PERMISSION forDictionary:arguments]) {
460468
badgePermission = [arguments[BADGE_PERMISSION] boolValue];
461469
}
470+
if ([self containsKey:PROVISIONAL_PERMISSION forDictionary:arguments]) {
471+
provisionalPermission = [arguments[PROVISIONAL_PERMISSION] boolValue];
472+
}
462473
if ([self containsKey:CRITICAL_PERMISSION forDictionary:arguments]) {
463474
criticalPermission = [arguments[CRITICAL_PERMISSION] boolValue];
464475
}
465476
[self requestPermissionsImpl:soundPermission
466477
alertPermission:alertPermission
467478
badgePermission:badgePermission
479+
provisionalPermission: provisionalPermission
468480
criticalPermission:criticalPermission
469481
result:result];
470482
}
471483

472484
- (void)requestPermissionsImpl:(bool)soundPermission
473485
alertPermission:(bool)alertPermission
474486
badgePermission:(bool)badgePermission
487+
provisionalPermission:(bool)provisionalPermission
475488
criticalPermission:(bool)criticalPermission
476489
result:(FlutterResult _Nonnull)result {
477490
if (!soundPermission && !alertPermission && !badgePermission &&
@@ -494,6 +507,9 @@ - (void)requestPermissionsImpl:(bool)soundPermission
494507
authorizationOptions += UNAuthorizationOptionBadge;
495508
}
496509
if (@available(iOS 12.0, *)) {
510+
if(provisionalPermission) {
511+
authorizationOptions += UNAuthorizationOptionProvisional;
512+
}
497513
if (criticalPermission) {
498514
authorizationOptions += UNAuthorizationOptionCriticalAlert;
499515
}

flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,9 @@ class IOSFlutterLocalNotificationsPlugin
536536
/// application needs to do this at a later point in time, set the
537537
/// [DarwinInitializationSettings.requestAlertPermission],
538538
/// [DarwinInitializationSettings.requestBadgePermission] and
539-
/// [DarwinInitializationSettings.requestSoundPermission] values to false.
539+
/// [DarwinInitializationSettings.requestSoundPermission] and
540+
/// [DarwinInitializationSettings.requestProvisionalPermission] values to
541+
/// false.
540542
/// [requestPermissions] can then be called to request permissions when
541543
/// needed.
542544
///
@@ -576,12 +578,14 @@ class IOSFlutterLocalNotificationsPlugin
576578
bool sound = false,
577579
bool alert = false,
578580
bool badge = false,
581+
bool provisional = false,
579582
bool critical = false,
580583
}) =>
581584
_channel.invokeMethod<bool?>('requestPermissions', <String, bool>{
582585
'sound': sound,
583586
'alert': alert,
584587
'badge': badge,
588+
'provisional': provisional,
585589
'critical': critical,
586590
});
587591

@@ -743,12 +747,14 @@ class MacOSFlutterLocalNotificationsPlugin
743747
bool sound = false,
744748
bool alert = false,
745749
bool badge = false,
750+
bool provisional = false,
746751
bool critical = false,
747752
}) =>
748753
_channel.invokeMethod<bool>('requestPermissions', <String, bool?>{
749754
'sound': sound,
750755
'alert': alert,
751756
'badge': badge,
757+
'provisional': provisional,
752758
'critical': critical,
753759
});
754760

flutter_local_notifications/lib/src/platform_specifics/darwin/initialization_settings.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class DarwinInitializationSettings {
99
this.requestAlertPermission = true,
1010
this.requestSoundPermission = true,
1111
this.requestBadgePermission = true,
12+
this.requestProvisionalPermission = false,
1213
this.requestCriticalPermission = false,
1314
this.defaultPresentAlert = true,
1415
this.defaultPresentSound = true,
@@ -34,6 +35,16 @@ class DarwinInitializationSettings {
3435
/// Default value is true.
3536
final bool requestBadgePermission;
3637

38+
/// Request permission to send provisional notification for iOS 12+
39+
///
40+
/// Subject to specific approval from Apple: https://developer.apple.com/documentation/usernotifications/asking_permission_to_use_notifications#3544375
41+
///
42+
/// Default value is false.
43+
///
44+
/// On iOS, this property is only applicable to iOS 12 or newer.
45+
/// On macOS, this property is only applicable to macOS 10.14 or newer.
46+
final bool requestProvisionalPermission;
47+
3748
/// Request permission to show critical notifications.
3849
///
3950
/// Subject to specific approval from Apple:

flutter_local_notifications/lib/src/platform_specifics/darwin/mappers.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extension DarwinInitializationSettingsMapper on DarwinInitializationSettings {
3838
'requestAlertPermission': requestAlertPermission,
3939
'requestSoundPermission': requestSoundPermission,
4040
'requestBadgePermission': requestBadgePermission,
41+
'requestProvisionalPermission': requestProvisionalPermission,
4142
'requestCriticalPermission': requestCriticalPermission,
4243
'defaultPresentAlert': defaultPresentAlert,
4344
'defaultPresentSound': defaultPresentSound,

flutter_local_notifications/macos/Classes/FlutterLocalNotificationsPlugin.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class FlutterLocalNotificationsPlugin: NSObject, FlutterPlugin, UNUserNot
1414
static let requestAlertPermission = "requestAlertPermission"
1515
static let requestSoundPermission = "requestSoundPermission"
1616
static let requestBadgePermission = "requestBadgePermission"
17+
static let requestProvisionalPermission = "requestProvisionalPermission"
1718
static let requestCriticalPermission = "requestCriticalPermission"
1819
static let defaultPresentAlert = "defaultPresentAlert"
1920
static let defaultPresentSound = "defaultPresentSound"
@@ -23,6 +24,7 @@ public class FlutterLocalNotificationsPlugin: NSObject, FlutterPlugin, UNUserNot
2324
static let alert = "alert"
2425
static let sound = "sound"
2526
static let badge = "badge"
27+
static let provisional = "provisional"
2628
static let critical = "critical"
2729
static let notificationLaunchedApp = "notificationLaunchedApp"
2830
static let id = "id"
@@ -224,13 +226,15 @@ public class FlutterLocalNotificationsPlugin: NSObject, FlutterPlugin, UNUserNot
224226
let requestedAlertPermission = arguments[MethodCallArguments.requestAlertPermission] as! Bool
225227
let requestedSoundPermission = arguments[MethodCallArguments.requestSoundPermission] as! Bool
226228
let requestedBadgePermission = arguments[MethodCallArguments.requestBadgePermission] as! Bool
229+
let requestProvisionalPermission = arguments[MethodCallArguments.requestProvisionalPermission] as! Bool
227230
let requestedCriticalPermission = arguments[MethodCallArguments.requestCriticalPermission] as! Bool
228231

229232
configureNotificationCategories(arguments) {
230233
self.requestPermissionsImpl(
231234
soundPermission: requestedSoundPermission,
232235
alertPermission: requestedAlertPermission,
233236
badgePermission: requestedBadgePermission,
237+
provisionalPermission: requestProvisionalPermission,
234238
criticalPermission: requestedCriticalPermission,
235239
result: result
236240
)
@@ -311,8 +315,10 @@ public class FlutterLocalNotificationsPlugin: NSObject, FlutterPlugin, UNUserNot
311315
let requestedAlertPermission = arguments[MethodCallArguments.alert] as! Bool
312316
let requestedSoundPermission = arguments[MethodCallArguments.sound] as! Bool
313317
let requestedBadgePermission = arguments[MethodCallArguments.badge] as! Bool
318+
let requestedProvisionalPermission = arguments[MethodCallArguments.provisional] as! Bool
314319
let requestedCriticalPermission = arguments[MethodCallArguments.critical] as! Bool
315-
requestPermissionsImpl(soundPermission: requestedSoundPermission, alertPermission: requestedAlertPermission, badgePermission: requestedBadgePermission, criticalPermission: requestedCriticalPermission, result: result)
320+
321+
requestPermissionsImpl(soundPermission: requestedSoundPermission, alertPermission: requestedAlertPermission, badgePermission: requestedBadgePermission, provisionalPermission: requestedProvisionalPermission, criticalPermission: requestedCriticalPermission, result: result)
316322
} else {
317323
result(nil)
318324
}
@@ -634,8 +640,8 @@ public class FlutterLocalNotificationsPlugin: NSObject, FlutterPlugin, UNUserNot
634640
}
635641

636642
@available(macOS 10.14, *)
637-
func requestPermissionsImpl(soundPermission: Bool, alertPermission: Bool, badgePermission: Bool, criticalPermission: Bool, result: @escaping FlutterResult) {
638-
if !soundPermission && !alertPermission && !badgePermission && !criticalPermission {
643+
func requestPermissionsImpl(soundPermission: Bool, alertPermission: Bool, badgePermission: Bool, provisionalPermission: Bool, criticalPermission: Bool, result: @escaping FlutterResult) {
644+
if !soundPermission && !alertPermission && !badgePermission && !provisionalPermission && !criticalPermission {
639645
result(false)
640646
return
641647
}
@@ -649,6 +655,9 @@ public class FlutterLocalNotificationsPlugin: NSObject, FlutterPlugin, UNUserNot
649655
if badgePermission {
650656
options.insert(.badge)
651657
}
658+
if provisionalPermission {
659+
options.insert(.provisional)
660+
}
652661
if criticalPermission {
653662
options.insert(.criticalAlert)
654663
}

flutter_local_notifications/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: flutter_local_notifications
22
description: A cross platform plugin for displaying and scheduling local
33
notifications for Flutter applications with the ability to customise for each
44
platform.
5-
version: 15.0.1
5+
version: 15.1.0
66
homepage: https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications
77
issue_tracker: https://github.com/MaikuB/flutter_local_notifications/issues
88

flutter_local_notifications/test/ios_flutter_local_notifications_test.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ void main() {
4949
'requestAlertPermission': true,
5050
'requestSoundPermission': true,
5151
'requestBadgePermission': true,
52+
'requestProvisionalPermission': false,
53+
'requestCriticalPermission': false,
5254
'defaultPresentAlert': true,
5355
'defaultPresentSound': true,
5456
'defaultPresentBadge': true,
5557
'defaultPresentBanner': true,
5658
'defaultPresentList': true,
57-
'requestCriticalPermission': false,
5859
'notificationCategories': <String>[],
5960
})
6061
]);
@@ -107,6 +108,7 @@ void main() {
107108
'requestAlertPermission': true,
108109
'requestSoundPermission': true,
109110
'requestBadgePermission': true,
111+
'requestProvisionalPermission': false,
110112
'requestCriticalPermission': false,
111113
'defaultPresentAlert': true,
112114
'defaultPresentSound': true,
@@ -168,6 +170,7 @@ void main() {
168170
requestAlertPermission: false,
169171
requestBadgePermission: false,
170172
requestSoundPermission: false,
173+
requestProvisionalPermission: false,
171174
defaultPresentAlert: false,
172175
defaultPresentBadge: false,
173176
defaultPresentSound: false,
@@ -182,6 +185,7 @@ void main() {
182185
'requestAlertPermission': false,
183186
'requestSoundPermission': false,
184187
'requestBadgePermission': false,
188+
'requestProvisionalPermission': false,
185189
'requestCriticalPermission': false,
186190
'defaultPresentAlert': false,
187191
'defaultPresentSound': false,
@@ -577,6 +581,7 @@ void main() {
577581
'sound': false,
578582
'badge': false,
579583
'alert': false,
584+
'provisional': false,
580585
'critical': false,
581586
})
582587
]);
@@ -589,13 +594,15 @@ void main() {
589594
sound: true,
590595
badge: true,
591596
alert: true,
597+
provisional: true,
592598
critical: true,
593599
);
594600
expect(log, <Matcher>[
595601
isMethodCall('requestPermissions', arguments: <String, Object>{
596602
'sound': true,
597603
'badge': true,
598604
'alert': true,
605+
'provisional': true,
599606
'critical': true,
600607
})
601608
]);

flutter_local_notifications/test/macos_flutter_local_notifications_test.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ void main() {
4848
'requestAlertPermission': true,
4949
'requestSoundPermission': true,
5050
'requestBadgePermission': true,
51+
'requestProvisionalPermission': false,
5152
'requestCriticalPermission': false,
5253
'defaultPresentAlert': true,
5354
'defaultPresentSound': true,
@@ -65,6 +66,7 @@ void main() {
6566
requestAlertPermission: false,
6667
requestBadgePermission: false,
6768
requestSoundPermission: false,
69+
requestProvisionalPermission: false,
6870
defaultPresentAlert: false,
6971
defaultPresentBadge: false,
7072
defaultPresentSound: false,
@@ -79,6 +81,7 @@ void main() {
7981
'requestAlertPermission': false,
8082
'requestSoundPermission': false,
8183
'requestBadgePermission': false,
84+
'requestProvisionalPermission': false,
8285
'requestCriticalPermission': false,
8386
'defaultPresentAlert': false,
8487
'defaultPresentSound': false,
@@ -494,6 +497,7 @@ void main() {
494497
'sound': false,
495498
'badge': false,
496499
'alert': false,
500+
'provisional': false,
497501
'critical': false,
498502
})
499503
]);
@@ -506,13 +510,15 @@ void main() {
506510
sound: true,
507511
badge: true,
508512
alert: true,
513+
provisional: true,
509514
critical: true,
510515
);
511516
expect(log, <Matcher>[
512517
isMethodCall('requestPermissions', arguments: <String, Object>{
513518
'sound': true,
514519
'badge': true,
515520
'alert': true,
521+
'provisional': true,
516522
'critical': true,
517523
})
518524
]);

0 commit comments

Comments
 (0)