📱

Background Tasksフレームワーク入門

に公開

Background Tasksは、iOS 13で追加されたフレームワークです。その名の通り、アプリがバックグラウンドにあるときにタスクを実行できるようにするものです。

AppRefreshタスクとProcessingタスク

Background Tasksフレームワークで実行できるバックグラウンドタスクには今のところAppRefreshタスクとProcessingタスクの2種類があります。

AppRefreshタスクはアプリのコンテンツをバックグラウンドで更新するタスクです。株価のようなちょっとした情報更新に使用することが想定されています[1]

Use app refresh tasks for updating your app with small bits of information, such as the latest stock values.

Processingタスクは時間のかかる処理をバックグラウンドで実行するタスクです。数分かかるタスクも実行できるが、システムが中断する可能性もあるとドキュメント[2]には書かれています。

Although processing tasks can run for minutes, the system can interrupt the process.

また同ドキュメントによると、Processingタスクはデバイスがアイドル状態のときのみ実行され、システムはユーザーがデバイスを使い始めるとすべてのバックグラウンドで実行中のProcessingタスクを停止する、ただしAppRefreshタスクはその影響を受けない、とあります。

Processing tasks run only when the device is idle. The system terminates any background processing tasks running when the user starts using the device. Background refresh tasks are not affected.

既存のバックグラウンド処理機能との違い

Background Tasksフレームワークが追加されたことに伴い、以前からあったbackground fetchのAPIがdeprecatedになりました。[3]

一方で、background fetchよりもっと昔からあるUIApplicationbeginBackgroundTask(expirationHandler:)等々のAPIを利用するバックグラウンド処理機能の方は残っています。こちらはアプリがフォアグラウンドからバックグラウンドに回る際に、処理が完了していない場合に追加で処理時間を与えられるものであり、新しいフレームワークの方はバックグラウンドで(遅延可能な処理を)定期的・継続的な処理を行うものなので、用途が明確に違うために残されているのでしょう。

実装の基本的な流れ

Background Tasksを用いたバックグラウンド処理の実装は、プロジェクト設定等の細かい作業が多かったりするのですが、大局的には以下の2ステップと考えておけばスッキリ理解できます。

1. バックグラウンドで実行する処理をregisterする

BGTaskSchedulerregister(forTaskWithIdentifier:using:launchHandler:)メソッドを呼び、タスクのidentifier、タスクを実行するキュー、バックグラウンドでアプリが起こされたときに実行する処理を登録します。

func register(forTaskWithIdentifier identifier: String, 
        using queue: DispatchQueue?, 
launchHandler: @escaping (BGTask) -> Void) -> Bool

これはAppDelegateのapplication(_:didFinishLaunchingWithOptions:launchOptions:)で行う必要があります。違うタイミングでregisterしようとすると、

All launch handlers must be registered before application finishes launching

という実行時エラーになります。

2. リクエストを作成し、submitする

BGAppRefreshTaskRequestまたはBGProcessingTaskRequest(どちらもBGTaskRequestクラスを継承)を初期化し、BGTaskSchedulersubmit(_:)メソッドで送信します。

func submit(_ taskRequest: BGTaskRequest) throws

実装手順

AppRefresh、Processingの両タスクを使用する実装の手順を示します。

1. Capablitiyを設定する

Xcodeの[Signing & Capabilities]を選択し、[+Capability]ボタンをクリックして"Background Modes"を追加します。

Modesリストの中にある、"Background fetch"と"Background processing"にチェックを入れます。(利用するバックグラウンドタスクの種類に応じてどちらか、あるいは両方を選択します)

2. Info.plistを設定する

Info.plistに、"BGTaskSchedulerPermittedIdentifiers"キー(表示名は"Permitted background task scheduler identifiers")を追加し、各タスクごとにidentifierとなる文字列を追加します。

このidentifierは、あとでコード側でも使用します。

3. モジュールをimportする

バックグラウンド処理の実装を行うクラスで、BackgroundTasks をimportします。

import BackgroundTasks

4. バックグラウンドで実行する処理を登録する

AppDelegateのapplication(_:didFinishLaunchingWithOptions:launchOptions:)メソッド内でBGTaskSchedulerregisterメソッドを呼び、手順2でInfo.plistに定義したタスクidentifierと、バックグラウンドで実行したい処理のブロックを渡します。

BGTaskScheduler.shared.register(
    forTaskWithIdentifier: appRefreshTaskId, using: nil) { task in
    
    ...
    
    task.setTaskCompleted(success: true)    
}
    
