Skip to content

fix(push-notifications): resolve unregister() only after FCM token deletion completes on Android - #2607

Open
ciccilleju wants to merge 1 commit into
ionic-team:mainfrom
ciccilleju:fix/push-unregister-await-delete-token
Open

ciccilleju wants to merge 1 commit into
ionic-team:mainfrom
ciccilleju:fix/push-unregister-await-delete-token

Conversation

@ciccilleju

@ciccilleju ciccilleju commented Oct 5, 2026 •

Copy link
Copy Markdown

On Android, unregister() calls FirebaseMessaging.deleteToken() and resolves the JavaScript call immediately, before token deletion finishes. Even when the application awaits unregister() before calling register(), getToken() can still return the cached token. FCM then invalidates that token, leaving the backend with a token that fails with UNREGISTERED and preventing subsequent push delivery.

This change resolves unregister() from deleteToken()'s completion listener and rejects the call if deletion fails. The change is limited to Android; the iOS implementation is unchanged.

Fixes #2593.

Reproduction

  1. Register for push notifications and capture the token from the registration event.
  2. Run the following sequence without adding a delay:
await PushNotifications.unregister();
await PushNotifications.register();
  1. Capture the next token from the registration event. With the current implementation, the previous token can be returned while its deletion is still pending; sending to that token subsequently fails with UNREGISTERED.
  2. With this change, the unregister() promise resolves only after deletion succeeds, so the awaited register() starts after that deletion has completed. A deletion failure rejects unregister() instead of reporting success.

Validation

  • An equivalent fix is applied locally with patch-package to @capacitor/push-notifications 8.1.3, in an app using Capacitor 8.5.2.
  • Android plugin Java compilation passed with Java 21:
./gradlew :capacitor-push-notifications:compileDebugJavaWithJavac
  • This verifies compilation of the local equivalent fix. End-to-end FCM delivery and the deletion-failure path were not tested in this check.
  • Repository CI has not run yet: the pull request workflows currently show action_required.

…letion completes on Android

unregister() resolved right after calling deleteToken(), so a register() issued
before the deletion finished received the cached token, which FCM invalidated
moments later. Resolve from the deleteToken() completion listener and reject if
the deletion fails.
@ciccilleju

Copy link
Copy Markdown
Author

This also addresses #2593. The issue occurs even when awaiting unregister() before calling register(), because the promise currently resolves before FCM token deletion completes. I have updated the description with the awaited reproduction sequence and validation details.

The CI, Bot, and Release Dev Build for PR workflows currently show action_required, with no CI jobs executed. Could a maintainer approve the workflows so CI can run?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: (Push-Notification) Registration listener returns old Token if register is called immediatly after unregister

1 participant