RORK LABEN
BUILD — Rork Max はクラウド上の実機 Mac に Xcode と iOS SDK を載せ、SwiftUI を書き、ビルドし、エラーを読んで直す反復を回します。コードを吐いて終わりではない点が生成物の質に効いていますNATIVE — 生成されるのは React Native ではなく純粋な Swift / SwiftUI です。AR や Metal、ウィジェットなど React Native からは届かない機能に手が届くことが、他ビルダーとの実質的な差になりますPLATFORMS — 対応は iPhone・iPad・Apple Watch・Apple TV・Vision Pro に加えて iMessage まで含みます。ウォッチや拡張から入る設計を試すのに向いていますCOMPANION — Rork Companion により、有料の Apple Developer アカウントなしで生成したアプリを実機の iPhone で確認できます。最初の一本を試す段階の障壁が一段下がりましたPRICING — 無料で開始でき有料プランは月額25ドルから、Rork Max は月額200ドルの Max プランです。回収できる本数と規模を先に見積もっておく価値がありますDEADLINE — Google Play は2026年8月31日以降、新規アプリと更新の双方に対象 API レベル36 以上を要求します。残り10日で、生成物の targetSdkVersion は自分で確認が必要ですBUILD — Rork Max はクラウド上の実機 Mac に Xcode と iOS SDK を載せ、SwiftUI を書き、ビルドし、エラーを読んで直す反復を回します。コードを吐いて終わりではない点が生成物の質に効いていますNATIVE — 生成されるのは React Native ではなく純粋な Swift / SwiftUI です。AR や Metal、ウィジェットなど React Native からは届かない機能に手が届くことが、他ビルダーとの実質的な差になりますPLATFORMS — 対応は iPhone・iPad・Apple Watch・Apple TV・Vision Pro に加えて iMessage まで含みます。ウォッチや拡張から入る設計を試すのに向いていますCOMPANION — Rork Companion により、有料の Apple Developer アカウントなしで生成したアプリを実機の iPhone で確認できます。最初の一本を試す段階の障壁が一段下がりましたPRICING — 無料で開始でき有料プランは月額25ドルから、Rork Max は月額200ドルの Max プランです。回収できる本数と規模を先に見積もっておく価値がありますDEADLINE — Google Play は2026年8月31日以降、新規アプリと更新の双方に対象 API レベル36 以上を要求します。残り10日で、生成物の targetSdkVersion は自分で確認が必要です
記事一覧/開発ツール
開発ツール/2026-06-24上級

電話・イヤホン抜き・他アプリ再生に強い、音声アプリの中断ハンドリング

AVAudioSessionの中断通知とルート変更通知を正しく扱い、電話の着信やイヤホンの抜き差しで再生が破綻しない音声アプリを作ります。オーディオカテゴリの決め方、Now Playingとリモートコマンドの接続、バックグラウンド再生のテストまでSwiftコードで整理します。

Rork Max233AVFoundationオーディオSwiftUI64バックグラウンド再生3

プレミアム記事

瞑想や学習向けの音声を再生する小さなアプリを個人開発で出したとき、最初に届いた不具合報告が「電話が来た後、音が戻ってこない」というものでした。再生中に着信があると音が止まるのは当然なのですが、通話が終わってもアプリは止まったまま、画面の再生ボタンは「再生中」の見た目のまま固まっていたのです。

原因は、AVAudioSession の中断を一切ハンドリングしていなかったことでした。再生は AVAudioPlayer に任せきりで、OS から「いま中断したよ」「もう戻っていいよ」という通知が来ていることに、私のコードがまったく耳を傾けていなかったのです。音声アプリの品質は、機能が一通り動くかどうかよりも、この種の割り込みにどれだけ丁寧に応えるかで決まると、その時に痛感しました。

ここから、電話・Siri による中断、イヤホンの抜き差しによるルート変更を正しく扱い、再生が破綻しない実装を、Rork Max が生成するネイティブ Swift にそのまま組み込める形で見ていきます。

まずオーディオセッションのカテゴリを決める

何より先に、アプリがどういう音を出すアプリなのかを OS に宣言します。これを怠ると、サイレントスイッチで音が消えたり、他アプリの音楽を不必要に止めてしまったりします。

import AVFoundation
 
