block / block/buzz

feat(mobile/android): end-to-end push notifications — FCM registration, POST_NOTIFICATIONS, and banner display

Open
#6,092 0 comments 5 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.