diff --git a/lib/notifications.dart b/lib/notifications.dart index d7a3c58be2..9ed1e99f91 100644 --- a/lib/notifications.dart +++ b/lib/notifications.dart @@ -62,8 +62,6 @@ class NotificationService { Future start() async { switch (defaultTargetPlatform) { case TargetPlatform.android: - // TODO(#324) defer notif setup if user not logged into any accounts - // (in order to avoid calling for permissions) await ZulipBinding.instance.firebaseInitializeApp( options: kFirebaseOptionsAndroid); @@ -73,6 +71,14 @@ class NotificationService { ZulipBinding.instance.firebaseMessagingOnBackgroundMessage( _onBackgroundMessage); + await _requestPermission(); // TODO(#324): defer if not logged into any accounts + // On Android, the notification permission is only about showing + // notifications in the UI, not about getting notification data in the + // background. Even if the app lacks permission to show notifications + // in the UI, it's useful to get the token and enable the user's Zulip + // servers to send notification data to the client, because it means if + // the user later enables notifications, they'll promptly start working. + // Get the FCM registration token, now and upon changes. See FCM API docs: // https://firebase.google.com/docs/cloud-messaging/android/client#sample-register ZulipBinding.instance.firebaseMessaging.onTokenRefresh @@ -83,16 +89,11 @@ class NotificationService { await ZulipBinding.instance.firebaseInitializeApp( options: kFirebaseOptionsIos); - // Docs on this API: https://firebase.flutter.dev/docs/messaging/permissions/ - final settings = await ZulipBinding.instance.firebaseMessaging - .requestPermission(); - assert(debugLog('notif settings: $settings')); - switch (settings.authorizationStatus) { - case AuthorizationStatus.denied: - return; - case AuthorizationStatus.authorized: - case AuthorizationStatus.provisional: - case AuthorizationStatus.notDetermined: + if (!await _requestPermission()) { + // TODO(#324): request only "provisional" permission at this stage: + // https://github.com/zulip/zulip-flutter/issues/324#issuecomment-1771400325 + // then proceed to get and use the token just like on Android + return; } await _getApnsToken(); @@ -107,6 +108,21 @@ class NotificationService { } } + Future _requestPermission() async { + // Docs on this API: https://firebase.flutter.dev/docs/messaging/permissions/ + final settings = await ZulipBinding.instance.firebaseMessaging + .requestPermission(); + assert(debugLog('notif authorization: ${settings.authorizationStatus}')); + switch (settings.authorizationStatus) { + case AuthorizationStatus.denied: + return false; + case AuthorizationStatus.authorized: + case AuthorizationStatus.provisional: + case AuthorizationStatus.notDetermined: + return true; + } + } + Future _getFcmToken() async { final value = await ZulipBinding.instance.firebaseMessaging.getToken(); // TODO(#323) warn user if getToken returns null, or doesn't timely return diff --git a/test/notifications_test.dart b/test/notifications_test.dart index 50940943ea..38d2d7bd98 100644 --- a/test/notifications_test.dart +++ b/test/notifications_test.dart @@ -82,11 +82,11 @@ void main() { } group('permissions', () { - testWidgets('on iOS request permission', (tester) async { + testWidgets('request permission', (tester) async { await init(); check(testBinding.firebaseMessaging.takeRequestPermissionCalls()) .length.equals(1); - }, variant: TargetPlatformVariant.only(TargetPlatform.iOS)); + }, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS})); }); group('NotificationChannelManager', () {