Skip to Content
SoftwareApplicationsMagazinApp IntegrationThe native app's headless audio player

The native app’s headless audio player

When playing audio in the web audio-player, the native app is actually playing the audio, while the web-view keeps on rendering the UI. In order to the web-views UI in sync with the native app’s audio player, the native app sends frequent updates to the web-view about the current playing state.

In addition, when interacting with the lock-screen UI of the phone where the native-app is playing the audio, the native-app forwords these interactions to the web-view, so that the web-view can update its UI accordingly.

Events sent from the web-view to the native app

The web-view uses postMessage to send events to the native app. The function notifyApp is used to send the events.

Example:

notifyApp(AudioEvent.SETUP_TRACK, { // Adapted, not sent as-is — see below. item: toNativeAppTrack(item), autoPlay, initialTime, playbackRate, coverImage: audioCoverUrl(item.document?.image, 1024), })

The item payload is a frozen shape. The web player’s own queue items carry Sanity content ({ _id, title, slug, audioSourceMp3, … }), but the app reads a track’s url from document.meta.audioSource.mp3 — the shape the old AudioQueueItem GraphQL fragment delivered. App versions already installed can never be updated, so a web release cannot change what they receive. helpers/nativeAppTrack.ts translates between the two at this boundary, and is the only place that knows about the old shape. The same applies to the play-audio payload in AudioProvider, used by app versions below v2.2.0.

Events

Event nameDescription
audio:playThe user pressed the play button
audio:pauseThe user pressed the pause button
audio:seekThe user seeked to a new position in the audio
audio:stopThe user has closed the audio-player, the playback should be stopped
audio:fowardSkip ahead x seconds
audio:backwardSkip back x seconds
audio:playbackRateChange the playback rate
audio:setupTrackPrepare the audio player for playing the given track

Events received in the webview, sent from the native-app

In order to receive events from the native app, the react-hook useNativeAppEvent is used.

Example:

useNativeAppEvent<string>( AudioEvent.QUEUE_ADVANCE, async (itemId) => { const isHeadOfQueue = audioQueue && audioQueue.length > 0 && audioQueue[0].id === itemId const isActiveItem = activePlayerItem && activePlayerItem.id === itemId if (isHeadOfQueue || isActiveItem) { // HasOptedOutFromAutoPlay might be null, which should then result in 'true' await onQueueAdvance(isAutoPlayEnabled) } }, [initialized, activePlayerItem, isAutoPlayEnabled], )

Most of the communication received by the web-view is handled in the AudioPlayerController  component.

Events

Event nameDescription
audio:syncSent every frequently, contains the current playing state used to keep the web-view in sync with the native app
audio:queueAdvanceThe native app reports that the playback has finished and a next track should be sent if in the queue
audio:errorThe native app reports an error
audio:trackThe native app reports the current track
audio:minimizePlayerThe native app reports that the audio player should be minimized

Example message flow

References

Last updated on