Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(messaging, ios): allow system to display button for in-app notification settings #13484

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ class _Permissions extends State<Permissions> {
return Container(
margin: const EdgeInsets.only(bottom: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
StanleyCocos marked this conversation as resolved.
Show resolved Hide resolved
children: [
Text('$title:', style: const TextStyle(fontWeight: FontWeight.bold)),
Expanded(child: Text('$title:', style: const TextStyle(fontWeight: FontWeight.bold))),
Text(value),
],
),
Expand Down Expand Up @@ -89,6 +89,7 @@ class _Permissions extends State<Permissions> {
row('Notification Center', settingsMap[_settings.notificationCenter]!),
row('Show Previews', previewMap[_settings.showPreviews]!),
row('Sound', settingsMap[_settings.sound]!),
row('Provides App Notification Settings', settingsMap[_settings.providesAppNotificationSettings]!),
],
ElevatedButton(
onPressed: checkPermissions, child: const Text('Reload Permissions')),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,12 @@ - (void)messagingRequestPermission:(id)arguments
options |= UNAuthorizationOptionCriticalAlert;
}
}

if ([permissions[@"providesAppNotificationSettings"] isEqual:@(YES)]) {
if (@available(iOS 12.0, *)) {
options |= UNAuthorizationOptionProvidesAppNotificationSettings;
}
}

id handler = ^(BOOL granted, NSError *_Nullable error) {
if (error != nil) {
Expand Down Expand Up @@ -771,7 +777,16 @@ + (NSDictionary *)NSDictionaryFromUNNotificationSettings:(UNNotificationSettings
settingsDictionary[@"notificationCenter"] = [FLTFirebaseMessagingPlugin
NSNumberForUNNotificationSetting:settings.notificationCenterSetting];
settingsDictionary[@"timeSensitive"] = timeSensitive;


if (@available(iOS 12.0, *)) {
if (settings.providesAppNotificationSettings) {
settingsDictionary[@"providesAppNotificationSettings"] = @1;
} else {
settingsDictionary[@"providesAppNotificationSettings"] = @0;
}
} else {
settingsDictionary[@"providesAppNotificationSettings"] = @-1;
}
return settingsDictionary;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ class FirebaseMessaging extends FirebasePluginPlatform {
///
/// iOS/macOS only.
bool sound = true,

/// Request permission for an option indicating the system should display a button for in-app notification settings.
/// Defaults to `false`.
///
/// iOS/macOS only.
bool providesAppNotificationSettings = false,
}) {
return _delegate.requestPermission(
alert: alert,
Expand All @@ -202,6 +208,7 @@ class FirebaseMessaging extends FirebasePluginPlatform {
criticalAlert: criticalAlert,
provisional: provisional,
sound: sound,
providesAppNotificationSettings: providesAppNotificationSettings,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,57 +132,68 @@ void main() {
criticalAlert: anyNamed('criticalAlert'),
provisional: anyNamed('provisional'),
sound: anyNamed('sound'),
providesAppNotificationSettings: anyNamed('providesAppNotificationSettings'),
)).thenAnswer((_) => Future.value(defaultNotificationSettings));

// true values
await messaging!.requestPermission(
alert: true,
announcement: true,
badge: true,
carPlay: true,
criticalAlert: true,
provisional: true,
sound: true);
alert: true,
announcement: true,
badge: true,
carPlay: true,
criticalAlert: true,
provisional: true,
sound: true,
providesAppNotificationSettings: true,
);

verify(kMockMessagingPlatform.requestPermission(
alert: true,
announcement: true,
badge: true,
carPlay: true,
criticalAlert: true,
provisional: true,
sound: true));
alert: true,
announcement: true,
badge: true,
carPlay: true,
criticalAlert: true,
provisional: true,
sound: true,
providesAppNotificationSettings: true,
));

// false values
await messaging!.requestPermission(
alert: false,
announcement: false,
badge: false,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: false);
alert: false,
announcement: false,
badge: false,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: false,
providesAppNotificationSettings: false,
);

verify(kMockMessagingPlatform.requestPermission(
alert: false,
announcement: false,
badge: false,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: false));
alert: false,
announcement: false,
badge: false,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: false,
providesAppNotificationSettings: false,
));

// default values
await messaging!.requestPermission();

verify(kMockMessagingPlatform.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true));
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
providesAppNotificationSettings: true,
));
});
});

Expand Down
21 changes: 12 additions & 9 deletions packages/firebase_messaging/firebase_messaging/test/mock.dart
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,16 @@ class MockFirebaseMessaging extends Mock
}

@override
Future<NotificationSettings> requestPermission(
{bool? alert = true,
bool? announcement = false,
bool? badge = true,
bool? carPlay = false,
bool? criticalAlert = false,
bool? provisional = false,
bool? sound = true}) {
Future<NotificationSettings> requestPermission({
bool? alert = true,
bool? announcement = false,
bool? badge = true,
bool? carPlay = false,
bool? criticalAlert = false,
bool? provisional = false,
bool? sound = true,
bool? providesAppNotificationSettings = false,
}) {
return super.noSuchMethod(
Invocation.method(#requestPermission, [], {
#alert: alert,
Expand All @@ -136,7 +138,8 @@ class MockFirebaseMessaging extends Mock
#carPlay: carPlay,
#criticalAlert: criticalAlert,
#provisional: provisional,
#sound: sound
#sound: sound,
#providesAppNotificationSettings: providesAppNotificationSettings,
}),
returnValue: neverEndingFuture<NotificationSettings>(),
returnValueForMissingStub: neverEndingFuture<NotificationSettings>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ class MethodChannelFirebaseMessaging extends FirebaseMessagingPlatform {
bool criticalAlert = false,
bool provisional = false,
bool sound = true,
bool providesAppNotificationSettings = false,
}) async {
if (defaultTargetPlatform != TargetPlatform.iOS &&
defaultTargetPlatform != TargetPlatform.macOS &&
Expand All @@ -303,6 +304,7 @@ class MethodChannelFirebaseMessaging extends FirebaseMessagingPlatform {
'criticalAlert': criticalAlert,
'provisional': provisional,
'sound': sound,
'providesAppNotificationSettings': providesAppNotificationSettings,
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@ import 'package:firebase_messaging_platform_interface/firebase_messaging_platfor
/// Represents the devices notification settings.
class NotificationSettings {
// ignore: public_member_api_docs
const NotificationSettings(
{required this.alert,
required this.announcement,
required this.authorizationStatus,
required this.badge,
required this.carPlay,
required this.lockScreen,
required this.notificationCenter,
required this.showPreviews,
required this.timeSensitive,
required this.criticalAlert,
required this.sound});
const NotificationSettings({
required this.alert,
required this.announcement,
required this.authorizationStatus,
required this.badge,
required this.carPlay,
required this.lockScreen,
required this.notificationCenter,
required this.showPreviews,
required this.timeSensitive,
required this.criticalAlert,
required this.sound,
required this.providesAppNotificationSettings,
});

/// Whether or not messages containing a notification will alert the user.
///
Expand Down Expand Up @@ -79,4 +81,9 @@ class NotificationSettings {
///
/// Apple devices only.
final AppleNotificationSetting sound;

/// Whether or not system displays an application notification settings button
///
/// Apple devices only.
final AppleNotificationSetting providesAppNotificationSettings;
}
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,12 @@ abstract class FirebaseMessagingPlatform extends PlatformInterface {
///
/// iOS only.
bool sound = true,

/// Request permission for an option indicating the system should display a button for in-app notification settings.
/// Defaults to `false`.
///
/// iOS/macOS only.
bool providesAppNotificationSettings = false,
}) {
throw UnimplementedError('requestPermission() is not implemented');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ NotificationSettings convertToNotificationSettings(Map<String, int> map) {
convertToAppleNotificationSetting(map['notificationCenter']),
showPreviews: convertToAppleShowPreviewSetting(map['showPreviews']),
sound: convertToAppleNotificationSetting(map['sound']),
providesAppNotificationSettings: convertToAppleNotificationSetting(map['providesAppNotificationSettings']),
);
}

Expand All @@ -159,4 +160,5 @@ const NotificationSettings defaultNotificationSettings = NotificationSettings(
sound: AppleNotificationSetting.notSupported,
timeSensitive: AppleNotificationSetting.notSupported,
criticalAlert: AppleNotificationSetting.notSupported,
providesAppNotificationSettings: AppleNotificationSetting.notSupported,
);
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class FirebaseMessagingWeb extends FirebaseMessagingPlatform {
bool criticalAlert = false,
bool provisional = false,
bool sound = true,
bool providesAppNotificationSettings = false,
}) {
return convertWebExceptions(() async {
String status =
Expand Down
Loading