Background: 基礎、iOSおよびAndroidでのアプリのバックグラウンド動作

著者: IT Sectr 公開日: 2026-03-03 読了時間: 10 分

Backgroundはアプリのライフサイクル状態で、実行を継続しますが画面には表示されません。iOSおよびAndroidでのバックグラウンド作業の基礎を説明します:制限、タイムアウト、beginBackgroundTask、WorkManager、Serviceによるバックグラウンドタスク、およびBackgroundの正しい処理のためのベストプラクティス。

重要ポイント

  • Background — アプリはユーザーに見えませんが、限られた時間コードを実行できます
  • iOSバックグラウンドタスク — beginBackgroundTask(expirationHandler:)は作業完了に最大30秒を提供
  • Android Service — 長時間のバックグラウンド操作には通知付きForeground Service
  • WorkManager — 実行保証付きのAndroidバックグラウンドタスクに推奨されるAPI
  • 制限 — 両プラットフォームともバッテリー節約のためバックグラウンド作業ルールを強化

Background — バックグラウンド状態の基礎

Backgroundはアプリがオペレーティングシステムに存在し続け、コードを実行しリソースを消費しますが、デバイス画面に表示されない状態です。ユーザーはホーム画面、別のアプリにいるか、デバイスの画面がロックされています。iOSでは、BackgroundはInactiveの後に続きます — 遷移チェーン:Active → Inactive → Background。Androidでは、onStopがActivityのBackgroundへの遷移を示します。

両プラットフォームともバックグラウンド作業に厳しい制限を課しています。iOSはBackgroundに入った後、コード実行に限られた時間(通常30秒)を提供し、その後アプリはSuspendedに移行します。Androidはより柔軟で、可視通知付きのForeground Serviceは無制限に実行できますが、通常のBackground Serviceは数分に制限されています。開発者の主要なタスクは、状態を適切に保存し、システムのバックグラウンドタスクAPIを介して作業の継続をスケジュールすることです。

システムはメモリが不足すると、いつでもバックグラウンドアプリを終了できます。終了時、保存されていないデータはすべて失われます。したがって、applicationDidEnterBackground(iOS)またはonStop(Android)で状態を保存することが非常に重要です。終了後、次の起動はNot Runningからコールドスタートで始まり、保存された状態を復元します。

Background vs Suspended

BackgroundとSuspendedを区別することが重要です。Background — アプリがアクティブにコードを実行しています。Suspended — アプリはメモリにありますがコードを実行していません — 凍結されています。iOSでは、アプリはバックグラウンドタスク完了後にBackgroundからSuspendedに移行します。AndroidにはSuspendedはなく、プロセスは存在する(Backgroundを含む)か終了(Not Running)かのいずれかです。ただし、AndroidはLMK(Low Memory Killer)を介してスレッド実行を一時停止できます。

特性iOS BackgroundAndroid Background
コード実行はい、最大30秒はい、APIに依存
UI表示いいえいいえ
デフォルトタイムアウト~30秒(beginBackgroundTask)数分(Service)
無制限作業特別カテゴリのみ(オーディオ、VoIP、ナビ)通知付きForeground Service
実行保証なし — システムがいつでも終了可WorkManagerが実行を保証
権限必要はい — Info.plistのcapabilitiesはい — FOREGROUND_SERVICE権限
次の状態Suspended → Not RunningNot Running(または再起動)

iOSのBackground: Swift、beginBackgroundTaskとBGTaskScheduler

iOSでは、BackgroundはデリゲートメソッドapplicationDidEnterBackgroundを介して処理されます。このメソッドで、開発者はユーザー状態を保存し、リソースを解放し、バックグラウンドタスクを完了する必要があります。Backgroundに入った後にコードを実行するには、beginBackgroundTask(expirationHandler:)を使用します — システムに追加時間(通常30秒)を要求するAPIです。この時間内にタスクが完了しない場合、expirationHandlerが呼び出され、アプリは強制的にSuspendedに移行します。

iOS 13で、AppleはBGTaskSchedulerを導入しました — バックグラウンドタスクをスケジュールするための最新APIです。バックグラウンドに入った後の終了のみに時間を与えるbeginBackgroundTaskとは異なり、BGTaskSchedulerは将来のタスク実行をスケジュールできます — 例えば、1時間に1回のコンテンツ更新や夜間の分析アップロードなど。BGTaskSchedulerは新しいプロジェクトに推奨されるアプローチであり、バッテリー効率が優れています。

