Zum Hauptinhalt springen

Wie man Audio im Hintergrund in Capacitor abspielt

Hören Sie Musik im Hintergrund in Capacitor: iOS-Hintergrundmodus für Audio, Android-Vordergrunddienst, Steuerung der Bildschirmverriegelung, Wiedergabelisten und Unterbrechungen.

Artikelcredits

Martin Donadieu

Autor

Valeria

Rezensent

Jordan

Redakteur

Wie man Audio im Hintergrund in Capacitor abspielt

Um Hintergrundmusik in Capacitor abzuspielen, benötigen Sie zwei native Komponenten: die audio Hintergrundmodus auf iOS, und ein mediaPlayback Fügen Sie eine Bildschirm-Steuerung über eine Medien-Sitzung hinzu und Ihre Musik-, Podcast- oder Meditation-App bleibt abspielen, wenn der Benutzer das Telefon sperren oder zwischen Apps wechselt. Diese Anleitung zeigt beide Konfigurationen in Capacitor 8. @capgo/capacitor-native-audio für native Wiedergabe und @capgo/capacitor-media-session für Systemsteuerungen.

Warum hört Audio im Hintergrund auf

Ein Capacitor-App ist eine native Shell um einen WebView herum, folgt also jeder Plattform Lifecycle-Regeln:

iOS Android
Was passiert im Hintergrund Die App wird innerhalb von Sekunden suspendiert Die Activity wird pausiert, WebView-Timer werden gedrosselt, der Prozess kann beendet werden
Was hält das Audio am Leben UIBackgroundModes enthält audio, Audio-Sitzungskategorie playback Ein Hintergrunddienst des Typs mediaPlayback mit einer Benachrichtigung
Stummschalter playback Kategorie ignoriert es. ambient respektiert es Kein Äquivalent
Steuerung auf dem Bildschirm zum Sperrbildschirm MPNowPlayingInfoCenter und MPRemoteCommandCenter MediaSession mit einer Medienbenachrichtigung
Speicherregel Muss akustisches Inhalt spielen, den der Benutzer erwartet (Richtlinie 2.5.4) Diensttyp muss dem tatsächlichen Gebrauch entsprechen, wie er im Google Play Console deklariert ist.

Keine Plattform bietet Hintergrundmusik standardmäßig an, und das Beheben nur einer Seite ist der häufigste Grund für die Fehlermeldungen "funktioniert auf iPhone, hält auf Android an".

Wählen Sie Ihre Wiedergabeansatz

Es gibt zwei gute Architekturen:

  1. Nativwiedergabe mit @capgo/capacitor-native-audio: Die Audio-Decoder werden von AVFoundation auf iOS und Media3 ExoPlayer auf Android verwendet. Ideal für Musikplayer, Hörbücher, Meditation-Apps und alles, wo die WebView möglicherweise gedrosselt wird. Es unterstützt lokale Dateien, Remote-URLs, HLS-Streams, Fades, Rate und Now Playing-Metadaten.
  2. HTML <audio> plus @capgo/capacitor-media-session: Halten Sie Ihre bestehende Web-Player und lassen Sie den Plugin die Metadaten und Steuerungen an die OS weitergeben. Auf Android läuft es auch den Vordergrunddienst während der Sitzung ab. Ideal, wenn Sie bereits einen Web-Player haben oder einen einzigen code Pfad für Web und Nativ benötigen.
@capgo/capacitor-native-audio <audio> + Medien-Sitzung
Wiedergabe-Engine Nativ WebView
Webunterstützung Ja (HTML-Audio-Fallback) Ja
Benutzerinformationen auf dem Bildschirm showNotification + notificationMetadata setMetadata
Android-Vordergrunddienst Sie starten es Plugin startet es während des Abspielens oder Pausen
Remote-Control-Ereignisse playbackState Hörer setActionHandler
Genauere, niedrigschwellige SFX Ja Limitiert

Konfigurieren Sie iOS für Hintergrundaudio

