You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On iOS, Firebase isn't involved in delivering notifications, but we've still been using firebase_messaging and firebase_core in some setup that involves communicating with the iOS platform:
If you haven't logged into any accounts yet (which we can check using ZulipBinding.instance.getGlobalStore()), include "provisional" in the authorization request so it doesn't kick up a permissions prompt (for Defer setting up notifications until user has logged in #324).
(Also call it here if you have logged into an account, so that if permissions are still granted, we still call iosRegisterApns, described below. That's how we'll respond to the token changing between app sessions, which can happen. In this case "provisional" isn't needed, I think.)
iosRegisterApns(), which calls UIApplication.shared.registerForRemoteNotifications() (on the main thread via DispatchQueue.main.async). Call this whenever we get a non-denied result from iosRequestAuthorization. (The ios prefix is because NotificationHostApi is shared in the Pigeon definition and generates Kotlin code for Android too.)
New event stream iosApnsRegistrationEvents in NotificationEventChannelApi, emitting IosApnsRegistrationEvent. A single stream for both success and failure, matching the existing notificationTapEvents pattern. The Dart side pattern-matches on the event type.
NotificationService.start adds a listener for this stream beforeiosRegisterApns is ever called, to avoid missing events.
On IosApnsRegistrationSucceeded: update NotificationService.token.
On IosApnsRegistrationFailed: log, and consider retrying iosRegisterApns if the error seems transient (like a network issue).
Clean up: remove kFirebaseOptionsIos (no longer needed). The firebase_core/firebase_messaging deps stay in pubspec.yaml for Android; Flutter doesn't support per-platform plugin exclusion (flutter/flutter#81650).
On iOS, Firebase isn't involved in delivering notifications, but we've still been using
firebase_messagingandfirebase_corein some setup that involves communicating with the iOS platform:NSApplication.registerForRemoteNotifications), and then:POST /users/me/apns_device_token, and soonPOST /api/v1/mobile_push/registerfor E2EE)UNUserNotificationCenter.requestAuthorization(options:completionHandler:))This seems to have worked OK so far, but there are a few issues:
firebase_messagingAPI doesn't seem to support adding a listener for that; instead it looks like it just has a method to query a stateful field which is populated when that AppDelegate method is called. (implementation)If we were writing all of this ourselves, here's a sketch of what it could look like with our current Pigeon architecture (using Swift! 🙂):
IosNotificationAuthorizationStatuswith valuesauthorized,denied,provisional.IosApnsRegistrationEventwith subclasses:IosApnsRegistrationSucceeded— carries aString token(the APNs device token as a hex-encoded string, converted from the rawDataon the Swift side)IosApnsRegistrationFailed— carries aString errorNotificationHostApi:iosRequestAuthorization({required bool provisional}), which is async and returnsIosNotificationAuthorizationStatus. On the Swift side, this callsUNUserNotificationCenter.requestAuthorization(options:completionHandler:), thenUNUserNotificationCenter.getNotificationSettingsto distinguishauthorizedfromprovisional(since therequestAuthorizationcompletion handler only gives a boolean).NotificationService.start.ZulipBinding.instance.getGlobalStore()), include "provisional" in the authorization request so it doesn't kick up a permissions prompt (for Defer setting up notifications until user has logged in #324).iosRegisterApns, described below. That's how we'll respond to the token changing between app sessions, which can happen. In this case "provisional" isn't needed, I think.)iosRegisterApns(), which callsUIApplication.shared.registerForRemoteNotifications()(on the main thread viaDispatchQueue.main.async). Call this whenever we get a non-deniedresult fromiosRequestAuthorization. (Theiosprefix is becauseNotificationHostApiis shared in the Pigeon definition and generates Kotlin code for Android too.)iosApnsRegistrationEventsinNotificationEventChannelApi, emittingIosApnsRegistrationEvent. A single stream for both success and failure, matching the existingnotificationTapEventspattern. The Dart side pattern-matches on the event type.NotificationService.startadds a listener for this stream beforeiosRegisterApnsis ever called, to avoid missing events.IosApnsRegistrationSucceeded: updateNotificationService.token.IosApnsRegistrationFailed: log, and consider retryingiosRegisterApnsif the error seems transient (like a network issue).kFirebaseOptionsIos(no longer needed). Thefirebase_core/firebase_messagingdeps stay in pubspec.yaml for Android; Flutter doesn't support per-platform plugin exclusion (flutter/flutter#81650).