func configureAudioSession() {
    let session = AVAudioSession.sharedInstance()
    do {
        // 再生主体のアプリ。サイレントスイッチに影響されず再生する
        try session.setCategory(.playback, mode: .default)
        try session.setActive(true)
    } catch {
        print("Audio session setup failed: \(error)")
    }
}

.playback は「このアプリの音はコンテンツそのものである」という宣言で、ロック中やバックグラウンドでも鳴らせます。逆に、他アプリの音楽の上に短い効果音を重ねたいだけなら .ambient を選ぶ、というように、用途に応じてカテゴリを変えます。最初の宣言を正しく選ぶことが、後の挙動すべての土台になります。

中断通知を購読する

中断は AVAudioSession.interruptionNotification で届きます。.began(中断開始)と .ended(中断終了)の二つの局面があり、終了時には「自分から再開してよいか」のヒントが付いてきます。

final class PlaybackController {
    private var wasPlayingBeforeInterruption = false
 
    func observeInterruptions() {
        NotificationCenter.default.addObserver(
            self, selector: #selector(handleInterruption),
            name: AVAudioSession.interruptionNotification, object: nil)
    }
 
    @objc private func handleInterruption(_ note: Notification) {
        guard let info = note.userInfo,
              let raw = info[AVAudioSessionInterruptionTypeKey] as? UInt,
              let type = AVAudioSession.InterruptionType(rawValue: raw) else { return }
 
        switch type {
        case .began:
            // 電話やSiriが割り込んだ。状態を覚えておく
            wasPlayingBeforeInterruption = player.isPlaying
            player.pause()
 
        case .ended:
            guard let optsRaw = info[AVAudioSessionInterruptionOptionKey] as? UInt else { return }
            let options = AVAudioSession.InterruptionOptions(rawValue: optsRaw)
            // shouldResume が立っていて、かつ中断前に再生中だったときだけ再開
            if options.contains(.shouldResume), wasPlayingBeforeInterruption {
                try? AVAudioSession.sharedInstance().setActive(true)
                player.play()
            }
 
        @unknown default:
            break
        }
    }
}

ここで肝になるのが shouldResume の扱いです。OS は「再開してよい中断」と「再開すべきでない中断」を区別しています。たとえば他の音楽アプリがユーザー操作で前面に出てきたときは、勝手に再生を奪い返すべきではありません。shouldResume が立っていないのに再生を再開すると、ユーザーの意図に反してしまいます。中断前に再生中だったかどうかも併せて確認し、両方を満たすときだけ静かに戻すのが行儀の良い実装です。

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

この記事の続きを読む

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

この記事で得られること
AVAudioSession の中断通知(電話・Siri)とルート変更通知(イヤホン抜き差し)を正しく購読し、再生を破綻させない実装ができます
中断後に自分から再開してよい場合と、ユーザー操作を待つべき場合を shouldResume フラグで切り分けられます
Now Playing とリモートコマンドに連動させ、ロック画面やコントロールセンターから操作できる本番品質の音声アプリを組めます
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

開発ツール2026-07-18
文字サイズ最大とドイツ語で、生成された画面は静かに詰まる — Rork Max の SwiftUI にレイアウト耐性の検証を通した記録
Rork Max が生成した SwiftUI 画面を疑似ローカライズと最大文字サイズに通し、どこから詰まるかを機械的に洗い出した記録です。ViewThatFits・ScaledMetric・layoutPriority の使いどころと、再生成のたびに回帰を捕まえるスナップショット検証を、実際の数値とともにまとめました。
開発ツール2026-07-12
Rork Maxのアプリで、アイコンを気持ちよく動かすsymbolEffect実装メモ
Rork Maxが生成したSwiftアプリで、SF Symbolsをbounce・pulse・variableColor・contentTransitionで動かす実装を、動くコードとOSバージョンの出し分け、そして動かしすぎて後悔した落とし穴つきで整理します。
開発ツール2026-07-09
Rork Max が書いた Swift を、Swift 6 の厳格な並行性検査に通す
Rork Max が生成した SwiftUI アプリを Swift 6 の complete concurrency checking に通した記録です。警告217件をターゲット単位で削り、@MainActor の置き場所と Sendable の壊し方を実測とともに整理しました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →