React Nativeで実現するPiP × バックグラウンド再生の並列設計
React Nativeアプリで Picture-in-Picture(PiP)とバックグラウンド音声再生をフォールバックモデルで共存させる設計パターン。状態遷移、Now Playing情報の受け渡し、AudioSessionの整合性、PWA制約への対応まで解説。
React Nativeで実現するPiP × バックグラウンド再生の並列設計
動画配信サービスを開発していると、ユーザーから「動画を見ながら別のアプリを使いたい」「歩きながら講義を聞きたい」といった要望が必ず出てきます。
これらを実現するのが Picture-in-Picture(PiP) と バックグラウンド音声再生 ですが、React Nativeで両方を同時にサポートしようとすると、意外なほど設計上の落とし穴があります。
本記事では、React Nativeアプリで PiP とバックグラウンド音声再生を フォールバックモデル で共存させる設計パターンを紹介します。
対象読者
- React Nativeで動画プレイヤーを実装している開発者
- PiPやバックグラウンド再生の設計で悩んでいる方
- iOS / Web / PWA のクロスプラットフォーム対応を検討している方
プラットフォーム別の対応状況
まず現実を整理します。「PiP」と「バックグラウンド再生」は似て非なるもので、プラットフォームごとに対応状況が異なります。
| 機能 | Mobile (React Native) | Web (Safari) | Web (PWA) |
|---|---|---|---|
| バックグラウンド音声再生 | react-native-video + react-native-track-player で実現可能 | 非対応 | 非対応 |
| PiP | react-native-video の pictureInPicture prop で制御可能 | ブラウザネイティブで動作 | iOS制約により不可 |
| ロック画面 / Control Center 操作 | react-native-track-player 経由で対応 | — | — |
ポイントは PWA(Webクリップ)ではPiPもバックグラウンド再生も不可 という点です。これはiOSプラットフォーム側の制約であり、アプリケーション側で回避する手段がありません。
なぜ expo-video ではなく react-native-video を使うのか
Expo SDK 51 以降で提供されている expo-video は、Expoエコシステムとの統合が優れており、シンプルなユースケースでは導入しやすいライブラリです。しかし、本記事で扱うようなバックグラウンド再生のシナリオでは 動画の連続再生(プレイリスト再生)をサポートしていない という制約があります。
教育系・講座系のアプリでは「レッスン1が終わったら自動でレッスン2に進む」というプレイリスト的な連続再生が求められます。フォアグラウンドだけでなく、バックグラウンド再生中にも次の動画へシームレスに遷移する必要がありますが、expo-video は現時点でこのユースケースをカバーしていません。
一方、react-native-video + react-native-track-player の組み合わせであれば、TrackPlayer のキュー管理機能を活用してバックグラウンドでの連続再生を実現できます。
| ライブラリ | PiP | バックグラウンド再生 | バックグラウンド連続再生 | Control Center |
|---|---|---|---|---|
expo-video | 対応 | 対応 | 非対応 | 限定的 |
react-native-video + track-player | 対応 | 対応 | 対応 | 対応 |
この「バックグラウンドでの連続再生」要件が、react-native-video を選択した決定的な理由です。
設計方針 PiP優先・音声フォールバックモデル
検討の結果たどり着いたのが「PiPが使える場面ではPiPを優先し、PiPが終了/非対応の場合はバックグラウンド音声にフォールバックする」というモデルです。
このモデルの良いところは、ユーザーの意図に応じて最適な再生モードが自動選択される 点です。映像が必要な場面ではPiPが、音声だけで十分な場面ではバックグラウンド再生が使われます。
Mobile(React Native)の状態遷移設計
React Nativeでの実装が最も複雑です。核心は 動画プレイヤーとオーディオプレイヤーの制御権の受け渡し にあります。
実装上の重要ポイント
1. react-native-video の PiP 有効化
まず pictureInPicture を有効にします。
tsx<Video source={{ uri: videoUrl }} pictureInPicture={true} // PiPを有効化 playInBackground={true} // バックグラウンド再生も有効 onPictureInPictureStatusChanged={({ isActive }) => { setPipActive(isActive); if (!isActive) { // PiP終了 → バックグラウンド音声再生に移行 handoffToAudioPlayer(); } }} />
2. Now Playing 情報の受け渡し
PiPとバックグラウンド音声では、ロック画面 / Control Center に表示する Now Playing 情報の管理者 が異なります。ここが最大の難所です。
3. AudioSession の整合性
iOS の AudioSession カテゴリは状態遷移に合わせて適切に管理する必要があります。
| 状態 | AudioSession カテゴリ | mixWithOthers |
|---|---|---|
| フォアグラウンド再生 | .playback | なし |
| PiP 再生 | .playback | なし(維持) |
| バックグラウンド音声 | .playback | なし(維持) |
mixWithOthers を設定すると他のアプリの音声と混ざってしまうため、動画コンテンツでは基本的に使用しません。
ユーザー体験マッピング
設計が正しいかどうかは、具体的なユースケースで検証します。
| シナリオ | 最適な再生モード | 理由 |
|---|---|---|
| レッスン動画を見ながらメモを取る | PiP | 映像を見ながら別アプリを操作したい |
| 講義を聞きながら移動 | バックグラウンド音声 | 画面ロックして省電力 |
| 視聴中に電話がかかってきた | PiP → 通話後に復帰 | iOS標準挙動に準拠 |
| PiP非対応デバイス | バックグラウンド音声 | フォールバックで現行動作を維持 |
Web での対応
Safari
ブラウザネイティブの PiP API が動作するため、動画プレイヤー(Mux Player 等)が標準対応していれば追加実装は不要です。ユーザーの発見しやすさを向上させたい場合は、プレイヤーUIに明示的なPiPボタンを追加するとよいでしょう。
PWA(Webクリップ)
iOSの制約により、PWA環境では PiPもバックグラウンド再生も不可 です。これはアプリ側では解決できないため、以下の対応が現実的です。
- ユーザーへの案内 「バックグラウンド再生はSafariまたはネイティブアプリをご利用ください」
- 可能であれば、ネイティブアプリへの誘導導線を設置
実装の優先順位
すべてを一度に実装するのではなく、段階的に進めることを推奨します。
| 優先度 | 対応内容 | 工数 | インパクト |
|---|---|---|---|
| Phase 1 | PWA制約をユーザーに案内 | 即日 | 問い合わせを即座に解決 |
| Phase 2 | Mobile PiP + 遷移ハンドリング | 中〜大 | ネイティブアプリのUX大幅向上 |
| Phase 3 | Web PiPボタンの明示追加 | 小 | Safariでの発見性向上 |
Phase 1 で即座にユーザーの困りごとを解決し、Phase 2 は十分な検証期間を設けて進めるのが現実的です。特に Phase 2 では、既存のオーディオ再生まわりのロジックとの相互作用が複雑になるため、段階的なテストが重要です。
まとめ
PiP × バックグラウンド再生の並列設計で押さえるべきポイントは3つです。
- フォールバックモデル PiP → バックグラウンド音声、という優先順位で自動遷移する
- 制御権の受け渡し 動画プレイヤーと音声プレイヤー間の Now Playing 情報・AudioSession の引き継ぎを確実に行う
- プラットフォーム制約の受容 PWAの制約は回避不可能。ユーザーへの適切な案内で対応する
React Nativeで動画配信アプリを開発している方の参考になれば幸いです。