Document the Android reader, pause sharing and dev builds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
This commit is contained in:
@@ -57,7 +57,8 @@ npm run mobile # starts Metro; scan the QR code with a dev build or Expo
|
|||||||
```
|
```
|
||||||
|
|
||||||
- The app talks to the API on the same host as Metro (your LAN IP, port 4000), so phone and computer must be on the same network. Set `EXPO_PUBLIC_API_URL` for other environments.
|
- The app talks to the API on the same host as Metro (your LAN IP, port 4000), so phone and computer must be on the same network. Set `EXPO_PUBLIC_API_URL` for other environments.
|
||||||
- Native tabs and some native modules need a **development build** for full fidelity: `npx expo run:ios` / `npx expo run:android` locally, or `npx eas-cli@latest build --profile development`.
|
- The app includes custom native code (the Android now-playing reader), so it needs a **development build**, not Expo Go: `npm run android -w @musicshare/mobile` (needs the Android SDK and JDK 17) or `npx eas-cli@latest build --profile development`. In Expo Go the reader is simply hidden.
|
||||||
|
- `android/` and `ios/` are generated by `expo prebuild` and gitignored; configure native settings in `app.json` and `modules/`.
|
||||||
- **Spotify/Plex sign-in from a phone:** the OAuth callback goes to `API_PUBLIC_URL`, which defaults to `127.0.0.1` — that's the phone itself. Expose the API with a tunnel (`cloudflared tunnel --url http://localhost:4000`) and set `API_PUBLIC_URL` to the https URL (and add it as a redirect URI in the Spotify dashboard).
|
- **Spotify/Plex sign-in from a phone:** the OAuth callback goes to `API_PUBLIC_URL`, which defaults to `127.0.0.1` — that's the phone itself. Expose the API with a tunnel (`cloudflared tunnel --url http://localhost:4000`) and set `API_PUBLIC_URL` to the https URL (and add it as a redirect URI in the Spotify dashboard).
|
||||||
- Bundle IDs are `tech.chrisedwards.musicshare` (in `apps/mobile/app.json`); change before your first store build, they're permanent after.
|
- Bundle IDs are `tech.chrisedwards.musicshare` (in `apps/mobile/app.json`); change before your first store build, they're permanent after.
|
||||||
|
|
||||||
@@ -115,10 +116,12 @@ Links are https universal links, so on phones they open the native app. Missing
|
|||||||
| Jellyfin | ✅ | Server URL + login; only the issued access token is stored and it's revoked on disconnect. Optional Webhook-plugin URL for instant updates. |
|
| Jellyfin | ✅ | Server URL + login; only the issued access token is stored and it's revoked on disconnect. Optional Webhook-plugin URL for instant updates. |
|
||||||
| Apple Music | ⏳ | No server-side now-playing API. MusicKit gives recently-played only; the iOS app can read the device player while open. |
|
| Apple Music | ⏳ | No server-side now-playing API. MusicKit gives recently-played only; the iOS app can read the device player while open. |
|
||||||
| YouTube Music | via Last.fm | No official history API |
|
| YouTube Music | via Last.fm | No official history API |
|
||||||
| Android (any app) | ⏳ | The mobile app reads the system media session (`NotificationListenerService`) |
|
| Android (any music app) | ✅ | One toggle in the app. `modules/now-playing-reader` listens to system media sessions (via notification access, never reading notification contents), filters to known music apps, and reports changes plus a 4-minute heartbeat through WorkManager with a per-phone revocable token. Testing with apps outside the allowlist: `EXPO_PUBLIC_EXTRA_MEDIA_APPS=com.android.chrome` (dev only). |
|
||||||
|
|
||||||
## SaaS readiness
|
## SaaS readiness
|
||||||
|
|
||||||
|
- **Pause sharing:** `PUT /me/sharing` pauses for 1h, 8h or indefinitely. While paused, connections aren't polled, phone reports are dropped, and nothing is added to history.
|
||||||
|
- **Google Play:** notification access needs the in-app disclosure (`share-setup` screen) and a matching Data safety entry (listening activity, shared with friends).
|
||||||
- **Pinned friends:** followers can pin friends to the top of their feed (`PUT/DELETE /users/:username/pin`); the limit comes from `maxPinnedFriends` in the plan.
|
- **Pinned friends:** followers can pin friends to the top of their feed (`PUT/DELETE /users/:username/pin`); the limit comes from `maxPinnedFriends` in the plan.
|
||||||
- **Plans:** `users.plan` plus `PLAN_ENTITLEMENTS` in `packages/shared/src/plans.ts` are the single place feature gates live. The API enforces them (e.g. connection limits return `402`), and `/me` returns them so clients can show upsells.
|
- **Plans:** `users.plan` plus `PLAN_ENTITLEMENTS` in `packages/shared/src/plans.ts` are the single place feature gates live. The API enforces them (e.g. connection limits return `402`), and `/me` returns them so clients can show upsells.
|
||||||
- **Billing (next):** RevenueCat is recommended. It unifies App Store, Play Store and Stripe (web) subscriptions, and a webhook sets `plan`/`plan_expires_at`. App Store and Play rules require in-app purchase for digital features bought in-app.
|
- **Billing (next):** RevenueCat is recommended. It unifies App Store, Play Store and Stripe (web) subscriptions, and a webhook sets `plan`/`plan_expires_at`. App Store and Play rules require in-app purchase for digital features bought in-app.
|
||||||
|
|||||||
Reference in New Issue
Block a user