Öffnen ios/App/App/Info.plist und fügen Sie den Hintergrundmodus hinzu. Sie können auch das Kontrollkästchen "Audio, AirPlay und Bild in Bild" unter Signieren und Fähigkeiten, Hintergrundmodi in Xcode anwählen, was dieselbe Schlüssel schreibt:

<key>UIBackgroundModes</key>
<array>
  <string>audio</string>
</array>

Die Audio-Sitzungskategorie spielt auch eine Rolle. @capgo/capacitor-native-audio setzt sie für Sie fest: mit showNotification: true Es verwendet .playback mit der Standardmodus, der andere Apps unterbricht (Spotify wird angehalten) und Ihre App zum Abspielen von Musik macht. Mit showNotification: false Es verwendet .playback mit mixWithOthers, der für Soundeffekte geeignet ist, aber keine Steuerung auf dem Bildschirm anzeigt. Wählen Sie eine pro App, nicht pro Track.

Wenn Sie durch <audio>spielen, aktiviert WebKit die Wiedergabe-Sitzung, wenn die Medien beginnen. Stellen Sie sicher, dass die Wiedergabe von einem Benutzerinteraktionsereignis aus zum ersten Mal gestartet wird, oder iOS blockiert es.

Mit Xcode 26 oder höher bauen, bevor Sie es in App Store Connect hochladen, was seit April 2026 erforderlich ist. Capgo Erstellen Wenn Sie auf Windows oder Linux arbeiten, können Sie das im Cloud tun.

Konfigurieren Sie Android für Hintergrundaudio

Fügen Sie die Berechtigungen hinzu android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

FOREGROUND_SERVICE_MEDIA_PLAYBACK ist für Apps, die sich auf Android 14 (API 34) oder höher richten, und Capacitor 8 API 36, erforderlich. Ohne es wird der Dienststart einen SecurityExceptionwürfeln. Wenn Sie veröffentlichen, fragt die Play Console Sie nach, die Vordergrunddiensttyp zu deklarieren und zu rechtfertigen. "Media playback, das der Benutzer gestartet hat", ist der akzeptierte Gebrauch.

POST_NOTIFICATIONS ist eine Laufzeitberechtigung auf Android 13+. Medien-Sitzungsbenachrichtigungen sind von der Benachrichtigungs-Berechtigung befreit und zeigen sich immer noch im Schatten, aber jede andere Benachrichtigung, die Ihr Dienst postet, benötigt sie.

Android 12+ blockiert den Start eines Vordergrunddienstes, während die App im Hintergrund ist. Starten Sie ihn, wenn der Benutzer auf "Play" klickt, während Ihre Aktivität sichtbar ist.

Option A: Lassen Sie den Mediensitzungs-Plugin den Dienst laufen

@capgo/capacitor-media-session erklärt einen mediaPlayback Dienst in seinem eigenen Manifest und startet ihn, wenn Sie den Abspielzustand auf setzen playing oder paused. Es stoppt, wenn der Zustand zurückgeht zu none und die App ist im Hintergrund. Wenn Sie möchten, dass der Dienst für die gesamte App-Sitzung läuft, setzen Sie die Plugin-Konfiguration in capacitor.config.ts:

plugins: {
  MediaSession: {
    foregroundService: 'always',
  },
},

The default, starting only during playback, is what most apps want.

Option B: Starten Sie Ihren eigenen Vordergrunddienst

@capgo/capacitor-native-audio erledigt die Wiedergabe, den Fokus und die Medienbenachrichtigung, aber es erstellt keinen Vordergrunddienst. Wenn Sie es ohne den Medien-Sitzungs-Plugin verwenden, fügen Sie ein kleines Service und einen lokalen Plugin zu Ihrem Android-Projekt hinzu.

android/app/src/main/java/com/example/app/PlaybackService.java:

package com.example.app;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.IBinder;
import androidx.core.app.NotificationCompat;

public class PlaybackService extends Service {
    private static final String CHANNEL_ID = "playback";

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                CHANNEL_ID, "Playback", NotificationManager.IMPORTANCE_LOW);
            getSystemService(NotificationManager.class).createNotificationChannel(channel);
        }
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Playing audio")
            .setSmallIcon(R.mipmap.ic_launcher)
            .setOngoing(true)
            .build();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            startForeground(1, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK);
        } else {
            startForeground(1, notification);
        }
        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

