Production Quickstart (Capacitor)
Use this guide to bootstrap a realistic first production integration for @ddgutierrezc/legato-capacitor.
Prerequisites
Section titled “Prerequisites”- Capacitor app with native targets configured (
iosand/orandroid) @ddgutierrezc/legato-capacitorand@ddgutierrezc/legato-contractinstalled- Successful native sync (
npx cap sync)
Step 1: Install and align versions
Section titled “Step 1: Install and align versions”npm install @ddgutierrezc/legato-capacitor @ddgutierrezc/legato-contractnpx cap syncThen confirm dependency alignment with Compatibility.
Step 2: Initialize playback and media session early
Section titled “Step 2: Initialize playback and media session early”import { audioPlayer, mediaSession } from '@ddgutierrezc/legato-capacitor';
export async function initializeLegato() { await audioPlayer.setup(); await mediaSession.setup();}Call initialization from your app bootstrap before exposing playback UI interactions.
Step 3: Register essential listeners
Section titled “Step 3: Register essential listeners”import { audioPlayer, onPlaybackStateChanged, onPlaybackProgress, onPlaybackError, onRemotePlay, onRemotePause,} from '@ddgutierrezc/legato-capacitor';
export async function registerLegatoListeners() { const handles = await Promise.all([ onPlaybackStateChanged(({ state }) => { console.log('[playback-state]', state); }), onPlaybackProgress(({ position, duration }) => { console.log('[playback-progress]', { position, duration }); }), onPlaybackError(({ error }) => { console.error('[playback-error]', error.code, error.message, error.details); }), onRemotePlay(async () => { await audioPlayer.play(); }), onRemotePause(async () => { await audioPlayer.pause(); }), ]);
return async () => { await Promise.all(handles.map((h) => h.remove())); };}Step 4: Add a realistic queue and start playback
Section titled “Step 4: Add a realistic queue and start playback”import { audioPlayer } from '@ddgutierrezc/legato-capacitor';
export async function startDemoPlayback() { const snapshotAfterAdd = await audioPlayer.add({ tracks: [ { id: 'episode-001', url: 'https://cdn.example.com/audio/episode-001.mp3', title: 'Episode 1', artist: 'Legato Demo', }, { id: 'episode-002', url: 'https://cdn.example.com/audio/episode-002.mp3', title: 'Episode 2', artist: 'Legato Demo', }, ], startIndex: 0, });
console.log('Queue after add:', snapshotAfterAdd.queue); await audioPlayer.play();}Step 5: Capability checks before optional controls
Section titled “Step 5: Capability checks before optional controls”const caps = await audioPlayer.getCapabilities();
const canSeek = caps.supported.includes('seek');const canSkipNext = caps.supported.includes('skip-next');const canSkipPrevious = caps.supported.includes('skip-previous');Render or enable seek/skip controls based on these flags instead of static assumptions.
Step 6: Final validation checklist
Section titled “Step 6: Final validation checklist”setup()for both namespaces resolves without errors.add(...)returns a snapshot with expected queue items.play()transitions state through expected playback lifecycle events.playback-progressevents are observed while playing.- At least one remote event path (
remote-play/remote-pause) is validated on target device. - Error logs include
error.codeanderror.detailswhen failures occur.
Common mistakes
Section titled “Common mistakes”- Calling
play()beforesetup()or before adding tracks. - Assuming
audioPlayer.setup()initializes media-session listeners. - Branching logic on
error.messageinstead of stableerror.code. - Showing seek controls unconditionally without checking runtime capabilities.
- Registering listeners without removing them on teardown (duplicate handlers).
Optional native check
Section titled “Optional native check”If behavior is inconsistent at the native integration layer:
legato native doctorFor safe patch planning before file mutation:
legato native configure --dry-run