Skip to content
shipped2026·mobile-appPINNED

Polskie Radio — national broadcaster app

Mobile engineer (playback + native), tech owner

React NativeExpo SDK 55TypeScriptKotlinSwiftExpo ModulesTanStack QueryMMKVUnistyles 3CarPlayAndroid AutoChromecastFirebase AnalyticsGemiusSentry

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

100%

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 %.