RORK LABEN
DEADLINE — 本日8月31日から、Google Play への新規アプリ提出と既存アプリの更新は Android 16(API レベル36)以上をターゲットにする必要がありますSCOPE — 既存アプリは削除されません。ただし要件を下回ったままだと、新しい Android バージョンのユーザーには表示されなくなります。消えないが届かなくなる、という形の影響ですEXTENSION — 間に合わない場合、11月1日までの延長を申請できます。申請という選択肢があること自体を知らずに当日を迎える例が毎年出ていますMIGRATION — Rork の生成物は React Native と Expo が土台です。targetSdkVersion を上げる作業は、Expo SDK とネイティブ依存の更新を必ず伴いますTESTING — 本当に時間を取られるのはビルドが通った後です。バックグラウンド実行制限、権限モデル、フォアグラウンドサービスの型指定が一斉に効きますORDER — 現実的な順序は、延長申請の可否を確認し、Expo SDK のアップグレード計画を立て、最後に最小構成で実機の回帰テストを行うことです。当日に全部やると原因が追えませんDEADLINE — 本日8月31日から、Google Play への新規アプリ提出と既存アプリの更新は Android 16(API レベル36)以上をターゲットにする必要がありますSCOPE — 既存アプリは削除されません。ただし要件を下回ったままだと、新しい Android バージョンのユーザーには表示されなくなります。消えないが届かなくなる、という形の影響ですEXTENSION — 間に合わない場合、11月1日までの延長を申請できます。申請という選択肢があること自体を知らずに当日を迎える例が毎年出ていますMIGRATION — Rork の生成物は React Native と Expo が土台です。targetSdkVersion を上げる作業は、Expo SDK とネイティブ依存の更新を必ず伴いますTESTING — 本当に時間を取られるのはビルドが通った後です。バックグラウンド実行制限、権限モデル、フォアグラウンドサービスの型指定が一斉に効きますORDER — 現実的な順序は、延長申請の可否を確認し、Expo SDK のアップグレード計画を立て、最後に最小構成で実機の回帰テストを行うことです。当日に全部やると原因が追えません
記事一覧/開発ツール
開発ツール/2026-08-31中級

画面ロックから3分後、expo-audio の環境音は静かに止まっていました

expo-audio の音が画面ロックで止まる原因を、ビルド設定・オーディオセッション・ロック画面連携の三層に分けて切り分けます。Android で約3分後に止まるのは、ドキュメントに書かれた止まり方です。

expo-audio4バックグラウンド再生4React Native233Expo192Android47

個人開発で、睡眠向けの環境音アプリを長く運用しています。ユーザーは雨の音を再生して、そのまま眠る。画面は1分もせずロックされ、音だけが朝まで残る——「画面が消えてからが本番」という性質のアプリです。

expo-av が廃止された流れを受けて expo-audio へ移行した検証ビルドを Android 実機で試したとき、妙な止まり方に出会いました。画面をロックした直後は鳴り続けているのに、3分ほど経ってから、エラーも出さずに静かに止まるのです。

即座に止まるなら設定漏れを疑えます。しかし「しばらく鳴ってから止まる」は、原因の見当がつけにくい挙動です。調べてみると、これはバグでも端末の癖でもなく、Expo の公式ドキュメントに明記されている止まり方でした。止まるまでの経緯と、設定を三層に分けて塞いだ手順を残しておきます。

expo-av の背景再生の知識は、expo-audio に持ち越せません

前提の整理から始めます。expo-av は SDK 52 で非推奨になり、SDK 55 で削除されました。Rork が生成するアプリは Expo を基盤にしているため、新しい SDK でビルドし直す限り、音まわりは expo-audio へ移ることになります。

expo-av の時代、バックグラウンド再生の要は staysActiveInBackground という一つの真偽値でした。setAudioModeAsync にこれを渡せば、おおむね話は済んでいました。

expo-audio の AudioMode には、このフィールドが存在しません。名前で探して見つからず、それらしい shouldPlayInBackgroundtrue にして満足する——私がまさにその順路をたどりました。iOS ではそれで動きます。そして Android では、3分で止まります。

設定が「一つの真偽値」から「三つの層」に分かれたこと。これが今回の落とし穴の正体です。

三層の全体像——どの層が欠けると、どう止まるか

先に地図を示します。expo-audio のバックグラウンド再生は、次の三層がすべて揃って初めて成立します。

