背景で音を再生するには、Capacitorで必要なのは2つのネイティブな部分だけです。 audio To play audio in the background in __CAPGO_KEEP_0__, you need two native pieces: the background mode on iOS, and a foreground service on Android. Add lock screen controls through a media session, and your music, podcast or meditation app keeps playing when the user locks the phone or switches apps. This guide shows both setups on __CAPGO_KEEP_0__ 8, with mediaPlayback To play audio in the background in Capacitor, you need two native pieces: the background mode on iOS, and a foreground service on Android. Add lock screen controls through a media session, and your music, podcast or meditation app keeps playing when the user locks the phone or switches apps. This guide shows both setups on Capacitor 8, with @capgo/capacitor-native-audio native プレイバックと @capgo/capacitor-media-session システム制御のために
背景で音が止まる理由
A Capacitor アプリは、WebViewの周りにnativeシェルを構築しているため、各プラットフォームのライフサイクル規則に従います。
| iOS | Android | |
|---|---|---|
| 背景で何が起こるか | アプリは数秒以内に一時停止 | アクティビティは一時停止、WebViewのタイマーはスローダウン、プロセスは殺害される |
| 音を生き残らせるもの | UIBackgroundModes に含まれる audio, オーディオ セッション カテゴリ playback |
A service of type mediaPlayback バックグラウンドでオーディオを再生する |
| サイレントモード | playback category ignores it ambient 尊敬します |
バックグラウンドでオーディオを再生する方法 |
| ロック画面コントロール | MPNowPlayingInfoCenter and MPRemoteCommandCenter |
MediaSession メディアスタイルの通知で |
| アプリケーション設定 | ユーザーが期待する音を聞くことができるようにする必要があります (ガイドライン 2.5.4) | サービスタイプは実際の使用に一致する必要があります。Play Consoleで宣言されているものと同じです。 |
どのプラットフォームもデフォルトではバックグラウンド再生を提供していないため、iPhoneで動作し、Androidで停止するという「iPhoneで動作し、Androidで停止する」というバグレポートの最も一般的な原因は、1つの側面のみを修正することです。
再生方法を選択してください
2つの良いアーキテクチャがあります
- ネイティブ再生
@capgo/capacitor-native-audio:iOSではAVFoundationが、AndroidではMedia3 ExoPlayerが音声データをデコードします。音楽プレーヤー、オーディオブック、瞑想アプリ、ウェブビューが制限されている場合など、最適です。ローカルファイル、リモートURL、HLSストリーム、フェード、レート、そしてNow Playingメタデータをサポートしています。 - HTML
<audio>+@capgo/capacitor-media-session:既存のウェブプレーヤーを維持し、プラグインがOSにメタデータとコントロールを公開するようにします。Androidでは、セッションが再生されている間、前景サービスを実行します。既存のウェブプレーヤーがある場合や、ウェブとネイティブの両方で単一のcodeパスが必要な場合に最適です。
@capgo/capacitor-native-audio |
<audio> + |
|
|---|---|---|
| メディアセッション | 再生エンジン | ネイティブ |
| Webサポート | Yes (HTMLオーディオフォールバック) | Yes |
| コンテキスト: Capgoのソリューションマーケティングページ。役割: 短いUIラベルまたはナビゲーションアイテム。ページソリューション/ベータテスト。アストロ。メッセージキー`ソリューション_ベータテスト_比較_ネイティブ_tf` (ソリューション ベータテスト 比較ネイティブ Tf)。| コンテキスト: Capgoのソリューションマーケティングページ。役割: 短いUIラベルまたはナビゲーションアイテム。ページソリューション/PRプレビュー。アストロ。メッセージキー`ソリューション_プル_比較_ネイティブ_tf` (ソリューション プル 比較ネイティブ Tf)。 | showNotification + notificationMetadata |
setMetadata |
| ロック画面メタデータ | Androidフロントグラウンドサービス | 1つを開始します |
| プラグインは再生中または一時停止中のときに開始します | playbackState リモートコントロールイベント |
setActionHandler |
| リスナー | Yes | Limited |
iOSをバックグラウンドで再生する方法
開く ios/App/App/Info.plist 背景モードを追加してください。XcodeのSigning & Capabilities、Background Modesの「Audio, AirPlay, and Picture in Picture」をタップしてください。これは、同じキーを書き込むことと同じです:
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
オーディオセッションのカテゴリも重要です。 @capgo/capacitor-native-audio デフォルトモードを設定すると、他のアプリを中断し(Spotifyは停止)アプリを再生アプリにします。 showNotification: true it uses .playback iOSは、メディアが開始されたときに、WebKitが再生セッションを有効にします。最初のメディア再生はユーザー操作から始めてください。iOSはそれをブロックします。 showNotification: false it uses .playback オプション mixWithOthersオプション
オプション <audio>オプション
Xcode 26 またはそれ以上でビルドし、App Store Connectにアップロードする必要があります。これは2026年4月以降の要件です。 Capgo ビルド クラウドで行うことができます。WindowsまたはLinuxで作業している場合。
バックグラウンドオーディオのためのAndroidの設定
許可を追加する 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 Android 14 (API 34) またはそれ以上をターゲットにしているアプリでは、Capacitor 8 は API 36 をターゲットしています。許可を追加しないと、サービスを開始するとエラーが発生します。 SecurityExceptionforeground service を宣言し、その理由を説明するように、Play Consoleに問い合わせる必要があります。ユーザーが開始したメディアプレイバックは、許可された使用例です。
POST_NOTIFICATIONS Android 13 以降では、メディアセッションの通知は通知許可から除外され、シェードに表示されますが、サービスが投稿する他の通知には許可が必要です。
Android 12 以降では、バックグラウンドでアプリが実行されている場合に、foreground service を開始することはブロックされます。ユーザーが再生を開始したときに、サービスを開始するようにしてください。
オプション A: メディアセッション プラグインがサービスを実行するようにします
@capgo/capacitor-media-session declares a mediaPlayback サービスを宣言し、独自のマニフェストを設定します playing または paused状態がバックグラウンドに戻ったときに停止します。 none アプリがバックグラウンドにある場合にサービスが実行されるようにしたい場合は、プラグインの設定を capacitor.config.ts:
plugins: {
MediaSession: {
foregroundService: 'always',
},
},
デフォルトでは、再生中のみの起動は、ほとんどのアプリが望むものです。
オプションB: 自分でフォアグラウンドサービスを開始する
@capgo/capacitor-native-audio 再生、フォーカス、メディア通知を管理しますが、フォアグラウンドサービスを作成しません。メディアセッションプラグインを使用していない場合は、Androidプロジェクトに小さなサービスとローカルプラグインを追加する必要があります。
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 同じパッケージ内に
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();
}
}
AndroidManifest.xmlに MainActivity.java 前に super.onCreate、そしてサービスをマニフェストに宣言する
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" />
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';
ネイティブで音を再生する@capgo/capacitor-native-audio
bun add @capgo/capacitor-native-audio
bunx cap sync
起動時に一度設定し、プレロードして再生します:
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 web アセットの相対パス (audio/intro.mp3), a file:// URL https:// 再生リストを作成して、自動で進みます。 .m3u8 トラックが終了したときに発生するイベントです。画面がロックされていても、ネイティブ プレーヤーが実行されているため: isUrl: trueもし音源ホストが認証を必要とする場合、パス headers.
ロック画面と UI を同期してください。
The complete __CAPGO_KEEP_0__
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();
}
});
__CAPGO_KEEP_0__ ForegroundServiceStartNotAllowedException.
__CAPGO_KEEP_0__
ユーザーはロック画面、ヘッドフォン、または通知で、pauseを押します。 playbackState と、ネイティブプレーヤーを真実の源として扱います:
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
});
また、画面が前景に戻ったときに、アプリの状態を更新することも必要です。 isPlaying そして getCurrentTime、ウェブビューがイベントが発生したときに一時停止されていた可能性があるため、
HTMLのオーディオ要素を使用し、メディアセッションコントロールを使用します。
既存のウェブプレーヤーがあれば、それを維持し、プラグインを追加します。
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,
});
});
Call setPositionState 最大1秒から2秒ごとに、または生産環境では最大2秒ごとに呼び出しします。ロック画面は更新間を補間し、ブリッジにイベントを大量に送信するとバッテリーが浪費されるためです。 timeupdate 中断とルート変更を処理します。
中断やルート変更を処理する
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:
- ヘッドフォンを外す:ユーザーは再生を一時停止することを期待します。Androidでは、
AudioManager.ACTION_AUDIO_BECOMING_NOISYサービスで@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'
});
- を登録する必要があります。再生がすでに一時停止している場合は除きます。iOSでは、でルートの変更をリスンする必要があります。
背景再生の比較
:ナビゲーションプロンプトは背景音をダウンすることになります。話し言葉アプリは一時停止するべきです。低い声は難しいので、
- 背景再生のテスト
- シミュレータは背景の動作について嘘を言います。実機でテストしてください:
- 再生を開始し、画面をロックし、2分待ちます。音は続きます。
- ロック画面の再生、一時停止、次の曲、検索のコントロールを使用し、ロックを解除し、UIが一致するか確認してください。
- 再生を開始し、別のアプリで音を再生し、戻ってきてください。
- On Android 13+, バータンを消湯しではバータンを完法に不当してはいます。
- バータンを完法に上一丂二にバータンを完法に読いです。
adb shell dumpsys activity services | grep -A3 PlaybackService バータンを完法に上一丂二にバータンを完法に読いです。
コンターバータンを試いです。
バータンを完法に上一丂二にバータンを完法に読いです。: UIBackgroundModes lacks audioコンターバータンを試いです。 ambient or soloAmbient. Check Info.plist バータンを完法に上一丂二にバータンを完法に読いです。
バータンを完法に上一丂二にバータンを完法に読いです。バータンを完法に上一丂二にバータンを完法に読いです。 mediaPlayback. OEM バッテリー最適化設定も確認してください。
SecurityException: Starting FGS with type mediaPlayback ... requires permissions: 追加 FOREGROUND_SERVICE_MEDIA_PLAYBACK.
ForegroundServiceStartNotAllowedException: アプリがバックグラウンドで実行されていた場合にサービスを開始したことを意味します。ユーザーのプレイボタンでサービスを開始してください。
iOS のロック画面コントロールなし: showNotification false (ミックス可能なセッション) またはメタデータが設定されていなかった場合にのみ表示されます。ミックス可能なセッションを所有するアプリのみが Now Playing アプリになります。
Android の 2 つの通知: サービス通知を有効にしました。 showNotification ネイティブオーディオとサービス通知を投稿しました。サービス通知を最小限に抑え、またはメディアセッション プラグインのサービスのみを使用してください。
他の音楽アプリがあなたのアプリの上に再生され続けます。: ミックス可能なセッションを設定しました。セッションを focus: true と showNotification: true.
プレイヤーの変更を迅速に実装
JavaScriptでプレイヤーのロジック、UI、メタデータ、分析を準備します。Nativeセットアップがストアビルドに含まれる場合、 Capgoのライブアップデート codeに修正をプッシュすることができます。レビューサイクルが必要なく、 ネイティブオーディオドキュメント and メディアセッションドキュメント オプションをすべてカバーし、音声録音も行うアプリの場合、 Capacitorオーディオレコーダープラグイン.