Skip to content

Commit b36f924

Browse files
feat(messaging, apple): allow system to display button for in-app notification settings (#13484)
Co-authored-by: Russell Wheatley <russellwheatley85@gmail.com>
1 parent b51dc2e commit b36f924

File tree

12 files changed

+123
-58
lines changed

12 files changed

+123
-58
lines changed

packages/firebase_messaging/firebase_messaging/example/lib/permissions.dart

+8-2
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,13 @@ class _Permissions extends State<Permissions> {
5757
return Container(
5858
margin: const EdgeInsets.only(bottom: 8),
5959
child: Row(
60-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
6160
children: [
62-
Text('$title:', style: const TextStyle(fontWeight: FontWeight.bold)),
61+
Expanded(
62+
child: Text(
63+
'$title:',
64+
style: const TextStyle(fontWeight: FontWeight.bold),
65+
),
66+
),
6367
Text(value),
6468
],
6569
),
@@ -89,6 +93,8 @@ class _Permissions extends State<Permissions> {
8993
row('Notification Center', settingsMap[_settings.notificationCenter]!),
9094
row('Show Previews', previewMap[_settings.showPreviews]!),
9195
row('Sound', settingsMap[_settings.sound]!),
96+
row('Provides App Notification Settings',
97+
settingsMap[_settings.providesAppNotificationSettings]!),
9298
],
9399
ElevatedButton(
94100
onPressed: checkPermissions, child: const Text('Reload Permissions')),

packages/firebase_messaging/firebase_messaging/ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m

+15
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,12 @@ - (void)messagingRequestPermission:(id)arguments
612612
}
613613
}
614614

615+
if ([permissions[@"providesAppNotificationSettings"] isEqual:@(YES)]) {
616+
if (@available(iOS 12.0, *)) {
617+
options |= UNAuthorizationOptionProvidesAppNotificationSettings;
618+
}
619+
}
620+
615621
id handler = ^(BOOL granted, NSError *_Nullable error) {
616622
if (error != nil) {
617623
result.error(nil, nil, nil, error);
@@ -784,6 +790,15 @@ + (NSDictionary *)NSDictionaryFromUNNotificationSettings:(UNNotificationSettings
784790
NSNumberForUNNotificationSetting:settings.notificationCenterSetting];
785791
settingsDictionary[@"timeSensitive"] = timeSensitive;
786792

793+
if (@available(iOS 12.0, *)) {
794+
if (settings.providesAppNotificationSettings) {
795+
settingsDictionary[@"providesAppNotificationSettings"] = @1;
796+
} else {
797+
settingsDictionary[@"providesAppNotificationSettings"] = @0;
798+
}
799+
} else {
800+
settingsDictionary[@"providesAppNotificationSettings"] = @-1;
801+
}
787802
return settingsDictionary;
788803
}
789804

packages/firebase_messaging/firebase_messaging/lib/src/messaging.dart

+7
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,12 @@ class FirebaseMessaging extends FirebasePluginPlatform {
193193
///
194194
/// iOS/macOS only.
195195
bool sound = true,
196+
197+
/// Request permission for an option indicating the system should display a button for in-app notification settings.
198+
/// Defaults to `false`.
199+
///
200+
/// iOS/macOS only.
201+
bool providesAppNotificationSettings = false,
196202
}) {
197203
return _delegate.requestPermission(
198204
alert: alert,
@@ -202,6 +208,7 @@ class FirebaseMessaging extends FirebasePluginPlatform {
202208
criticalAlert: criticalAlert,
203209
provisional: provisional,
204210
sound: sound,
211+
providesAppNotificationSettings: providesAppNotificationSettings,
205212
);
206213
}
207214

packages/firebase_messaging/firebase_messaging/test/firebase_messaging_test.dart

+47-35
Original file line numberDiff line numberDiff line change
@@ -132,57 +132,69 @@ void main() {
132132
criticalAlert: anyNamed('criticalAlert'),
133133
provisional: anyNamed('provisional'),
134134
sound: anyNamed('sound'),
135+
providesAppNotificationSettings:
136+
anyNamed('providesAppNotificationSettings'),
135137
)).thenAnswer((_) => Future.value(defaultNotificationSettings));
136138

137139
// true values
138140
await messaging!.requestPermission(
139-
alert: true,
140-
announcement: true,
141-
badge: true,
142-
carPlay: true,
143-
criticalAlert: true,
144-
provisional: true,
145-
sound: true);
141+
alert: true,
142+
announcement: true,
143+
badge: true,
144+
carPlay: true,
145+
criticalAlert: true,
146+
provisional: true,
147+
sound: true,
148+
providesAppNotificationSettings: true,
149+
);
146150

147151
verify(kMockMessagingPlatform.requestPermission(
148-
alert: true,
149-
announcement: true,
150-
badge: true,
151-
carPlay: true,
152-
criticalAlert: true,
153-
provisional: true,
154-
sound: true));
152+
alert: true,
153+
announcement: true,
154+
badge: true,
155+
carPlay: true,
156+
criticalAlert: true,
157+
provisional: true,
158+
sound: true,
159+
providesAppNotificationSettings: true,
160+
));
155161

156162
// false values
157163
await messaging!.requestPermission(
158-
alert: false,
159-
announcement: false,
160-
badge: false,
161-
carPlay: false,
162-
criticalAlert: false,
163-
provisional: false,
164-
sound: false);
164+
alert: false,
165+
announcement: false,
166+
badge: false,
167+
carPlay: false,
168+
criticalAlert: false,
169+
provisional: false,
170+
sound: false,
171+
providesAppNotificationSettings: false,
172+
);
165173

166174
verify(kMockMessagingPlatform.requestPermission(
167-
alert: false,
168-
announcement: false,
169-
badge: false,
170-
carPlay: false,
171-
criticalAlert: false,
172-
provisional: false,
173-
sound: false));
175+
alert: false,
176+
announcement: false,
177+
badge: false,
178+
carPlay: false,
179+
criticalAlert: false,
180+
provisional: false,
181+
sound: false,
182+
providesAppNotificationSettings: false,
183+
));
174184

175185
// default values
176186
await messaging!.requestPermission();
177187

178188
verify(kMockMessagingPlatform.requestPermission(
179-
alert: true,
180-
announcement: false,
181-
badge: true,
182-
carPlay: false,
183-
criticalAlert: false,
184-
provisional: false,
185-
sound: true));
189+
alert: true,
190+
announcement: false,
191+
badge: true,
192+
carPlay: false,
193+
criticalAlert: false,
194+
provisional: false,
195+
sound: true,
196+
providesAppNotificationSettings: false,
197+
));
186198
});
187199
});
188200

packages/firebase_messaging/firebase_messaging/test/mock.dart

+12-9
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,16 @@ class MockFirebaseMessaging extends Mock
120120
}
121121

122122
@override
123-
Future<NotificationSettings> requestPermission(
124-
{bool? alert = true,
125-
bool? announcement = false,
126-
bool? badge = true,
127-
bool? carPlay = false,
128-
bool? criticalAlert = false,
129-
bool? provisional = false,
130-
bool? sound = true}) {
123+
Future<NotificationSettings> requestPermission({
124+
bool? alert = true,
125+
bool? announcement = false,
126+
bool? badge = true,
127+
bool? carPlay = false,
128+
bool? criticalAlert = false,
129+
bool? provisional = false,
130+
bool? sound = true,
131+
bool? providesAppNotificationSettings = false,
132+
}) {
131133
return super.noSuchMethod(
132134
Invocation.method(#requestPermission, [], {
133135
#alert: alert,
@@ -136,7 +138,8 @@ class MockFirebaseMessaging extends Mock
136138
#carPlay: carPlay,
137139
#criticalAlert: criticalAlert,
138140
#provisional: provisional,
139-
#sound: sound
141+
#sound: sound,
142+
#providesAppNotificationSettings: providesAppNotificationSettings,
140143
}),
141144
returnValue: neverEndingFuture<NotificationSettings>(),
142145
returnValueForMissingStub: neverEndingFuture<NotificationSettings>());

packages/firebase_messaging/firebase_messaging_platform_interface/lib/src/method_channel/method_channel_messaging.dart

+2
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ class MethodChannelFirebaseMessaging extends FirebaseMessagingPlatform {
284284
bool criticalAlert = false,
285285
bool provisional = false,
286286
bool sound = true,
287+
bool providesAppNotificationSettings = false,
287288
}) async {
288289
if (defaultTargetPlatform != TargetPlatform.iOS &&
289290
defaultTargetPlatform != TargetPlatform.macOS &&
@@ -303,6 +304,7 @@ class MethodChannelFirebaseMessaging extends FirebaseMessagingPlatform {
303304
'criticalAlert': criticalAlert,
304305
'provisional': provisional,
305306
'sound': sound,
307+
'providesAppNotificationSettings': providesAppNotificationSettings,
306308
}
307309
});
308310

packages/firebase_messaging/firebase_messaging_platform_interface/lib/src/notification_settings.dart

+19-12
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,20 @@ import 'package:firebase_messaging_platform_interface/firebase_messaging_platfor
88
/// Represents the devices notification settings.
99
class NotificationSettings {
1010
// ignore: public_member_api_docs
11-
const NotificationSettings(
12-
{required this.alert,
13-
required this.announcement,
14-
required this.authorizationStatus,
15-
required this.badge,
16-
required this.carPlay,
17-
required this.lockScreen,
18-
required this.notificationCenter,
19-
required this.showPreviews,
20-
required this.timeSensitive,
21-
required this.criticalAlert,
22-
required this.sound});
11+
const NotificationSettings({
12+
required this.alert,
13+
required this.announcement,
14+
required this.authorizationStatus,
15+
required this.badge,
16+
required this.carPlay,
17+
required this.lockScreen,
18+
required this.notificationCenter,
19+
required this.showPreviews,
20+
required this.timeSensitive,
21+
required this.criticalAlert,
22+
required this.sound,
23+
required this.providesAppNotificationSettings,
24+
});
2325

2426
/// Whether or not messages containing a notification will alert the user.
2527
///
@@ -79,4 +81,9 @@ class NotificationSettings {
7981
///
8082
/// Apple devices only.
8183
final AppleNotificationSetting sound;
84+
85+
/// Whether or not system displays an application notification settings button
86+
///
87+
/// Apple devices only.
88+
final AppleNotificationSetting providesAppNotificationSettings;
8289
}

packages/firebase_messaging/firebase_messaging_platform_interface/lib/src/platform_interface/platform_interface_messaging.dart

+6
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,12 @@ abstract class FirebaseMessagingPlatform extends PlatformInterface {
252252
///
253253
/// iOS only.
254254
bool sound = true,
255+
256+
/// Request permission for an option indicating the system should display a button for in-app notification settings.
257+
/// Defaults to `false`.
258+
///
259+
/// iOS/macOS only.
260+
bool providesAppNotificationSettings = false,
255261
}) {
256262
throw UnimplementedError('requestPermission() is not implemented');
257263
}

packages/firebase_messaging/firebase_messaging_platform_interface/lib/src/utils.dart

+3
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ NotificationSettings convertToNotificationSettings(Map<String, int> map) {
143143
convertToAppleNotificationSetting(map['notificationCenter']),
144144
showPreviews: convertToAppleShowPreviewSetting(map['showPreviews']),
145145
sound: convertToAppleNotificationSetting(map['sound']),
146+
providesAppNotificationSettings: convertToAppleNotificationSetting(
147+
map['providesAppNotificationSettings']),
146148
);
147149
}
148150

@@ -159,4 +161,5 @@ const NotificationSettings defaultNotificationSettings = NotificationSettings(
159161
sound: AppleNotificationSetting.notSupported,
160162
timeSensitive: AppleNotificationSetting.notSupported,
161163
criticalAlert: AppleNotificationSetting.notSupported,
164+
providesAppNotificationSettings: AppleNotificationSetting.notSupported,
162165
);

packages/firebase_messaging/firebase_messaging_platform_interface/test/method_channel_tests/method_channel_messaging_test.dart

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ void main() {
4949
'criticalAlert': 0,
5050
'provisional': 0,
5151
'sound': 1,
52+
'providesAppNotificationSettings': 0,
5253
};
5354
case 'Messaging#setAutoInitEnabled':
5455
return {
@@ -197,6 +198,7 @@ void main() {
197198
'criticalAlert': false,
198199
'provisional': false,
199200
'sound': true,
201+
'providesAppNotificationSettings': false,
200202
}
201203
},
202204
),

packages/firebase_messaging/firebase_messaging_web/lib/firebase_messaging_web.dart

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class FirebaseMessagingWeb extends FirebaseMessagingPlatform {
142142
bool criticalAlert = false,
143143
bool provisional = false,
144144
bool sound = true,
145+
bool providesAppNotificationSettings = false,
145146
}) {
146147
return convertWebExceptions(() async {
147148
String status =

packages/firebase_messaging/firebase_messaging_web/lib/src/utils.dart

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ NotificationSettings getNotificationSettings(String? status) {
3838
sound: AppleNotificationSetting.notSupported,
3939
timeSensitive: AppleNotificationSetting.notSupported,
4040
criticalAlert: AppleNotificationSetting.notSupported,
41+
providesAppNotificationSettings: AppleNotificationSetting.notSupported,
4142
);
4243
}
4344

0 commit comments

Comments
 (0)