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 — рекомендований API для фонових завдань на Android з гарантією виконання
  • Обмеження — обидві платформи посилюють правила фонової роботи для економії батареї

Background — основи фонового стану

Background — стан додатка, в якому він продовжує існувати в операційній системі, виконувати код та споживати ресурси, але не відображається на екрані пристрою. Користувач знаходиться на головному екрані, в іншому додатку або екран пристрою заблоковано. На iOS Background слідує за Inactive — ланцюжок переходу: Active → Inactive → Background. На Android onStop сигналізує про перехід Activity у Background.

Обидві платформи накладають суворі обмеження на фонову роботу. iOS надає обмежене вікно (зазвичай 30 секунд) для виконання коду після переходу в Background, після чого додаток переводиться в 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 гарантує виконання
Потрібен дозвілТак — capabilities в Info.plistТак — FOREGROUND_SERVICE дозвіл
Наступний станSuspended → Not RunningNot Running (або перезапуск)

Background на iOS: Swift, beginBackgroundTask та BGTaskScheduler

На iOS Background обробляється через метод делегата applicationDidEnterBackground. У цьому методі розробник повинен зберегти стан користувача, звільнити ресурси та завершити фонові завдання. Для виконання коду після переходу в Background використовується beginBackgroundTask(expirationHandler:) — API, який запитує у системи додатковий час (зазвичай 30 секунд). Якщо завдання не завершується за цей час, викликається expirationHandler, і додаток примусово переводиться в Suspended.

З iOS 13 Apple представила BGTaskScheduler — сучасний API для планування фонових завдань. На відміну від beginBackgroundTask, який дає час тільки на завершення після переходу в фон, BGTaskScheduler дозволяє запланувати виконання завдань у майбутньому — наприклад, оновлення контенту раз на годину або вивантаження аналітики вночі. 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)
        }
    }
}

У коді показана повна обробка Background на iOS. applicationDidEnterBackground запускає фонове завдання через beginBackgroundTask з таймаутом та expirationHandler. Паралельно реєструється BGTaskScheduler для періодичного оновлення контенту. beginBackgroundTask використовується для негайного завершення роботи, BGTaskScheduler — для довгострокового планування. Обидва API вимагають правильного управління ідентифікаторами завдань.

Background на Android: 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. SyncService — Foreground Service з повідомленням для негайної та довгої фонової роботи. DataSyncWorker — WorkManager для відкладених завдань з умовами (Wi-Fi, зарядка). WorkManager гарантує виконання навіть при перезавантаженні пристрою та підтримує exponential backoff для повторних спроб. Foreground Service вимагає постійного повідомлення в статус-барі.

Обмеження фонової роботи на iOS та Android

Обидві мобільні платформи постійно посилюють правила фонової роботи. На iOS кожне нове покоління ОС скорочує час роботи в фоновому режимі та додає нові обмеження. На 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, Battery Optimization
ПлануванняBGTaskScheduler (iOS 13+)WorkManager (Android Jetpack)
Після перезавантаженняТільки push-повідомленняWorkManager зберігає завдання
Макс. час виконання~30 хвилин (аудіо)Необмежено (Foreground Service)

Найкращі практики фонової роботи

Перше правило — мінімізуйте споживання ресурсів у фоновому режимі. Більшість фонових завдань можна відкласти на час, коли пристрій заряджається та підключений до Wi-Fi. Використовуйте BGTaskScheduler (iOS) та WorkManager (Android) для планування завдань з умовами. Не запускайте важкі обчислення у фоновому режимі — це розряджає батарею та призводить до троттлінгу CPU.

Друге правило — завжди вказуйте expirationHandler для beginBackgroundTask. Якщо додаток не завершить завдання у відведений час, система примусово переведе його в Suspended або завершить. ExpirationHandler — останній шанс зберегти дані та коректно завершити роботу. На Android використовуйте setForegroundAsync в WorkManager для перетворення звичайного завдання на передній план, якщо потрібно більше часу.

Третє правило — перевіряйте обмеження фонової роботи перед запуском. На iOS використовуйте UIApplication.shared.backgroundTimeRemaining для перевірки часу, що залишився. На Android перевірте ActivityManager.isBackgroundRestricted() — якщо true, додаток не зможе запускати фонові завдання, і потрібно запропонувати користувачу зняти обмеження в налаштуваннях. Це особливо важливо для додатків з критичними фоновими функціями — будильники, календарі, синхронізація.

Четверте правило — тестуйте фонові завдання на реальному пристрої. Симулятор та емулятор не відтворюють реальні обмеження фонової роботи. На iOS використовуйте Debug → Simulate Background Fetch в Xcode. На Android — adb shell am broadcast -a android.intent.action.ACTION_BOOT_COMPLETED для тестування WorkManager після перезавантаження. Реальні тести на пристрої з низьким зарядом батареї виявляють більшість проблем фонової роботи.

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 — синхронний API для продовження життя додатка на ~30 секунд після переходу в фон. Викликається в applicationDidEnterBackground. BGTaskScheduler — асинхронний API для планування завдань у майбутньому через системні тригери (час, місцезнаходження, оновлення контенту). BGTaskScheduler — сучасний підхід, рекомендований Apple для iOS 13+.

Чому Android вбиває мій Background Service?

Починаючи з Android 8 (API 26), Background Service завершується через кілька хвилин після переходу додатка в фон. Рішення: використовуйте Foreground Service з повідомленням для довгих операцій або WorkManager для відкладених завдань. Перевірте Battery Optimization для вашого додатка в налаштуваннях — якщо воно оптимізоване, система може відкласти або скасувати фонові завдання.

Як протестувати Background на симуляторі iOS?

Натисніть Cmd+Shift+H для переходу на головний екран. В Xcode використовуйте Debug → Simulate Background Fetch. Для перевірки beginBackgroundTask відкрийте консоль (Shift+Cmd+C) та викличте e UIApplication.shared.backgroundTimeRemaining. В Xcode 15+ доступний сценарій Background Execution у вкладці Diagnostics симулятора.

Що таке process death на Android?

Process Death — завершення процесу Android системою при нестачі ресурсів або при бездіяльності у фоновому режимі. На відміну від iOS, Android не має Suspended — процес або живий (може бути в фоновому режимі), або мертвий (Not Running). Process Death — нормальна поведінка ОС, і додаток повинен коректно відновлювати стан після нього через 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 створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також