RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/開発ツール
開発ツール/2026-05-05上級

Rork のポッドキャストアプリを本番運用へ — expo-audio への移行・割り込みからの復帰・ダウンロード再開

Rork のポッドキャストアプリを実運用に耐えさせるための実装メモ。SDK 55 で消える expo-av からの移行、着信割り込みからの復帰、中断されたダウンロードの再開、iCloud バックアップと容量予算の設計まで、動くコードで扱います。

ポッドキャストバックグラウンド再生3expo-audio3expo-av5オフライン3Rork515React Native209

プレミアム記事

ポッドキャストアプリを Rork で作ろうと決めたとき、最初に「あれ、思っていたより難しい」と感じた方は少なくないのではないでしょうか。音楽プレイヤーとの違いは、RSS フィードを解析してエピソードを動的に取得しなければならない点、そしてアプリをバックグラウンドに下げた後も音声が途切れてはならない点にあります。

壁紙アプリや健康系アプリを長年作ってきた経験のなかで、バックグラウンド再生まわりの設定ミスが原因で TestFlight のフィードバックに「画面を消すと止まる」という報告を受けたことがあります。原因は些細な設定漏れでした。ここでは同じ轍を踏まないための実装パターンを、動作するコードとともにお伝えします。

完成形から逆算してアーキテクチャを決める

コードを書き始める前に、作るアプリの全体像を決めておくことをおすすめします。行き当たりばったりで実装すると、後から状態管理が破綻しがちです。

今回構築するポッドキャストアプリの機能構成は以下のとおりです。

  • フィード管理: RSS URL を登録してエピソード一覧を取得・表示する
  • 再生機能: バックグラウンド再生・シークバー・再生速度変更(0.75x〜2x)
  • ダウンロード: エピソードをデバイスに保存してオフライン再生
  • ロック画面対応: iOS Control Center・Android メディアコントロールに再生情報を表示

状態管理には Zustand を使います。Context API でも構いませんが、音声再生のような「グローバルで唯一の状態」を管理する場面では、Zustand のシンプルさが際立ちます。

ライブラリ構成は次のとおりです。

# 必要なパッケージをインストール
npx expo install expo-av expo-file-system expo-media-library
npm install zustand react-native-xml2js date-fns

データ構造の定義

TypeScript の型定義から始めると、後の実装が格段に楽になります。

// types/podcast.ts
 
export interface Episode {
  id: string;           // RSS の guid をそのまま使う
  title: string;
  description: string;
  audioUrl: string;
  pubDate: Date;
  duration: number;     // 秒数
  imageUrl?: string;
  localPath?: string;   // ダウンロード済みの場合はローカルパス
}
 
export interface PodcastFeed {
  id: string;
  title: string;
  description: string;
  imageUrl: string;
  rssUrl: string;
  episodes: Episode[];
  lastUpdated: Date;
}
 
export interface PlayerState {
  currentEpisode: Episode | null;
  isPlaying: boolean;
  position: number;     // 秒数
  duration: number;     // 秒数
  playbackRate: number; // 0.75 / 1.0 / 1.25 / 1.5 / 2.0
}

この型定義を最初に固めておくことで、Rork の AI にコードを生成させるときも「この型に沿った実装を」と伝えるだけで、期待に近いコードが出てきやすくなります。

expo-av のセットアップとバックグラウンド再生の落とし穴

バックグラウンド再生で最もよく見る失敗は、app.json の設定と Audio.setAudioModeAsync の両方が必要なことを知らないケースです。どちらか一方しか設定していないと、iOS ではアプリが非アクティブになった瞬間に再生が止まります。

app.json の設定

{
  "expo": {
    "plugins": [
      [
        "expo-av",
        {
          "microphonePermission": "ポッドキャストのメモ録音機能に使用します"
        }
      ]
    ],
    "ios": {
      "infoPlist": {
        "UIBackgroundModes": ["audio"]
      }
    }
  }
}

UIBackgroundModes"audio" を追加することで、iOS がこのアプリをバックグラウンドでも音声を再生できるアプリとして認識します。この設定がないと、staysActiveInBackground: true を設定しても効果がありません。

Audio セッションの初期化

// hooks/useAudioSession.ts
import { Audio } from 'expo-av';
import { useEffect } from 'react';
 
export function useAudioSession() {
  useEffect(() => {
    const initAudioSession = async () => {
      try {
        await Audio.setAudioModeAsync({
          // バックグラウンドでも再生を継続する(iOS 必須設定)
          staysActiveInBackground: true,
          // サイレントモードでも再生する
          playsInSilentModeIOS: true,
          allowsRecordingIOS: false,
          // Android: 音量を下げる(ダック)ではなく完全に停止する
          shouldDuckAndroid: false,
          interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
          interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
        });
        console.log('Audio session initialized');
      } catch (error) {
        // Audio セッション初期化失敗は致命的エラーではないため、
        // ログに残してアプリは継続させる
        console.error('Failed to initialize audio session:', error);
      }
    };
 
    initAudioSession();
  }, []);
}

このフックをルートコンポーネント(app/_layout.tsx)で呼び出します。アプリ起動時に一度だけ実行すれば十分です。

Android では shouldDuckAndroid: false が重要です。true にすると、他のアプリが音声を再生したとき(例: 着信音)に音量が下がるだけで再生が続きます。ポッドキャストアプリとしては、他の音声が割り込んだときは一時停止する方が自然な動作です。

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

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
SDK 55 で削除される expo-av から expo-audio へ移す対応表と、Android で interruptionMode が効かない既知の制約
中断されたダウンロードを resumeData で再開する実装。完了判定にファイルの存在を使わない理由と HTTP 206 の扱い
着信・イヤホン抜去・容量逼迫という3つの割り込みに耐える設計と、実機で1分ずつ試せる検証5項目
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

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

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

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

関連記事

開発ツール2026-06-26
Rorkのアプリで音をバックグラウンド再生し、ロック画面から操作できるようにする
Rorkが生成したExpoアプリで音楽やヒーリング音をバックグラウンド再生し、ロック画面・コントロールセンターから操作できるようにするまでを、expo-audioの実装コードと落とし穴つきでまとめます。
開発ツール2026-07-15
Rorkの癒しアプリにスリープタイマーを付けたら、フェードアウトが実際の音とズレた話
Rorkが生成するスリープタイマーは、壁時計のsetIntervalで音量を下げます。数値上は30分でも、実際の音はもっと早く消えたり不自然に途切れたりします。フェードを再生位置で駆動し直す実装と、対数カーブ・停止処理・画面ロック時の限界までを実運用の視点でまとめました。
開発ツール2026-05-13
Rork で癒し系アプリのアンビエントサウンドを実装して詰まった3つのこと
癒し・瞑想系アプリのアンビエントサウンド実装でRorkが苦手な3つのパターンを解説。ループ途切れ・iOSサイレントモード・バッテリー消耗の問題をexpo-avで解決する実践コード付き。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →