background-execution について
アプリのバックグラウンド実行や一時停止中の処理を扱う Swift 開発者向けのスキルガイドです。タスクに適したシステム API の選択から、ライフサイクル上の制約、完了処理、テストまで案内します。
主な機能
- 01目的に応じたバックグラウンド API の選択
- 02BGTaskScheduler の登録と完了処理の確認
- 03バックグラウンド URLSession の再起動フローの確認
- 04プッシュ、位置情報、オーディオ設定の検証
- 05SwiftUI と macOS のバックグラウンド処理
- 06テストとよくある問題の案内
活用シーン
- 01コンテンツ更新に BGAppRefreshTask を選ぶ
- 02バックグラウンドでアップロードやダウンロードを完了する
- 03バックグラウンドタスクが動かない原因を調べる
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ n0an/ background-execution-agent-skill --skill background-executionインストール後、Claude Code で/background-executionを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlreferences/anti-patterns.mdbackground-audio.mdbackground-modes.mdbackground-push.mdbackground-url-session.mdbg-task-scheduler.mdfundamentals.mdmacos-background.mdswiftui-background-tasks.mdtask-assertions.mdtesting-and-debugging.md詳細
アプリがバックグラウンド状態またはサスペンド状態でも実行される Swift コードを作成・レビューします。作業内容に適した API を選び、システムの制約を守ることで、作業を確実に実行し、アプリが終了されないようにします。
レビューの手順:
references/fundamentals.mdを使って、バックグラウンド実行モデル(ライフサイクル、実行時間の上限、強制終了、5 つの原則)を把握します。- 以下の決定木で、選択した API が作業内容に合っていることを確認します。合っていない場合は、適切な API に切り替えます。
references/bg-task-scheduler.mdを使って、BGTaskSchedulerの使用方法(登録のタイミング、Info.plist、有効期限、setTaskCompleted)を確認します。references/task-assertions.mdを使って、タスクアサーション(beginBackgroundTask/endBackgroundTask、performExpiringActivity)を確認します。references/background-url-session.mdを使って、バックグラウンドのURLSession設定と再起動のフローを確認します。references/background-push.mdを使って、サイレントプッシュ/VoIP プッシュのペイロード、ヘッダー、ハンドラーを確認します。references/background-modes.mdを使って、UIBackgroundModesの宣言と位置情報に関する詳細を確認します。references/background-audio.mdを使って、バックグラウンドオーディオ(セッションカテゴリ、ロック中の録音、中断、ルート変更、マイクの許可)を確認します。references/swiftui-background-tasks.mdを使って、SwiftUI のScenePhase/.backgroundTaskの使用方法を確認します。references/macos-background.mdを使って、macOS のスケジューラー(NSBackgroundActivityScheduler、beginActivity、SMAppService)を確認します。references/testing-and-debugging.mdを使って、テスト/デバッグと制約への対処を確認します。references/anti-patterns.mdを使って、よくある間違いを見つけます。
作業の一部だけを行う場合は、関連するリファレンスファイルだけを読み込みます。
タスクに応じた参照先
ユーザーの目的に合わせて、読み込む順序を決めます。必要なものだけを読み込みます。
「アプリのコンテンツをバックグラウンドで更新したい」
references/bg-task-scheduler.md-BGAppRefreshTask、登録/送信/有効期限references/testing-and-debugging.md- 起動のシミュレート、backgroundRefreshStatusの処理
「長時間のメンテナンス/ML/クリーンアップをバックグラウンドで実行したい」
references/bg-task-scheduler.md-BGProcessingTask、電源/ネットワークの要件references/testing-and-debugging.md- 起動と有効期限のシミュレート
「ユーザーが開始したエクスポートを、アプリを離れた後も実行し続けたい(iOS 26)」
references/bg-task-scheduler.md-BGContinuedProcessingTask、進捗、送信方法、GPUreferences/fundamentals.md- ユーザーの同意/ユーザーが開始した作業に関する原則
「アプリがバックグラウンドに移行するとき、進行中のアップロード/保存を完了させたい」
references/task-assertions.md-beginBackgroundTask/endBackgroundTask、performExpiringActivity
「サスペンド中も継続する大容量ファイルのダウンロード/アップロードをしたい」
references/background-url-session.md- バックグラウンド設定、デリゲート、再起動のフローreferences/testing-and-debugging.md- 強制終了と制約に関する注意事項
「サーバーからアプリを起動したい」
references/background-push.md- サイレントプッシュのペイロード/ヘッダー/ハンドラー、または通話向けの PushKitreferences/background-modes.md-remote-notificationモード
「バックグラウンドでオーディオを再生し続けたい」
references/background-audio.md-audioモードとアクティブなセッション、カテゴリ/モード/オプション、中断、ルート変更
「画面をロックした状態で録音/音声入力/文字起こしをしたい」
references/background-audio.md-.playAndRecord、ロック中の録音、マイクの許可、AVAudioEngine のタップ、本番環境での注意点
「バックグラウンドで位置情報を追跡したい」
references/background-modes.md-locationモード、大きな変更の監視、領域の監視
「SwiftUI の方法で実装したい」
references/swiftui-background-tasks.md-ScenePhase、.backgroundTask(.appRefresh/.urlSession)references/bg-task-scheduler.md- 引き続きBGTaskSchedulerでスケジュールします
「macOS でバックグラウンド作業をしたい」
references/macos-background.md-NSBackgroundActivityScheduler、beginActivity、SMAppService
「バックグラウンドタスクが実行されません/テストするにはどうすればよいですか」
references/testing-and-debugging.md- lldb のシミュレーションコマンド、実行を制御する状態references/anti-patterns.md- よくある原因
「バグや App Review の問題が発生しています」
references/anti-patterns.md- 修正前と修正後の例を紹介
決定ツリー
どのバックグラウンド API を使えばよいですか?
Does the work require user consent or input mid-flight?
-> Background runtime is wrong. Bring it to the foreground.
Is work already running and you just need to finish it as the app backgrounds?
-> beginBackgroundTask / endBackgroundTask (apps)
-> ProcessInfo.performExpiringActivity (app extensions, watchOS)
Is it a user-initiated long task that should continue with visible progress? (iOS/iPadOS 26)
-> BGContinuedProcessingTask
Is it a large/long file download or upload that must survive suspension/termination?
-> background URLSession
Does the server need to tell the app new content exists?
-> background (silent) push (apns-push-type: background, content-available: 1)
Is it an incoming call invitation?
-> PushKit + CallKit (report the call on every push)
Is it periodic content refresh before the user opens the app?
-> BGAppRefreshTask
Is it long, deferrable maintenance / ML / cleanup?
-> BGProcessingTask (optionally requiresExternalPower / requiresNetworkConnectivity)
Does the app need to keep playing audio or recording the mic (incl. while locked)?
-> audio UIBackgroundMode + active AVAudioSession (.playback or .playAndRecord) [background-audio.md]
Does the app need to keep running for location / BLE / VoIP?
-> declare the matching UIBackgroundModes capability [background-modes.md]
macOS, deferrable repeating maintenance?
-> NSBackgroundActivityScheduler
macOS, keep critical non-UI work from being napped?
-> ProcessInfo.beginActivity / performActivity
どの BGTask タイプを使えばよいですか?
Short content refresh, system picks the time around app usage?
-> BGAppRefreshTask (UIBackgroundModes: fetch)
Long maintenance, ideally on charger + network?
-> BGProcessingTask (UIBackgroundModes: processing; requiresExternalPower / requiresNetworkConnectivity)
User-tapped long work with progress UI, continues after backgrounding? (iOS 26)
-> BGContinuedProcessingTask (title/subtitle, progress, submission strategy, optional .gpu)
Long processing of health-research-study data? (iOS 17)
-> BGHealthResearchTask
コア指示
- 決してバックグラウンド実行が保証されていると考えないでください。実行は状況に応じて任意に行われます。すべての機能にフォアグラウンドでの照合経路を設け、正確性が重要なロジックをバックグラウンドタスクだけに依存させないでください。
- 決して
BGTaskSchedulerハンドラーを遅延登録したり、ビューコード内や起動完了後に登録したりしないでください。システムがアプリを直接バックグラウンドで起動する場合があるため、すべてのハンドラーをApp.init()/application(_:didFinishLaunchingWithOptions:)で登録してください。(例外はBGContinuedProcessingTaskで、ユーザーの操作時に動的に登録します。) - 決して同じタスク識別子を二度登録しないでください。アプリがクラッシュします。
- 決して
BGTaskに有効期限ハンドラーを設定し忘れないでください。設定しないと、システムはタスクを完了済みかつ失敗として黙って扱います。ハンドラーを設定して、処理を速やかにキャンセルし、setTaskCompleted(success:)を必ず一度だけ呼び出してください。 - 決して再スケジュールを忘れないでください。
BGTaskSchedulerのリクエストは一度限りです。起動ハンドラーの最初の行で次のリクエストを送信してください。 requiresExternalPower/requiresNetworkConnectivityはBGProcessingTaskRequestにのみ設定し、アプリの更新リクエストには設定しないでください。earliestBeginDateは予定時刻ではなく、開始可能な最も早い時刻として扱ってください。- 決して
beginBackgroundTaskの開始と終了を対応させ忘れないでください。成功時と有効期限ハンドラー内の両方で、べき等に(.invalidを確認して)endBackgroundTaskを呼び出してください。対応しないとアサーションによりアプリが終了します。バックグラウンド遷移デリゲートの最後ではなく、処理を開始する前にbeginBackgroundTaskを呼び出してください。 - 決して
backgroundTimeRemainingを実際の猶予時間として信頼しないでください。フォアグラウンドではDBL_MAX、バックグラウンドでは参考値です。約30秒を想定して計画し、有効期限ハンドラーに頼ってください。 beginBackgroundTask(アプリ)またはperformExpiringActivity(エクステンション、watchOS)は、すでに実行中の処理を完了するためだけに使用してください。新たに長時間の処理を開始したり、将来の処理をスケジュールしたりするために使用してはいけません。- 決してバックグラウンド
URLSessionで完了ハンドラー付きの簡易メソッドやdataTaskを使わないでください。バックグラウンドセッションにはデリゲートが必要です。識別子ごとにセッションを1つ作成して保存し、再起動時には同一の識別子と構成で再作成してください。 - バックグラウンド
URLSessionの再起動フローを完全に実装してください。handleEventsForBackgroundURLSessionからハンドラーを保存し、セッションを再作成して、メインスレッド上でurlSessionDidFinishEvents(forBackgroundURLSession:)から保存したハンドラーを呼び出してください。didFinishDownloadingToのコールバック内で、locationのファイルを同期的に移動してください。 - バックグラウンドアップロードには、ファイルを使う
uploadTask(with:fromFile:)を使用してください。アプリ終了後は、データアップロードとストリームアップロードは失敗します。 - 決して
apns-push-type: background(およびapns-priority: 5)を付けずにサイレントプッシュを送信しないでください。また、aps辞書にはcontent-availableだけを含めてください。約30秒以内にフェッチ完了ハンドラーを呼び出してください。サイレントプッシュは信頼できるものではなく、間引きや統合の対象として扱ってください。 - iOS 13以降では、すべてのVoIPプッシュに対してCallKitへ着信を通知してください。通知しないと、システムがアプリを終了し、VoIPプッシュの権限を取り消します。通話以外のデータにVoIPプッシュを使用しないでください。
- 決して
locationバックグラウンドモードを有効にせずにallowsBackgroundLocationUpdates = trueを設定しないでください。致命的なエラーになります。継続的なlocationモードよりも、大きな変更の通知や領域監視を優先してください。 - バックグラウンドオーディオには、
audioモードと、バックグラウンドに対応したカテゴリ(再生には.playback、ロック中の録音には.playAndRecord/.record)を設定した有効なAVAudioSessionの両方が必要です。モードだけでは何も起こりません。起動時ではなく、オーディオの開始時にセッションを有効化し、.notifyOthersOnDeactivationを指定して無効化してください。必ずinterruptionNotification(再開前に.shouldResumeを確認)とrouteChangeNotification(.oldDeviceUnavailableで一時停止)に対応してください。 - マイクのキャプチャには、
AVAudioApplication.requestRecordPermission()(iOS 17以降)で権限を要求し、NSMicrophoneUsageDescriptionを宣言してください。このキーがないとアプリはクラッシュし、権限がないとキャプチャはエラーではなく無音のゼロ値サンプルを返します。AVAudioEngineのタップはメインアクター以外で設定してください(クロージャーはリアルタイムスレッドで実行されます)。また、AVAudioFileの設定を入力ノードのフォーマットに合わせてください。 UIBackgroundModesは必要最小限に宣言してください。正当な理由のないモードはApp Reviewで却下されます。より軽量な代替手段を優先してください。- ユーザーの状況を考慮してください。強制終了すると、次回の手動起動まで
BGTaskScheduler、サイレントプッシュ、バックグラウンドURLSessionによる再起動が抑止されます。backgroundRefreshStatusを読み取り(.deniedでは機能を縮退させ、.restrictedでは処理を行わないでください)、低電力モードや高い熱状態ではバックオフしてください。 - バックグラウンドに関係する設定(タスク登録、セッション再作成、依存関係の設定)は、
.onAppear/.task内ではなく、すべての起動時に実行される経路で行ってください。バックグラウンド起動では、UIが一度も構築されないことがあります。 - シーンが有効な場合は、非推奨の
applicationDidEnterBackground(_:)ではなくsceneDidEnterBackground(_:)を使用してください。戻るまでの時間は約5秒です。 - macOSでは、延期可能なメンテナンスには
NSBackgroundActivitySchedulerを使用し、App Napの制御にはProcessInfo.beginActivity/endActivity(対応させて使用)またはperformActivityを使用してください。performExpiringActivityはmacOSにはありません。 - 実機で、lldbの
_simulateLaunchForTaskWithIdentifier:/_simulateExpirationForTaskWithIdentifier:コマンドを使ってバックグラウンドタスクをテストしてください。これらのコマンドへの参照は決して出荷しないでください。必ず有効期限切れの経路もテストしてください。
出力形式
ユーザーがレビューを依頼した場合は、ファイルごとに指摘事項をまとめてください。各問題について:
- ファイル名と該当する行を示します。
- 置き換えるアンチパターンの名称を挙げます。
- 簡潔な修正前/修正後のコードを示します。
問題のないファイルは省略します。最後に、影響の大きい変更から優先順位を付けてまとめます。
ユーザーがバックグラウンド実行コードの作成または修正を依頼した場合は、指摘事項のレポートを返すのではなく、コードを直接変更してください。
出力例:
SyncManager.swift
22 行目:.onAppear で BGTaskScheduler ハンドラーを登録しています。バックグラウンド起動時には実行されません。
// Before
.onAppear {
BGTaskScheduler.shared.register(forTaskWithIdentifier: id, using: nil) { ... }
}
// After - register in App.init() / didFinishLaunching
init() {
BGTaskScheduler.shared.register(forTaskWithIdentifier: id, using: nil) { task in
self.handleRefresh(task: task as! BGAppRefreshTask)
}
}
48 行目:有効期限ハンドラーと setTaskCompleted がありません。有効期限が切れるとアプリが強制終了されます。
// Before
func handleRefresh(task: BGAppRefreshTask) { refresh() }
// After
func handleRefresh(task: BGAppRefreshTask) {
scheduleNext()
let op = RefreshOperation()
task.expirationHandler = { op.cancel() }
op.completionBlock = { task.setTaskCompleted(success: !op.isCancelled) }
queue.addOperation(op)
}
まとめ
- 登録のタイミング(優先度:高): ハンドラーを
App.init()に移動してください。そうしないと、バックグラウンド起動時に実行されません。 - 完了の要件(優先度:高): 有効期限ハンドラーを追加し、
setTaskCompletedを必ず一度だけ呼び出してください。
例は以上です。
参考資料
references/fundamentals.md- 実行モデル:フォアグラウンド/バックグラウンド/サスペンド、システムの実行予算、強制終了、ユーザー設定、5 つの原則、ライフサイクルとシーンの状態、「どの API を使うか」の対応表。references/bg-task-scheduler.md-BackgroundTasks:BGAppRefreshTask、BGProcessingTask、BGContinuedProcessingTask(iOS 26)、BGHealthResearchTask、登録、Info.plist キー、送信、有効期限、エラー。references/task-assertions.md-beginBackgroundTask/endBackgroundTask、backgroundTimeRemaining、ProcessInfo.performExpiringActivity、アサーションとBGTaskSchedulerの違い。references/background-url-session.md- バックグラウンドURLSessionの設定、必須のデリゲート、再起動/handleEventsForBackgroundURLSessionのフロー、各種設定、再開データ。references/background-push.md- サイレント/バックグラウンドプッシュ(ペイロード、ヘッダー、ハンドラー、スロットリング)、PushKit/VoIP と CallKit の要件。references/background-modes.md-UIBackgroundModesの対応表、バックグラウンド位置情報、BLE/アクセサリ/PTT、非推奨のバックグラウンドフェッチ。references/background-audio.md- バックグラウンド再生と録音:AVAudioSessionのカテゴリ/モード/オプション、ロック中の録音、マイクの許可、割り込み、ルート変更、AVAudioEngineタップと本番環境での注意点。references/swiftui-background-tasks.md-ScenePhase、.backgroundTaskシーン修飾子、非同期キャンセル、スケジュール設定とハンドラー処理。references/macos-background.md-NSBackgroundActivityScheduler、ProcessInfo.beginActivity/App Nap、SMAppService、クロスプラットフォーム対応表。references/testing-and-debugging.md- lldb による起動/有効期限切れのシミュレーション、backgroundRefreshStatus、低電力モード、熱状態、実行を制御する条件。references/anti-patterns.md- LLM がバックグラウンド実行コードの生成時によく犯す間違い。
コメント
Markdown 対応