swift
import UIKit
import BackgroundTasks

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid

    // アプリがバックグラウンドに移行 — バックグラウンドタスク開始
    func applicationDidEnterBackground(_ application: UIApplication) {
        saveAppState()
        startBackgroundTask()
    }

    private func startBackgroundTask() {
        backgroundTaskID = UIApplication.shared.beginBackgroundTask { [weak self] in
            // 時間切れ — 強制終了
            self?.endBackgroundTask()
        }

        // バックグラウンド作業をシミュレート(サーバーにデータ保存)
        DispatchQueue.global().async { [weak self] in
            uploadAnalyticsData()
            self?.endBackgroundTask()
        }
    }

    private func endBackgroundTask() {
        guard backgroundTaskID != .invalid else { return }
        UIApplication.shared.endBackgroundTask(backgroundTaskID)
        backgroundTaskID = .invalid
    }

    // BGTaskScheduler登録
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        BGTaskScheduler.shared.register(
            forTaskWithIdentifier: "com.example.refresh",
            using: nil
        ) { task in
            handleAppRefresh(task: task as! BGAppRefreshTask)
        }
        return true
    }

    func scheduleAppRefresh() {
        let request = BGAppRefreshTaskRequest(identifier: "com.example.refresh")
        request.earliestBeginDate = Date(timeIntervalSinceNow: 3600)
        try? BGTaskScheduler.shared.submit(request)
    }

    func handleAppRefresh(task: BGAppRefreshTask) {
        scheduleAppRefresh()
        task.expirationHandler = { task.setTaskCompleted(success: false) }
        fetchLatestData { result in
            task.setTaskCompleted(success: result)
        }
    }
}

コードはiOSでの完全なBackground処理を示しています。applicationDidEnterBackgroundは、タイムアウトとexpirationHandler付きでbeginBackgroundTaskを介してバックグラウンドタスクを開始します。同時に、BGTaskSchedulerが定期的なコンテンツ更新のために登録されます。beginBackgroundTaskは即時シャットダウンタスクに使用され、BGTaskSchedulerは長期計画に使用されます。両方のAPIはタスク識別子の適切な管理を必要とします。

AndroidのBackground: Kotlin、Service、WorkManager

Androidでは、Backgroundは複数のAPIを介して管理されます。従来のServiceはバックグラウンドでのコード実行を許可しますが、Android 8+(API 26)以降、Background Serviceは制限されています:アプリがバックグラウンドに入って数分後にシステムが終了します。永続的通知付きのForeground Serviceは無制限に実行できます。WorkManagerは、デバイス再起動後でも実行保証付きのバックグラウンドタスクに推奨されるソリューションです。

AndroidはiOSとは異なり、長時間実行されるバックグラウンドプロセスをサポートしています。Foreground Serviceはユーザーが確認すべきタスク(音楽再生、ナビゲーション、ワークアウト追跡)に使用されます。JobSchedulerとWorkManagerは遅延可能なタスク(データ同期、ログアップロード、キャッシュ更新)に使用されます。主な違い:Androidは条件付き(Wi-Fi、充電中、デバイスアイドル)でタスクをスケジュールでき、バッテリーとトラフィックを節約します。

kotlin
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.work.*

// 1. 長時間バックグラウンド作業のForeground Service
class SyncService : Service() {

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val notification = createNotification()
        startForeground(NOTIFICATION_ID, notification)
        performBackgroundWork()
        return START_STICKY
    }

    private fun performBackgroundWork() {
        Thread {
            // サーバーとのデータ同期
            syncDataToServer()
            stopForeground(STOP_FOREGROUND_REMOVE)
            stopSelf()
        }.start()
    }

    override fun onBind(intent: Intent?): IBinder? = null
}

// 2. 遅延バックグラウンドタスクのWorkManager
class DataSyncWorker(
    private val context: Context,
    private val params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        return try {
            // サーバーへの分析アップロード
            uploadAnalytics()
            Result.success()
        } catch (e: Exception) {
            if (runAttemptCount < 3) Result.retry() else Result.failure()
        }
    }
}

// WorkManagerタスクスケジューリング
fun scheduleBackgroundSync(context: Context) {
    val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresBatteryNotLow(true)
        .build()

    val request = OneTimeWorkRequestBuilder<DataSyncWorker>()
        .setConstraints(constraints)
        .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS)
        .build()

    WorkManager.getInstance(context).enqueue(request)
}

