PROBLEMProblem
Poland's national public broadcaster needed a single mobile app covering live radio (4 national + 17 regional stations), on-demand podcasts, offline downloads, and handoff to car head units and Chromecast. The previous stack was fragmented across platforms, and playback state drifted between the UI, lock screen, CarPlay/Android Auto and cast targets.
The app had to keep playing reliably through network drops, app backgrounding, OS process death, and transitions between local audio, cast, and car surfaces — without the UI and the native media session ever disagreeing about what is playing.
APPROACHApproach
Built on React Native + Expo SDK 55 with a Clean Architecture split (Domain → Application → Infrastructure → Presentation) and TypeScript strict mode end-to-end.
- A command-driven playback FSM in TypeScript is the single source of truth. All mutations go through a serialized
CommandBus— UI never writes to the store directly. - An event bus decouples side effects (analytics, MMKV persistence, media session, cast, schedule metadata, audio focus, buffering watchdog) into ~15 independent bridges.
- Custom Expo native modules (
expo-media-session,expo-cast) in Swift + Kotlin own lock screen, CarPlay, Android Auto, and Chromecast integration; updates are batched (iOS: 30 ms coalesce + 300 ms safety; Android: 300 ms debounce) to keep the JS store and native session in sync. - Offline podcasts use a separate download FSM with a foreground service on Android and background URLSession on iOS, surviving process death via MMKV-persisted state.
- TanStack Query + a concurrency-limited
ScheduleDataService(max 3) handle REST, polling, and cache.
ARCHITECTUREArchitecture
Two cooperating state machines — one for playback (idle → buffering → playing → paused → error), one for downloads (queued → downloading → paused → complete → failed) — both persisted to MMKV. Bridges subscribe to the event bus; adapters implement Domain ports so audio, video, and cast targets are interchangeable behind one facade.
RESULTResult
Shipped to the App Store and Google Play as the official Polskie Radio app. Playback stays consistent across phone, CarPlay, Android Auto, and Chromecast; downloads survive app kill and OS process death. Replacing per-platform glue with a shared FSM resulted in significantly less playback code versus the previous per-platform codebases, and analytics (GA4 + Gemius) now flow from one event bus instead of three. Test coverage on playback subsystems: 89–95 %.