SkateSpots/packages/skatespots-background/README.md
SkateSpots 3ad214683a feat(android): native background poller plugin (no Google) - Cordn pattern
packages/skatespots-background: a local Capacitor Android plugin that polls our
own push-service /pending and raises local notifications. Modes: off / standard
(WorkManager ~15 min) / fast (foreground service ~5 min). Kotlin +
AndroidManifest (POST_NOTIFICATIONS, FOREGROUND_SERVICE_DATA_SYNC, WAKE_LOCK,
battery-exemption) + Gradle module. Client: useBackgroundDelivery (registers a
poll token via NIP-98, seeds the plugin) + a Background delivery (Android)
control in NotificationSettingsCard. The app registers by NAME, not by importing
the package, so the web bundle is unaffected. UNVERIFIED - needs cap sync + a
device.
2026-10-01 19:51:56 +07:00

49 lines
2.5 KiB
Markdown

# skatespots-background
A **local Capacitor Android plugin** that gives the APK closed-app notifications
**without Google services** — the [Cordn](https://github.com/Cordn-msg/cordn-web)
pattern, simplified (our payloads are already content-free, so there is **no Rust
and no decryption** here).
It polls our own `push-service` (`GET /pending?token&since` → `{seq, at, changed}`)
and, when the cursor advances, raises a **local notification**.
## Modes
| Mode | Mechanism | Cadence | Notes |
| --- | --- | --- | --- |
| `off` | — | — | default |
| `standard` | **WorkManager** | ~15 min (OS minimum) | best-effort — Doze/OEM battery managers may defer it |
| `fast` | **foreground service** | ~5 min | near-live; shows a **sticky notification** + battery |
## Files
- `src/index.ts` — TS↔Kotlin bridge (the app registers the plugin **by name**).
- `android/src/main/AndroidManifest.xml` — permissions (`POST_NOTIFICATIONS`,
`FOREGROUND_SERVICE[_DATA_SYNC]`, `WAKE_LOCK`, `RECEIVE_BOOT_COMPLETED`,
`REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`) + the service.
- `android/src/main/java/org/skatespots/background/`:
- `SkateSpotsBackgroundPlugin.kt` — the `@CapacitorPlugin` (`configure`, `seed`,
`postNotification`, `clearNotifications`, `consumePendingUrl`,
`isBatteryExempted`, `requestBatteryExemption`).
- `PollWorker.kt` (WorkManager), `PollService.kt` (foreground), `Poller.kt`,
`Notifier.kt`, `PollPrefs.kt`.
- `android/build.gradle` — the plugin Gradle module.
## Wiring
1. The root `package.json` depends on it: `"skatespots-background": "file:packages/skatespots-background"`.
2. `npm run android:init` / `android:sync` (which run `npx cap sync android`) pick
it up and add the Android module.
3. The client enables it from **Settings → Notifications → Background delivery
(Android)** via `src/hooks/useBackgroundDelivery.ts`.
## ⚠️ Caveats
- **Android-only** and **cannot be verified in CI** — needs a device.
- `standard` is **not** a guarantee (Doze/OEM). `fast` needs the sticky
notification and the user must start it while the app is foreground.
- `build.gradle` mirrors the Capacitor plugin template; align its Gradle/Kotlin
versions with the app's Capacitor major if a build complains.
- The small icon uses `applicationInfo.icon`; swap for a dedicated monochrome
status icon if the app's launcher icon renders poorly in the shade.
## Server contract
`push-service` (see its README): `POST /native/poll/register` (NIP-98 proof →
poll token), `GET /pending?token&since`, `POST /native/poll/unregister`.