feat(mobile/android): end-to-end push notifications — FCM registration, POST_NOTIFICATIONS, and banner display
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
**Motivation**
Buzz on Android never shows an OS notification. A member who backgrounds the app learns about a DM or an @mention only when they reopen it. #4402 reports the same gap from the user side: the app stops receiving messages in the background and needs a restart.
The iOS half is already in flight — PR #1924 adds `.alert/.badge/.sound` authorization, `registerForRemoteNotifications()`, and a `NotificationService` extension. Android has no equivalent, and no client-side Android issue is filed for it.
Confirmed by reading `main` on 2026-08-17:
- `mobile/pubspec.yaml` — no `firebase_messaging` and no `flutter_local_notifications`. Android has no push path and no local-notification path.
- `mobile/android/app/src/main/AndroidManifest.xml` — no `POST_NOTIFICATIONS` permission (required since Android 13), no FCM service, no receiver.
- Nothing under `mobile/lib` creates a `kind:30350` push lease.
- `crates/buzz-push-gateway/src/` ships `apns.rs` with no FCM transport. That server half is #3229.
**Proposed solution**
Android client work, sized to land after #3229:
1. Add an FCM dependency and register the device token at startup.
2. Publish a NIP-PL `kind:30350` push lease per installation, mirroring the iOS path in PR #1924.
3. Declare `POST_NOTIFICATIONS` in the manifest and request it at runtime on Android 13+.
4. Create a notification channel and display a banner on wake for DMs, @mentions, and thread replies the user is in — matching the slot rules already used by desktop in `desktop/src/features/notifications/`.
5. NIP-PL carries a wake signal only, so banner text must come from the events fetched after reconnect, never from the push payload.
**Alternatives considered**
- **UnifiedPush instead of FCM.** NIP-PL names it as an optional profile. It removes the Google dependency and suits self-hosted relays (#5206), but it requires the user to install a distributor app, so it is a poor default.
- **A foreground service holding the WebSocket open.** No Google dependency, but Android kills it under memory pressure, it drains battery, and it forces a permanent status-bar notification.
- **Local notifications only, no push.** The app would show banners while it runs and nothing while backgrounded. That is half the value, but it is a smaller first step and it does not depend on #3229.
**Additional context**
Closest existing issue: **#4657** — "Mobile client never registers for push". It covers the transport gap for both platforms. This issue is the Android client half plus the display layer, which #4657 does not specify.
Related:
- #3229 — Android FCM transport profile in the push gateway (server half; blocks steps 1 and 2).
- PR #1924 — NIP-PL iOS push foundation. The Android work should mirror its `push_bridge.dart` / `push_models.dart` structure.
- #4402 — Android: app stops receiving new messages in the background (the user-visible symptom).
- #5206 — self-hosted relays cannot reach the default APNs gateway; the same constraint will apply to FCM.
- Spec: `docs/nips/NIP-PL.md` (`status: draft`).
Contributor guide
Assessment
This issue has not been assessed yet.