PlaybackServicePlugin.java im gleichen Paket:

package com.example.app;

import android.content.Intent;
import androidx.core.content.ContextCompat;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;

@CapacitorPlugin(name = "PlaybackService")
public class PlaybackServicePlugin extends Plugin {
    @PluginMethod
    public void start(PluginCall call) {
        ContextCompat.startForegroundService(getContext(), new Intent(getContext(), PlaybackService.class));
        call.resolve();
    }

    @PluginMethod
    public void stop(PluginCall call) {
        getContext().stopService(new Intent(getContext(), PlaybackService.class));
        call.resolve();
    }
}

Registrieren Sie es in MainActivity.java vorher super.onCreate, und deklarieren Sie den Dienst im Manifest:

public class MainActivity extends BridgeActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        registerPlugin(PlaybackServicePlugin.class);
        super.onCreate(savedInstanceState);
    }
}
<service
    android:name=".PlaybackService"
    android:exported="false"
    android:foregroundServiceType="mediaPlayback" />

Von TypeScript:

import { Capacitor, registerPlugin } from '@capacitor/core';

interface PlaybackServicePlugin {
  start(): Promise<void>;
  stop(): Promise<void>;
}

export const PlaybackService = registerPlugin<PlaybackServicePlugin>('PlaybackService');

export const isAndroid = Capacitor.getPlatform() === 'android';

Play audio natively mit @capgo/capacitor-native-audio

bun add @capgo/capacitor-native-audio
bunx cap sync

Konfigurieren Sie einmalig bei Start, dann laden und abspielen:

import { NativeAudio } from '@capgo/capacitor-native-audio';
import { PlaybackService, isAndroid } from './playback-service';

await NativeAudio.configure({
  focus: true,               // request audio focus, pause others
  background: true,          // keep playing in the background
  backgroundPlayback: true,  // Android: skip auto pause on background
  showNotification: true,    // lock screen and notification controls
});

export async function playEpisode(id: string, url: string, title: string, artwork: string) {
  await NativeAudio.preload({
    assetId: id,
    assetPath: url,
    isUrl: true,
    notificationMetadata: {
      title,
      artist: 'My Podcast',
      artworkUrl: artwork,
    },
  });

  if (isAndroid) await PlaybackService.start();
  await NativeAudio.play({ assetId: id });
}

export async function stopEpisode(id: string) {
  await NativeAudio.stop({ assetId: id });
  await NativeAudio.unload({ assetId: id });
  if (isAndroid) await PlaybackService.stop();
}

assetPath nimmt einen Pfad relativ zu Ihren Web-Ressourcen (audio/intro.mp3) an, einen file:// URL, einen https:// URL oder einen HLS- .m3u8 Stream. Für alles außer einem bundelten Asset setzen Sie isUrl: true. If your audio host requires auth, pass headers.

Bauen Sie eine Playlist, die von selbst fortschreitet:

Der complete ereignis wird ausgelöst, wenn ein Track endet, auch mit dem Bildschirm gesperrt, weil der native Player weiterläuft:

const queue = [
  { id: 'ep1', url: 'https://cdn.example.com/ep1.mp3', title: 'Episode 1' },
  { id: 'ep2', url: 'https://cdn.example.com/ep2.mp3', title: 'Episode 2' },
];
let index = 0;

await NativeAudio.addListener('complete', async ({ assetId }) => {
  await NativeAudio.unload({ assetId });
  index += 1;
  if (index < queue.length) {
    const next = queue[index];
    await NativeAudio.preload({
      assetId: next.id,
      assetPath: next.url,
      isUrl: true,
      notificationMetadata: { title: next.title, artist: 'My Podcast' },
    });
    await NativeAudio.play({ assetId: next.id });
  } else if (isAndroid) {
    await PlaybackService.stop();
  }
});

