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.
49 lines
2.5 KiB
Markdown
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`.
|