コードはAndroidでのバックグラウンド作業の2つのアプローチを示しています。SyncService — 即時および長時間のバックグラウンド作業のための通知付きForeground Service。DataSyncWorker — 条件付き(Wi-Fi、充電)の遅延タスクのためのWorkManager。WorkManagerはデバイス再起動後でも実行を保証し、再試行の指数バックオフをサポートします。Foreground Serviceはステータスバーに永続的通知が必要です。

iOSとAndroidのバックグラウンド作業の制限

両モバイルプラットフォームともバックグラウンド作業ルールを常に強化しています。iOSでは、OSの新しい世代ごとにバックグラウンド実行時間が短縮され、新しい制限が追加されます。Androidでは、Googleはますます厳格な省電力モード(Doze、App Standby)を導入しています。開発者は現在の制限を把握しておく必要があります。そうしないと、アプリがシステムによって早期に終了される可能性があります。

iOSでは、iOS 13以降、バックグラウンド時間を乱用するアプリに対してシステムがバックグラウンドタスクを無効にします。各アプリはユーザーの行動に基づいて特定の制限を受けます。BGTaskSchedulerは最適な時間(例:デバイスがWi-Fiに接続され充電中)に実行をスケジュールします。BGTaskSchedulerを正しく使用するアプリはより多くのバックグラウンド時間を得られます。

Androidでは、Android 9(API 28)以降、バックグラウンド作業はDozeモードによって制限され、デバイスがアイドル状態のときにアクティブになります。Doze中のアプリはバックグラウンドタスクを実行できず、ネットワークは切断され、JobSchedulerとWorkManagerはDoze終了までタスクを延期します。Foreground ServiceがDozeを回避する唯一の方法ですが、乱用するとユーザーによるアプリのブロックと権限の取り消しにつながります。

制限iOSAndroid
バックグラウンドタスクタイムアウト~30秒(beginBackgroundTask)数分(JobScheduler)
無制限バックグラウンドオーディオ、VoIP、ナビ、BluetoothForeground Service + 通知
省電力Low Power Mode — バックグラウンドタスク無効化Doze、App Standby、バッテリー最適化
スケジューリングBGTaskScheduler(iOS 13+)WorkManager(Android Jetpack)
再起動後プッシュ通知のみWorkManagerがタスクを保持
最大実行時間~30分(オーディオ)無制限(Foreground Service)

バックグラウンド作業のベストプラクティス

第一のルール — バックグラウンドでのリソース消費を最小限にします。ほとんどのバックグラウンドタスクは、デバイスが充電中でWi-Fiに接続されている時間に延期できます。条件付きタスクのスケジュールにはBGTaskScheduler(iOS)とWorkManager(Android)を使用してください。バックグラウンドで重い計算を実行しないでください — バッテリーを消耗し、CPUスロットリングを引き起こします。

第二のルール — beginBackgroundTaskには常にexpirationHandlerを指定してください。アプリが割り当てられた時間内にタスクを完了しない場合、システムは強制的にSuspendedに移行するか終了します。expirationHandlerはデータを保存し作業を適切に終了する最後のチャンスです。Androidでは、WorkManagerでsetForegroundAsyncを使用して、より多くの時間が必要な場合に通常のタスクをフォアグラウンドに変換します。

第三のルール — 起動前にバックグラウンド作業の制限を確認してください。iOSでは、UIApplication.shared.backgroundTimeRemainingを使用して残り時間を確認します。Androidでは、ActivityManager.isBackgroundRestricted()を確認 — trueの場合、アプリはバックグラウンドタスクを実行できないため、設定で制限を解除するようユーザーに提案します。これは重要なバックグラウンド機能を持つアプリにとって特に重要です — アラーム、カレンダー、同期。

第四のルール — 実際のデバイスでバックグラウンドタスクをテストしてください。シミュレータとエミュレータは実際のバックグラウンド作業制限を再現しません。iOSでは、XcodeでDebug → Simulate Background Fetchを使用します。Androidでは、再起動後のWorkManagerテストにadb shell am broadcast -a android.intent.action.ACTION_BOOT_COMPLETEDを使用します。バッテリー残量の少ないデバイスでの実際のテストが、ほとんどのバックグラウンド作業の問題を明らかにします。

swift
import UIKit

final class BackgroundTaskManager {
    static let shared = BackgroundTaskManager()
    private var tasks: [String: UIBackgroundTaskIdentifier] = [:]

    func startTask(name: String, expiration: @escaping () -> Void) {
        let remaining = UIApplication.shared.backgroundTimeRemaining
        print("バックグラウンド残り時間: \(remaining)秒")

        let task = UIApplication.shared.beginBackgroundTask { [weak self] in
            print("タスクの時間切れ: \(name)")
            expiration()
            self?.endTask(name: name)
        }

        tasks[name] = task
    }

    func endTask(name: String) {
        guard let task = tasks.removeValue(forKey: name),
              task != .invalid
        else { return }
        UIApplication.shared.endBackgroundTask(task)
    }
}

コードは残り時間を追跡し識別子を管理するバックグラウンドタスクマネージャーを示しています。backgroundTimeRemainingは強制終了前の秒数を返します — 値が無限の場合、アプリは制限なく実行されています(オーディオ、ナビ)。マネージャーは異なる名前で複数のバックグラウンドタスクを起動し、それぞれを適切に完了できます。このアプローチはバックグラウンドタスクのリークを防ぎ、未完了のタスクのためにシステムがアプリを終了しないようにします。

よくある質問

iOSアプリは永久にバックグラウンドで実行できますか?

はい、限られたカテゴリでのみ可能です:オーディオ(AVAudioSessionカテゴリ.playback)、VoIP(PushKit)、ナビゲーション(CLLocationManagerとallowsBackgroundLocationUpdates)、Bluetooth(central background mode)、バックグラウンド更新(BGTaskScheduler)。その他すべては最大30秒です。iOS 16+では、Appleは許可されたカテゴリでも要件を強化しました。

beginBackgroundTaskとBGTaskSchedulerの違いは?

beginBackgroundTaskは、バックグラウンドに入った後にアプリの寿命を約30秒延ばす同期APIです。applicationDidEnterBackgroundで呼び出されます。BGTaskSchedulerは、システムトリガー(時間、場所、コンテンツ更新)を介して将来のタスクをスケジュールする非同期APIです。BGTaskSchedulerはAppleがiOS 13+に推奨する最新のアプローチです。

AndroidがBackground Serviceを強制終了するのはなぜ?

Android 8(API 26)以降、Background Serviceはアプリがバックグラウンドに入ってから数分後に終了します。解決策:長時間の操作には通知付きのForeground Service、遅延タスクにはWorkManagerを使用してください。設定でアプリのバッテリー最適化を確認 — 最適化されている場合、システムはバックグラウンドタスクを遅延またはキャンセルする可能性があります。

iOSシミュレータでBackgroundをテストするには?

Cmd+Shift+Hを押してホーム画面に移動します。Xcodeで、Debug → Simulate Background Fetchを使用します。beginBackgroundTaskを確認するには、コンソール(Shift+Cmd+C)を開きe UIApplication.shared.backgroundTimeRemainingを呼び出します。Xcode 15+では、シミュレータのDiagnosticsタブでBackground Executionシナリオが利用可能です。

Androidのprocess deathとは?

Process Deathは、リソース不足またはバックグラウンドでのアイドル時にシステムがAndroidプロセスを終了することです。iOSとは異なり、AndroidにはSuspendedはなく、プロセスは生きている(バックグラウンドにできる)か死んでいる(Not Running)かのいずれかです。Process DeathはOSの通常の動作であり、アプリはSavedStateHandle、onSaveInstanceState、またはDataStoreを介して状態を適切に復元する必要があります。

まとめ

  • Background — アプリは画面に表示されないがコードを実行、Suspended(凍結)とは異なる
  • iOS — beginBackgroundTask(最大30秒)と将来のタスク計画のためのBGTaskScheduler
  • Android — 長時間操作にはForeground Service、保証付き遅延タスクにはWorkManager
  • 制限 — 両プラットフォームともルール強化:Doze、Low Power Mode、App Standby
  • 保存 — applicationDidEnterBackgroundとonStopがSuspended/Not Running前の最後の機会
  • スケジューリング — BGTaskSchedulerとWorkManagerは条件付きで動作(Wi-Fi、充電、時間)
  • Foreground Service — 両プラットフォームで無制限バックグラウンド作業の唯一の方法

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください