LASSIC Media らしくメディア
アプリのバックグラウンド遅延実行の実装
LASSIC IT事業部|元請(プライムベンダー)としてシステム保守・運用を受託
この記事のポイント
- バックグラウンド遅延実行とは、アプリが前面にない間の同期・アップロード・定期メンテをOSがタイミングを判断してまとめて実行する仕組みです。
- AndroidはWorkManager、iOSはBGTaskSchedulerという別々のOS標準APIで実装する必要があり、設計思想も制約も異なります。
- 実行時刻をOSが裁量する特性上、要件定義段階での制約設計を誤ると「動くはずが動かない」不具合につながりやすく、外注・内製の判断が重要になります。
目次
バックグラウンド遅延実行とは何か
バックグラウンド遅延実行(deferrable background work)とは、アプリが前面にない間に発生する同期・アップロード・定期メンテナンスなどの処理を、即座にではなくOSが都合の良いタイミングでまとめて実行させる仕組みを指します*1。ユーザーがアプリを操作していない時間帯でも、ネットワーク状態やバッテリー残量など複数の条件がそろった瞬間にOSがアプリを起動し、登録済みの処理を代行します。
本稿で扱うのは、あくまでこの「遅延実行」の領域です。ユーザーに常に可視の状態で継続動作させる処理(音楽再生・位置情報の常時取得など)は、Foreground ServiceやiOSのBackground Modesを用いた「フォアグラウンド常駐処理」であり、別稿で解説しています。両者は目的も実装APIもまったく異なるため、要件定義の段階で混同しないことが重要です。
また、オフラインファースト設計におけるデータ同期戦略やコンフリクト解決とも区別が必要です。本稿はその同期処理を「いつ・どの条件で起動するか」というOS標準のスケジューリングAPI(WorkManager・BGTaskScheduler)の実装論点に絞って解説します。
バックグラウンド遅延実行を使う典型的な用途は、サーバーとのデータ同期、ログ・画像のアップロード、キャッシュのクリーンアップ、通知内容の事前取得などです。いずれも「ユーザーが今すぐ結果を見るわけではないが、次にアプリを開いたときには終わっていてほしい」処理という共通点があります*1。
Android WorkManagerの実装論点
Android開発では、Google推奨のバックグラウンド遅延実行APIとしてJetpack WorkManagerが提供されています*1。WorkManagerは1回限りの処理を扱うOneTimeWorkRequestと、一定間隔で繰り返すPeriodicWorkRequestの2種類のリクエストを用意しており、用途に応じて使い分けます*1。
Constraints(制約)は、処理を実行してよい条件を宣言的に指定する仕組みです。ネットワーク種別(従量制回線を避けるUNMETERED等)、充電中か否か、端末のアイドル状態、ストレージ空き容量などを組み合わせて指定でき、複数の制約を設定した場合はすべての条件が満たされたときにのみ実行されます*1。この「AND条件」である点は設計時に見落とされやすく、意図せず実行タイミングが遅れる原因になります。
失敗時のリトライにはBackoffPolicyを使います。再試行までの最小遅延は10秒(MIN_BACKOFF_MILLIS)であり、増加のさせ方はLINEAR(一定量ずつ増加)とEXPONENTIAL(指数関数的に増加、デフォルト)の2方式から選択します*1。通信エラーが断続的に起きる処理ではEXPONENTIALを選び、サーバー負荷を抑えながら再試行するのが基本的な設計です。
PeriodicWorkRequestには最小繰り返し間隔が定められており、15分(MIN_PERIODIC_INTERVAL_MILLIS)より短い周期は指定できません*1。これはAndroidのJobSchedulerと同じ制約であり*1、「数分おきに同期したい」という要件はWorkManager単体では実現できない点に注意が必要です。加えて、フレックス期間(flexInterval)を設定すれば、周期の終盤の一定時間内で実行させることも可能です*1。
制約付きのPeriodicWorkRequestでは、周期が経過しても制約条件が満たされない限り実行がスキップされることがあります*1。「充電中のみ実行」という制約を付けたまま端末がずっとバッテリー駆動であれば、その回の同期は行われません。この挙動を理解せずに設計すると、「同期されない」という問い合わせにつながりやすいポイントです。
iOS BGTaskSchedulerの実装論点
iOSでは、iOS 13以降の標準フレームワークであるBackgroundTasksが提供するBGTaskSchedulerを使い、バックグラウンド遅延実行を実装します*2。中心となるのは2種類のリクエストで、短時間の更新処理に使うBGAppRefreshTaskRequestと、数分規模の処理時間を要するメンテナンス・バックアップ・クリーンアップ向けのBGProcessingTaskRequestがあります*3。
実装の流れは大きく2段階です。まずアプリ起動時にBGTaskScheduler.shared.register(forTaskWithIdentifier:using:launchHandler:)で、タスク識別子ごとの処理内容を事前登録します。次に実行してほしいタイミングが来たらsubmit(_:)でリクエストを送信し、OSに実行を依頼する形です*3。
BGAppRefreshTaskRequestにはearliestBeginDateプロパティがあり、「これより前には実行しない」という最早開始時刻を指定できます*4。ただし、これはあくまで下限の指定であり、実際にいつ実行されるかはOSがバッテリー残量・ネットワーク状態・端末の利用状況などを踏まえて決定するため、指定時刻ちょうどの実行は保証されません*3。
BGProcessingTaskRequestでは、requiresNetworkConnectivityでネットワーク接続を必須にするか、requiresExternalPowerで外部電源への接続を必須にするかを指定できます*5。バックアップ処理のように通信量が大きく時間もかかる処理では、これらを組み合わせて夜間の充電中にのみ実行させる設計が一般的です。
実行を任されたタスクには制限時間があり、時間内に処理が終わらない場合に備えてexpirationHandlerを設定し、リソースの後始末を行う必要があります。処理が完了した時点ではsetTaskCompleted(success:)を呼び出し、OSに完了を通知します*6。この呼び出しを忘れると、OSからの評価が下がり以降のスケジューリング機会が減る要因になります。
もう一つ欠かせないのが、Info.plistへの事前登録です。BGTaskSchedulerPermittedIdentifiersキーに、使用するすべてのタスク識別子を配列で登録しておく必要があり*7、ここに含まれない識別子でリクエストを送信すると実行されません。識別子は逆引きDNS形式(例:com.example.app.refresh)での命名が推奨されています*4。
WorkManagerとBGTaskSchedulerの違い
両OSのバックグラウンド遅延実行APIは目的が近い一方で、設計思想や制約の細部が異なります。実装を外注する場合も内製する場合も、この違いを理解したうえで要件を整理しないと、片方のOSだけで通用する前提を両OSに当てはめてしまう失敗が起こります。
| 比較軸 | Android WorkManager | iOS BGTaskScheduler |
|---|---|---|
| トリガの起点 | OneTimeWorkRequest(単発)とPeriodicWorkRequest(定期)を明示的に組み立ててenqueueする*1。 | BGAppRefreshTaskRequest(短時間更新)とBGProcessingTaskRequest(長時間処理)を用途で使い分ける*3。 |
| 制約の指定 | Constraintsでネットワーク種別・充電・アイドル・ストレージ等を指定。複数指定時はAND条件*1。 | requiresNetworkConnectivity・requiresExternalPowerなどBGProcessingTaskRequest側のプロパティで指定*5。 |
| 実行タイミングの保証 | 制約充足後にOSが実行。PeriodicWorkRequestは制約未充足だとその周期をスキップすることがある*1。 | earliestBeginDateは下限の指定に過ぎず、実行時刻そのものはOSが裁量で決定し保証されない*3。 |
| 最小繰り返し間隔 | PeriodicWorkRequestは15分未満を指定できない(MIN_PERIODIC_INTERVAL_MILLIS)*1。 | 固定の最小間隔という概念はなく、OSの学習した利用状況に基づき実行機会そのものが決まる*3。 |
| 事前登録の要否 | AndroidManifest.xmlへの個別宣言は不要。コード内でWorkRequestを組み立てれば動作する。 | Info.plistのBGTaskSchedulerPermittedIdentifiersに識別子を配列登録しておく必要がある*7。 |
| リトライ制御 | BackoffPolicy(LINEAR/EXPONENTIAL)と最小遅延10秒を指定して再試行を制御*1。 | OS標準のリトライ機構はなく、失敗時は次回submitで再登録する設計が必要。 |
実装でつまずきやすい制約とテストの難しさ
バックグラウンド遅延実行の実装で難易度が上がる最も重い要因は、実行タイミングを開発者が制御できないことです。両OSともに「いつ実行されるか」はOS側の裁量に委ねられており、実機での動作確認が本番相当の条件でしか再現しない場面が少なくありません。
設定を誤ると、想定した同期が長時間実行されず、ユーザーからは「アプリが古いデータのまま」という不具合に見えます。たとえばAndroidでPeriodicWorkRequestに複数のConstraintsを重ねすぎると、条件がそろう機会自体が減り、結果として同期頻度が実用に耐えないほど落ちることがあります*1。iOS側でもearliestBeginDateだけを頼りに厳密なスケジュールを組もうとすると、OSの裁量により想定より大幅に遅れて実行される、あるいは実行機会が来ないまま次の起動を迎えるといった事態が起こり得ます*3。
この作業を内製で行うには、Android・iOSそれぞれのOSライフサイクルとバックグラウンド実行モデルの知識に加え、実機での長時間検証、Xcode・Android Studioのデバッグ機能(BGTaskScheduler用のシミュレーションコマンドやWorkManagerのテスト用API)の扱いに慣れたエンジニアが必要です。両OS分の設計・実装・検証を1〜2名で並行対応する場合、単体のUI機能開発と比べて検証工程に要する期間が長くなりやすい点は見積もり時に織り込むべきです。
専門パートナーに依頼した場合と内製で完結させた場合の違いは、主にこの検証工程の設計に表れます。外部委託先に実機検証のノウハウが蓄積されていれば、OS更新に伴う挙動変化(新OSバージョンでの制約強化など)を踏まえた設計の見直しが早く、リリース後の「同期されない」問い合わせを事前に減らせます。内製の場合は、担当者が異動・退職した際にバックグラウンド実行特有の暗黙知が失われるリスクも考慮が必要です。
外注と内製の判断軸
バックグラウンド遅延実行の実装を外注するか内製するかは、主に3つの軸で判断します。第一に、Android・iOS両OSでの実装経験と実機検証体制があるかどうかです。第二に、要件定義の時点で「即時実行ではなく遅延実行である」ことを発注者・開発者双方が正しく合意できているかです。第三に、リリース後の継続的なOSアップデート対応をどちらが担うかという運用面の分担です。
要件定義を誤ると、遅延実行の特性を理解しないまま「リアルタイム同期」を前提にした仕様がそのまま発注書に残るケースがあります。この状態で開発が進むと、納品後に「思ったより同期が遅い」という手戻りが発生し、再設計のための追加工数が発生しかねません。発注前に、対象データの許容遅延時間(数分単位か、数時間単位か)を明確にしておくことが重要です。
また、WorkManagerとBGTaskSchedulerはいずれもOS標準APIであるため、サードパーティ製ライブラリへの依存を最小限にできる利点があります。その一方で、OSのメジャーアップデートごとに制約の挙動が変わる可能性があるため、リリース後も一定期間は保守体制を維持する前提で契約形態を検討する必要があります。
LASSICの支援範囲と進め方
元請(プライムベンダー)としてシステムの保守・運用を受託する立場から見ると、バックグラウンド遅延実行の実装は「作って終わり」ではなく、リリース後のOSアップデート追従までを含めて設計すべき領域です。要件定義の段階で許容遅延時間や実行条件を整理し、Android・iOSそれぞれの実装方針と検証計画を具体化したうえで開発に着手する進め方が有効です。
実装後は、実機での長時間動作検証とログ収集の仕組みを組み込み、リリース後に「同期が実行されているか」を運用側で確認できる状態にしておくことも欠かせません。ここまでを外部パートナーと合意した契約範囲に含めておくと、リリース後の問い合わせ対応もスムーズになります。
まとめ:バックグラウンド遅延実行を外注/内製で判断する3つの軸
本稿では、Androidの WorkManagerとiOSの BGTaskSchedulerによるバックグラウンド遅延実行の実装論点を整理しました。要点を3つに集約すると、第一にWorkManagerとBGTaskSchedulerは目的は近いが制約の指定方法・最小間隔・登録手順が異なること、第二に両OSとも実行タイミングはOSの裁量に委ねられ即時性は保証されないこと、第三に外注/内製の判断は実装経験・要件定義の精度・リリース後の保守体制の3軸で決めるべきことです。フォアグラウンド常駐処理やオフライン同期戦略とは異なる、OS標準スケジューリングAPI特有の設計難度を踏まえて計画することが、リリース後のトラブルを防ぐ鍵になります。
よくある質問
WorkManagerとBGTaskSchedulerは同じ設計で実装できますか。
同じ設計をそのまま流用することはできません。WorkManagerはConstraintsとBackoffPolicyによる制約・再試行制御が中心で、BGTaskSchedulerはBGAppRefreshTaskRequestとBGProcessingTaskRequestの使い分けとInfo.plist登録が前提になるためです*1*3。OSごとに独立した設計・実装・検証が必要です。
バックグラウンド遅延実行の処理を指定時刻ちょうどに実行できますか。
指定時刻ちょうどの実行は保証されません。AndroidのPeriodicWorkRequestは制約が未充足だと周期をスキップすることがあり*1、iOSのearliestBeginDateもあくまで下限の指定でOSが実際の実行時刻を裁量で決めます*3。リアルタイム性が必須の処理には別のアプローチを検討する必要があります。
iOSでバックグラウンド処理を使うために事前に必要な設定はありますか。
Info.plistのBGTaskSchedulerPermittedIdentifiersキーに、使用するすべてのタスク識別子を配列で登録しておく必要があります*7。登録していない識別子でリクエストを送信しても実行されないため、実装初期に識別子の命名規則も含めて確定しておくことをおすすめします。
WorkManagerで数分おきの同期は実現できますか。
実現できません。PeriodicWorkRequestの最小繰り返し間隔は15分と定められており、これより短い周期は指定できない仕様です*1。数分単位の即時性が必要な場合は、遅延実行とは別のプッシュ通知やフォアグラウンド処理の活用を検討する必要があります。
フォアグラウンド常駐処理と何が違いますか。
フォアグラウンド常駐処理はユーザーに可視の状態で継続動作させる処理で、Foreground ServiceやBackground Modesを使います。一方バックグラウンド遅延実行は、アプリが前面にない間の処理をOSが都合の良いタイミングでまとめて実行する仕組みで、WorkManagerやBGTaskSchedulerを使う点が異なります。目的に応じて実装APIを使い分ける必要があります。
著者:テレリモ総研編集部 鈴木 亮佑
ご不明な点はお問い合わせフォームからもご連絡いただけます。
- *1 出典:Android Developers「Define work requests」
- *2 出典:Apple Developer Documentation「Background Tasks」
- *3 出典:Apple Developer Documentation「BGTaskScheduler」
- *4 出典:Apple Developer Documentation「BGAppRefreshTaskRequest」
- *5 出典:Apple Developer Documentation「BGProcessingTaskRequest」
- *6 出典:Apple Developer Documentation「BGAppRefreshTask」
- *7 出典:Apple Developer Documentation「BGTaskSchedulerPermittedIdentifiers」