Share what's playing in any Android music app
A local Expo module listens to system media sessions (the only way Android exposes other apps' playback, gated by notification access; we never read notifications). It filters to known music apps, debounces and deduplicates changes, sends a heartbeat while playing, and delivers reports through WorkManager so they survive the app being closed. - One-screen onboarding that doubles as Google Play's prominent disclosure, opening straight to the app's toggle in Android settings - Only media notifications are pre-ticked on that settings screen - Device registration is single-flight (several screens react to the same permission change) and self-heals if the server revokes a token - Sign-out revokes the phone's token; resuming sharing re-sends the current track immediately - Pause controls in Settings and on the feed - Fix invisible tab icons and labels on Android - Keep Metro out of build output so it doesn't exhaust file watchers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
export type NativePlayback = {
|
||||
app: string;
|
||||
appName: string | null;
|
||||
state: 'playing' | 'paused' | 'stopped';
|
||||
title: string | null;
|
||||
artist: string | null;
|
||||
album: string | null;
|
||||
durationMs: number | null;
|
||||
};
|
||||
|
||||
export type NowPlayingReaderModuleEvents = {
|
||||
onPlaybackChange: (event: { playback: NativePlayback | null }) => void;
|
||||
onStatusChange: (event: { status: 'unauthorized' }) => void;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import { NativeModule, requireOptionalNativeModule } from 'expo';
|
||||
|
||||
import type { NativePlayback, NowPlayingReaderModuleEvents } from './NowPlayingReader.types';
|
||||
|
||||
declare class NowPlayingReaderModule extends NativeModule<NowPlayingReaderModuleEvents> {
|
||||
isPermissionGranted(): boolean;
|
||||
openPermissionSettings(): void;
|
||||
configure(apiUrl: string, deviceToken: string, allowedPackages: string[]): void;
|
||||
clear(): void;
|
||||
resend(): void;
|
||||
needsReregistration(): boolean;
|
||||
getCurrent(): NativePlayback | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Android only. null on iOS, web, and in Expo Go (no custom native code there),
|
||||
* so callers must feature-check.
|
||||
*/
|
||||
export default requireOptionalNativeModule<NowPlayingReaderModule>('NowPlayingReader');
|
||||
Reference in New Issue
Block a user