Halten Sie den Vordergrund-Dienst zwischen den Tracks laufend. Wenn Sie ihn nach einem Track beenden und versuchen, ihn wieder zu starten, während er im Hintergrund läuft, werfen Android 12+ ForegroundServiceStartNotAllowedException.

Halten Sie Ihre UI im Einklang mit dem Sperrbildschirm

Benutzer drücken die Pause-Taste auf dem Bildschirm, auf Kopfhörern oder in der Benachrichtigung. Hören Sie zu playbackState und behandeln Sie den nativen Player als Quelle der Wahrheit:

await NativeAudio.addListener('playbackState', (event) => {
  // event.state: 'playing' | 'paused' | 'stopped'
  // event.reason: 'play', 'pause', 'remotePlay', 'complete', ...
  store.setPlaying(event.isPlaying);
  if (event.currentTime !== undefined) store.setPosition(event.currentTime);
});

await NativeAudio.addListener('currentTime', ({ currentTime }) => {
  store.setPosition(currentTime); // every 100 ms while playing
});

Auch aktualisieren Sie den Zustand, wenn die App wieder in den Vordergrund kommt, mit isPlaying und getCurrentTimeda der WebView möglicherweise während der Ereignisemissionen angehalten wurde.

Verwenden Sie ein HTML-Audio-Element mit Medien-Sitzungssteuerungen

If you already have a web player, keep it and add the plugin:

bun add @capgo/capacitor-media-session
bunx cap sync
import { MediaSession } from '@capgo/capacitor-media-session';

const audio = new Audio();
audio.preload = 'auto';

export async function play(track: { url: string; title: string; artist: string; cover: string }) {
  audio.src = track.url;
  await audio.play();

  await MediaSession.setMetadata({
    title: track.title,
    artist: track.artist,
    artwork: [{ src: track.cover, sizes: '512x512', type: 'image/jpeg' }],
  });
  await MediaSession.setPlaybackState({ playbackState: 'playing' });
}

await MediaSession.setActionHandler({ action: 'play' }, async () => {
  await audio.play();
  await MediaSession.setPlaybackState({ playbackState: 'playing' });
});
await MediaSession.setActionHandler({ action: 'pause' }, async () => {
  audio.pause();
  await MediaSession.setPlaybackState({ playbackState: 'paused' });
});
await MediaSession.setActionHandler({ action: 'seekto' }, (details) => {
  if (details.seekTime != null) audio.currentTime = details.seekTime;
});
await MediaSession.setActionHandler({ action: 'nexttrack' }, () => playNext());

audio.addEventListener('timeupdate', () => {
  MediaSession.setPositionState({
    duration: audio.duration || 0,
    position: audio.currentTime,
    playbackRate: audio.playbackRate,
  });
});

Aufrufen Sie setPositionState Page/area: Capgo Marketing Website. Rolle: Kurze UI-Bezeichnung oder Navigationselement. Gesehen in: Seite trust.astro. Nachrichtsschlüssel `and` (Und). timeupdate Ereignisse verbrauchen die Batterie.

ereignet sich auf Kosten der Akkulaufzeit.

Phone calls, Siri, alarms and other apps interrupt playback. Native audio pauses on interruption and, on iOS, resumes when the system says it should. Two more cases need your attention:

  • Kopfhörer abgezogen: Benutzer erwarten, dass die Wiedergabe anhält. Auf Android registrieren Sie einen Empfänger für AudioManager.ACTION_AUDIO_BECOMING_NOISY im Dienst, wenn Ihr Spieler die Wiedergabe nicht bereits anhält. Auf iOS hören Sie nach Routenänderungen mit @capgo/capacitor-audio-session:
import { AudioSession, RouteChangeReasons } from '@capgo/capacitor-audio-session';

await AudioSession.addListener('routeChanged', (reason) => {
  if (reason === RouteChangeReasons.OLD_DEVICE_UNAVAILABLE) {
    pausePlayback();
  }
});

await AudioSession.addListener('interruption', (type) => {
  // 'began' or 'ended'
});
  • Ducking vs. Anhalten: Navigationsempfehlungen drücken Ihre Audio ab. Apps mit gesprochenem Wort sollten anhalten, da gedämpfte Sprache schwer zu folgen ist.

Testen Sie Hintergrundwiedergabe

Simulatoren liegen über Hintergrundverhalten falsch. Testen Sie auf echten Geräten:

  1. Starte die Wiedergabe, sperre das Gerät, warte zwei Minuten. Der Audio muss weiterlaufen.
  2. Use the lock screen play, pause, next and seek controls, then unlock and check your UI matches.
  3. Play, switch to another app that plays audio, then come back.
  4. Starten Sie einen Anruf oder FaceTime-Audio während der Wiedergabe.
  5. Auf Android aktivieren Sie die Energieeinsparung und testen Sie auf einem Samsung- oder Xiaomi-Gerät. Einige OEMs töten Hintergrundanwendungen aggressiv. Ein Vordergrunddienst überlebt, eine einfache Hintergrundaufgabe nicht.
  6. Auf Android 13+, verweigern Sie die Benachrichtigungsrechte und bestätigen Sie, dass das Abspielen weiterhin funktioniert.
  7. Ein Wiedergabeliste läuft durch mehrere Tracks mit dem Bildschirm ausgeschaltet.

adb shell dumpsys activity services | grep -A3 PlaybackService zeigt an, ob Ihr Dienst im Vordergrund läuft.

Troubleshooting

Audio hört nach etwa 30 Sekunden auf, wenn man iOS verwendet.: UIBackgroundModes mangelt audiooder die Sitzungskategorie ist ambient oder soloAmbient. Check Info.plist im der gebauten App, nicht nur in Ihrem Quellcode.

Der Audio spielt nur wenige Minuten auf Android.: kein Vordergrunddienst oder der Dienst ist nicht vom Typ mediaPlayback. Überprüfen Sie auch die OEM-Einstellungen für die Akkubatterie.

SecurityException: Starting FGS with type mediaPlayback ... requires permissions: hinzufügen FOREGROUND_SERVICE_MEDIA_PLAYBACK.

ForegroundServiceStartNotAllowedException: Sie haben den Dienst während der App im Hintergrund gestartet. Starten Sie ihn beim Anstoss des Benutzers.

Keine Steuerung auf dem iOS-Schutzschirm: showNotification ist falsch (mixbare Sitzung), oder wurde kein Metadaten-Set gesetzt. Nur die App, die eine nicht-mixbare Sitzung besitzt, wird zum Now Playing-App.

Zwei Benachrichtigungen auf Android: Sie haben showNotification in native Audio und auch Ihre eigene Dienstbenachrichtigung gepostet. Halten Sie die Dienstbenachrichtigung minimal, oder verwenden Sie nur den Dienst des Media-Session-Plugins.

Andere Musik-Apps spielen weiterhin über Ihre: Sie haben eine mixbare Sitzung konfiguriert. Setzen Sie focus: true und showNotification: true.

Schiffen Sie Änderungen am Player schneller

Die Logik, die Benutzeroberfläche, die Metadaten und die Analysen Ihres Spielers leben in JavaScript. Sobald die native Konfiguration oben in einem Store-Build ist, Capgo Live-Updates lassen Sie Sie Fixes an das code pushen, ohne ein neues Review-Zyklus zu benötigen. Die native Audio-Dokumentation und Die Medien-Sitzungs-Dokumentation umfasst alle Optionen, und wenn Ihr App auch Audio aufzeichnet, sehen Sie sich die Capacitor Audio-Recorder-Plugin.

Live-Updates für Capacitor-Apps

Wenn ein Web-Schicht-Bug live ist, liefern Sie die Reparatur über Capgo anstatt Tage zu warten, bis die App-Store-Zulassung vorliegt. Die Benutzer erhalten die Aktualisierung im Hintergrund, während native Änderungen im normalen Review-Prozess bleiben.

Neueste aus unserem Blog

Capgo bietet Ihnen die besten Einblicke, die Sie benötigen, um eine wirklich professionelle Mobilanwendung zu erstellen.