BGTaskScheduler.shared.register(
    forTaskWithIdentifier: processingTaskId, using: nil) { task in
    
    ...
    
    task.setTaskCompleted(success: true)    
}

5. リクエストを作成し、送信する

BGTaskRequestオブジェクトを初期化し、BGTaskSchedulersubmitするメソッドを実装しておき、

private func scheduleProcessingBGTasks() {
    let request = BGProcessingTaskRequest(identifier: processingTaskId)
    request.earliestBeginDate = Date(timeIntervalSinceNow: 20 * 60)
    request.requiresNetworkConnectivity = false
    request.requiresExternalPower = false
    try! BGTaskScheduler.shared.submit(request)
}

private func scheduleAppRefreshBGTasks() {
    let request = BGAppRefreshTaskRequest(identifier: appRefreshTaskId)
    request.earliestBeginDate = Date(timeIntervalSinceNow: 10 * 60)
    try! BGTaskScheduler.shared.submit(request)
}

アプリがバックグラウンドに回った時にこれらのメソッドを呼びます。

func applicationDidEnterBackground(_ application: UIApplication) {
    scheduleAppRefreshBGTasks()
    scheduleProcessingBGTasks()
}

以上で、システムにより適当なタイミングでバックグラウンドで処理が実行されるようになります。

submitされているタスクの一覧を取得する

BGTaskSchedulergetPendingTaskRequestsメソッドを用いて、submitされてまだ実行されていないタスクリクエストの一覧を取得できます。

func getPendingTaskRequests(completionHandler: @escaping ([BGTaskRequest])
    -> Void)

次のように使用します。

BGTaskScheduler.shared.getPendingTaskRequests { requests in
    print("pending task requests:\(requests)")
}

タスクの最大数

同時にスケジューリングできるタスクの数は、AppRefreshが1つ、Processingタスクが10まで、とされています。これを超えてsubmitしようとすると、BGTaskScheduler.Error.Code.tooManyPendingTaskRequestsエラーが返ってきます。[4]

There can be a total of 1 refresh task and 10 processing tasks scheduled at any time.

バックグラウンド処理のテスト

バックグラウンド処理が実行されるタイミングはシステム任せのため、テストやデバッグがしづらいケースもあります。そのため、開発中だけ使用する想定で、submit済みのバックグラウンドタスクを強制的に実行開始/停止する方法が用意されています。[5]

そのうち、強制的にバックグラウンドタスクを開始する手順を紹介します。

タスクを強制発火する

1. submit完了後の行にブレークポイントを張る

2. アプリを開始し、1のブレークポイントで止める

3. デバッガに次のコードを打ち込んで実行する

e -l objc -- (void)[[BGTaskScheduler sharedScheduler] 
 _simulateLaunchForTaskWithIdentifier:@"TASK_IDENTIFIER"]

TASK_IDENTIFIERの部分は実行したいバックグラウンドタスクのidentifierと置き換える)

4. アプリを再開する(→ アプリがバックグラウンドで起こされ、タスクが開始される)

iOS 26 でのアップデート

WWDC25 の "Finish tasks in the background" セッションより。

https://developer.apple.com/videos/play/wwdc2025/227/?time=678

こちらのXのツリーより転載:
https://x.com/shu223/status/1933651544400146927

BContinuedProcessingTask

BContinuedProcessingTask というのが今回追加された新API。バックグラウンドで、ファイルのエクスポートやSNSへの投稿等、進捗と終了が明確にわかるタスクを行わせることができる、というもの。

こういうUIが表示され、ユーザーは進行状況を確認でき、いつでもキャンセルできる:

ユースケース

こういうふうに使え/こういうふうに使うな、のリスト:

実装手順

バックグラウンドでのGPU利用

このバックグラウンドでの継続処理タスクでGPUを利用することもできる:

脚注
  1. https://developer.apple.com/documentation/BackgroundTasks/bgapprefreshtask ↩︎

  2. https://developer.apple.com/documentation/BackgroundTasks/bgprocessingtask ↩︎

  3. UIApplicationDelegateapplication(_:performFetchWithCompletionHandler:)がiOS 13からDeprecatedになりました。 ↩︎

  4. https://developer.apple.com/documentation/BackgroundTasks/bgtaskscheduler/3142252-submit ↩︎

  5. Starting and Terminating Tasks During Development ↩︎

Discussion