Skip to content

notif android: Request permission at startup #521

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

Merged
merged 2 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 28 additions & 12 deletions lib/notifications.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ class NotificationService {
Future<void> 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);

Expand All @@ -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
Expand All @@ -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();
Expand All @@ -107,6 +108,21 @@ class NotificationService {
}
}

Future<bool> _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<void> _getFcmToken() async {
final value = await ZulipBinding.instance.firebaseMessaging.getToken();
// TODO(#323) warn user if getToken returns null, or doesn't timely return
Expand Down
4 changes: 2 additions & 2 deletions test/notifications_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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', () {
Expand Down