Repository navigation
Conversation
Adds a `tokenReceived` event JS clients can subscribe to for live FCM registration token updates on iOS. Addresses the long-standing request in capacitor-community#177. Implementation: - Plugin.swift `messaging(_:didReceiveRegistrationToken:)` now calls `notifyListeners("tokenReceived", ["token": token])` - Gated on `Messaging.messaging().apnsToken != nil` so the pre-APNs registration token Firebase mints on first launch (which gets immediately replaced) is not emitted to consumers - Deduped against `lastNotifiedToken` so foreground/background transitions do not re-emit the same token JS API: FCM.addListener('tokenReceived', ({ token }) => { ... }); `getToken()` behaviour is unchanged; this PR is purely additive. No new dependencies. The Android side will arrive in a follow-up PR.
Adds the Android side of the `tokenReceived` event introduced for iOS in the previous commit. Closes capacitor-community#177. Implementation: - FCMMessagingService extends @capacitor/push-notifications' MessagingService, calls super first to preserve PushNotifications' registration handling, then forwards onNewToken to FCMPlugin. - AndroidManifest.xml registers FCMMessagingService and uses tools:node="remove" to drop the PushNotifications default service so Android FCM routes MESSAGING_EVENT to ours (FCM only routes to a single FirebaseMessagingService). - FCMPlugin static instance + single-slot pending token buffer + dedup in synchronized dispatchTokenReceived(). Tokens minted before the plugin loads are buffered and dispatched once load() runs. @capacitor/push-notifications is added as a peerDependency. The plugin already coexists with PushNotifications in most apps, and Android cannot route FCM messages to two services independently. Subclassing keeps both working. Maintenance contract: MessagingServiceContractTest asserts that @capacitor/push-notifications' MessagingService still exposes onNewToken(String) and still extends FirebaseMessagingService. CI fails if either changes, preventing silent breakage on push-notifications version bumps.
|
Thanks for the thorough write-up and the contract test. We're closing this one for three reasons:
#190 (iOS) is merged, since on iOS If you have a case |
What
Adds the Android side of the
tokenReceivedevent. Pairs with #190 (iOS) — together they close #177.Implementation:
FCMMessagingServiceextendscom.capacitorjs.plugins.pushnotifications.MessagingService. Callssuper.onNewToken()first (preserving PushNotifications' existing registration handling) then forwards toFCMPlugin.onNewTokenReceived(token), which callsnotifyListeners("tokenReceived", { token }).AndroidManifest.xmlregistersFCMMessagingServiceand usestools:node="remove"to drop@capacitor/push-notifications' default service entry. Android FCM only routesMESSAGING_EVENTto a singleFirebaseMessagingService, so we cannot simply add ours alongside.FCMPluginholds a staticinstance+ single-slotpendingTokenbuffer so cold-start tokens (those emitted before the plugin'sload()runs) are not lost. Dispatch issynchronizedand dedupes againstlastNotifiedToken.JS API (same as iOS, registered in
definitions.ts):Why
Issue #177 has been open since May 2025 asking for a way to monitor token refresh without polling
getToken(). On Android specifically, this event is the only signal for asynchronous token rotations after initial registration.Dependency:
@capacitor/push-notificationsas peerAdded as a
peerDependency(not a hard dependency) at>=8.0.0. Rationale:FirebaseMessagingServiceper APK; subclassing PushNotifications' service keeps both plugins functional simultaneously.@capacitor/push-notificationstoday must add it. Open to discussing alternative architectures (e.g. extendFirebaseMessagingServicedirectly and lose PushNotifications interop) if the maintainers prefer.Maintenance contract
MessagingServiceContractTest(inandroid/src/test/) asserts that@capacitor/push-notifications'MessagingServicestill exposesonNewToken(String)and still extendsFirebaseMessagingService. If either changes in a future PushNotifications release,./gradlew testfails — preventing the silent regression that the manifest comment warns about.Test plan
cd android && ./gradlew test—MessagingServiceContractTestpasses against@capacitor/push-notifications8.x.refreshToken(), and is properly deduped on subsequent re-emissions from FCM../gradlew :app:processDebugManifest— onlyFCMMessagingServiceis registered post-merge.Notes
getToken(),refreshToken(),subscribeTo,unsubscribeFrom, etc. are unchanged. Purely additive.dependencieschange — onlypeerDependencies.Stacking
This PR includes the iOS commit from #190 since both share
definitions.ts(theaddListener('tokenReceived', ...)overload andTokenReceivedEventtype). When #190 merges, this PR's diff narrows to Android-only. If you'd prefer I rebase offmasterand duplicate the TS changes here, happy to do that — let me know.