設定する場所設定内容欠けたときの症状
第一層:ビルド設定app.json の config pluginenableBackgroundPlayback(既定 trueiOS はロックで即停止。Android は前面サービス未宣言
第二層:オーディオセッション実行時の setAudioModeAsyncshouldPlayInBackground: true(既定 false両 OS ともロックや背景移行で即停止
第三層:ロック画面連携実行時の setActiveForLockScreenAndroid では実質必須(iOS は任意)Android のみ、約3分後に停止

この表は、症状からの逆引きに使えます。ロックした瞬間に止まるなら第一層か第二層。しばらく鳴ってから止まるなら第三層。「3分」という数字が、どの層を疑うべきかを教えてくれるわけです。

第一層と第二層——ビルド時の宣言と、実行時のセッション設定

第一層は config plugin です。app.json に次のように書きます。

{
  "expo": {
    "plugins": [
      ["expo-audio", { "enableBackgroundPlayback": true }]
    ]
  }
}

これが Android 側に FOREGROUND_SERVICEFOREGROUND_SERVICE_MEDIA_PLAYBACK の2つの権限と、メディア再生用の前面サービス(AudioControlsService)の宣言を追加し、iOS 側に UIBackgroundModesaudio を追加してくれます。ネイティブ設定を手で触る必要はありません。

注意したいのは、enableBackgroundPlayback の既定値が true であることです。つまりこの層は「何もしなくても通っている」ことが多い。一方で第二層の shouldPlayInBackground の既定値は false です。ビルド設定は既定で有効、実行時設定は既定で無効——二つの層で既定値の向きが逆なので、「マニフェストには全部入っているのに止まる」という混乱が起きやすくなっています。

第二層は、再生を始める前に一度だけ呼ぶセッション設定です。

import { setAudioModeAsync } from 'expo-audio';
 
await setAudioModeAsync({
  playsInSilentMode: true,      // iOS のサイレントスイッチ下でも再生する
  shouldPlayInBackground: true, // 背景再生の本体。既定は false
  interruptionMode: 'doNotMix', // ロック画面操作を使うなら必須
});

interruptionMode の既定は 'mixWithOthers' ですが、ロック画面のコントロールを正しく自分のプレイヤーに結び付けるには 'doNotMix' が必要だとドキュメントに明記されています。また、かつての interruptionModeAndroid は非推奨になり、interruptionMode が両プラットフォームに効くよう統合されました。移行時に古い記事を参照すると、ここでも名前の食い違いに当たります。

第三層——Android は setActiveForLockScreen がないと約3分で止まります

ここが今回の本題です。Expo のドキュメントには、Android について次の趣旨の記述があります。ロック画面コントロールを有効にしない場合、バックグラウンド再生は約3分で停止する。OS の制限である、と。

私のビルドが3分で静かに止まったのは、この一文の通りの挙動でした。実装としては、再生開始のタイミングで setActiveForLockScreen を呼びます。

player.loop = true;
player.setActiveForLockScreen(true, {
  title: '雨の音',
  artist: 'Ambient Sounds',
});
player.play();

この呼び出しがメディア通知を出し、その通知に紐づく前面サービスが再生を生かし続けます。通知シェードにメディア通知が出ていることが、「止まらないこと」の目に見える担保です。逆に言えば、ロック前に通知が出ていなければ、その再生は3分の砂時計の上にあります。

補足として、ロック画面を掌握できるプレイヤーは同時に1つだけです。環境音アプリのように複数の音源を切り替える構成では、アクティブなプレイヤーを切り替えるたびに呼び直すか、updateLockScreenMetadata で表示だけ更新する設計になります。

動作した最小構成と、私が検証に3分を組み込んだ理由

三層をまとめた最小構成です。

import { useAudioPlayer, setAudioModeAsync } from 'expo-audio';
import { useEffect } from 'react';
import { Button } from 'react-native';
 
const rainSound = require('./assets/rain.mp3');
 
export function AmbientPlayer() {
  const player = useAudioPlayer(rainSound);
 
  useEffect(() => {
    setAudioModeAsync({
      playsInSilentMode: true,
      shouldPlayInBackground: true,
      interruptionMode: 'doNotMix',
    });
  }, []);
 
  const start = () => {
    player.loop = true;
    player.setActiveForLockScreen(true, {
      title: '雨の音',
      artist: 'Ambient Sounds',
    });
    player.play();
  };
 
  return <Button title="再生" onPress={start} />;
}

検証の手順も、この件を経て一つ増やしました。Android 実機で再生を始め、画面をロックし、通知シェードにメディア通知が出ていることを確かめたうえで、3分以上そのまま聴く。シミュレータの30秒確認では、この問題は永遠に見つかりません。

環境音アプリにとって、3分は致命的な数字です。ユーザーがいちばん無防備な、眠りかけの時間に音が消えます。しかもレビューに書かれるのは「音が止まる」だけで、3分という手がかりは書かれません。2014年からアプリを出し続けてきた身として、手元で3分待つという地味な検証が、想像より多くのものを守ってくれると感じています。

ループの継ぎ目の途切れやサイレントモードでの無音など、環境音まわりの別の落とし穴は Rork で癒し系アプリのアンビエントサウンドを実装して詰まった3つのことにまとめています。また、ロック中の再生が確保できた次の段階——スリープタイマーとフェードアウトの精度——については、プレミアム記事の Rorkの癒しアプリにスリープタイマーを付けたら、フェードアウトが実際の音とズレた話で、再生位置駆動の設計として詳しく扱っています。

まずは実機で3分、聴いてみてください。そこが通れば、朝まで鳴り続ける土台はできています。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

開発ツール2026-06-26
Rorkのアプリで音をバックグラウンド再生し、ロック画面から操作できるようにする
Rorkが生成したExpoアプリで音楽やヒーリング音をバックグラウンド再生し、ロック画面・コントロールセンターから操作できるようにするまでを、expo-audioの実装コードと落とし穴つきでまとめます。
開発ツール2026-05-05
Rork のポッドキャストアプリを本番運用へ — expo-audio への移行・割り込みからの復帰・ダウンロード再開
Rork のポッドキャストアプリを実運用に耐えさせるための実装メモ。SDK 55 で消える expo-av からの移行、着信割り込みからの復帰、中断されたダウンロードの再開、iCloud バックアップと容量予算の設計まで、動くコードで扱います。
開発ツール2026-05-04
Rork でマイク・音声録音が動かない——よくある原因と修正法を症状別に整理
Rork で生成したアプリでマイクや音声録音が機能しない場合の原因を症状別に解説。パーミッション設定・expo-audio の状態管理・iOS/Android の挙動差・シミュレーター制限まで、実際に詰まりやすいポイントを網羅しています。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →