Background — состояние жизненного цикла приложения, в котором оно продолжает выполняться, но не отображается на экране. Объясняем основы фоновой работы на iOS и Android: ограничения, таймауты, фоновые задачи через beginBackgroundTask, WorkManager и Service, а также лучшие практики для корректной обработки Background.
Главное
Background — состояние приложения, в котором оно продолжает существовать в операционной системе, выполнять код и потреблять ресурсы, но не отображается на экране устройства. Пользователь находится на Home Screen, в другом приложении или экран устройства заблокирован. На 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 и Suspended. Background — приложение активно выполняет код. Suspended — приложение находится в памяти, но не выполняет код — оно заморожено. На iOS приложение переходит из Background в Suspended после завершения фоновых задач. На Android нет Suspended — процесс либо существует (включая Background), либо завершён (Not Running). Однако Android может приостановить выполнение потоков через LMK (Low Memory Killer).
| Характеристика | iOS Background | Android Background |
|---|---|---|
| Код выполняется | Да, до 30 секунд | Да, зависит от API |
| UI видим | Нет | Нет |
| Таймаут по умолчанию | ~30 сек (beginBackgroundTask) | Несколько минут (Service) |
| Неограниченная работа | Только специальные категории (аудио, VoIP, навигация) | Foreground Service с уведомлением |
| Гарантия выполнения | Нет — система может завершить в любой момент | WorkManager гарантирует выполнение |
| Требуется разрешение | Да — capabilities в Info.plist | Да — FOREGROUND_SERVICE пермишен |
| Следующее состояние | Suspended → Not Running | Not Running (или restart) |
В iOS Background обрабатывается через метод делегата applicationDidEnterBackground. В этом методе разработчик должен сохранить состояние пользователя, освободить ресурсы и завершить фоновые задачи. Для выполнения кода после ухода в Background используется beginBackgroundTask(expirationHandler:) — API, который запрашивает у системы дополнительное время (обычно 30 секунд). Если задача не завершается за это время, вызывается expirationHandler, и приложение принудительно переводится в Suspended.
С iOS 13 Apple представила BGTaskScheduler — современный API для планирования фоновых задач. В отличие от beginBackgroundTask, который даёт время только на завершение после ухода в фон, BGTaskScheduler позволяет запланировать выполнение задач в будущем — например, обновление контента раз в час или выгрузку аналитики ночью. BGTaskScheduler — рекомендуемый подход для новых проектов, так как он более эффективен с точки зрения батареи.
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 требуют правильного управления идентификаторами задач.
В Android Background управляется через несколько API. Традиционный Service позволяет выполнять код в фоне, но с Android 8+ (API 26) Background Service ограничен: система завершает его через несколько минут после ухода приложения в фон. Foreground Service с постоянным уведомлением может работать неограниченно долго. WorkManager — рекомендуемое решение для фоновых задач с гарантией выполнения даже после перезагрузки устройства.
Android, в отличие от iOS, поддерживает долгоживущие фоновые процессы. Foreground Service используется для задач, которые пользователь должен видеть — воспроизведение музыки, навигация, запись тренировки. JobScheduler и WorkManager — для задач, которые могут быть отложены: синхронизация данных, выгрузка логов, обновление кеша. Ключевое отличие: Android позволяет планировать задачи с условиями — Wi-Fi, зарядка, неактивность устройства, что экономит батарею и трафик.
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 Google вводит всё более строгие режимы энергосбережения (Doze, App Standby). Разработчик должен быть в курсе актуальных ограничений, чтобы приложение не было завершено системой преждевременно.
На iOS, начиная с iOS 13, система отключает фоновые задачи для приложений, которые злоупотребляют фоновым временем. Каждое приложение получает определённые лимиты на основе поведения пользователя. BGTaskScheduler планирует выполнение на оптимальное время — например, когда устройство подключено к Wi-Fi и заряжается. Приложения, которые корректно используют BGTaskScheduler, получают больше фонового времени.
На Android начиная с Android 9 (API 28) фоновая работа ограничена режимом Doze, который активируется при бездействии устройства. Приложения в Doze не могут выполнять фоновые задачи, сеть отключается, JobScheduler и WorkManager откладывают задачи до выхода из Doze. Foreground Service — единственный способ обойти Doze, но злоупотребление приводит к блокировке приложения пользователем и удалению разрешений.
| Ограничение | iOS | Android |
|---|---|---|
| Таймаут фоновой задачи | ~30 секунд (beginBackgroundTask) | Несколько минут (JobScheduler) |
| Неограниченный фон | Аудио, VoIP, навигация, Bluetooth | Foreground 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 для преобразования обычной задачи в foreground, если требуется больше времени.
Третье правило — проверяйте ограничения фоновой работы перед запуском. На 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 после перезагрузки. Реальные тесты на устройстве с низким зарядом батареи выявляют большинство проблем фоновой работы.
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 возвращает количество секунд до принудительного завершения — если значение бесконечно, приложение работает без ограничения (аудио, навигация). Менеджер позволяет запускать несколько фоновых задач с разными именами и корректно завершать каждую. Такой подход предотвращает утечку фоновых задач и гарантирует, что система не завершит приложение из-за незакрытых задач.
Часто задаваемые вопросы
Да, для ограниченного числа категорий: аудио (AVAudioSession категория .playback), VoIP (PushKit), навигация (CLLocationManager с allowsBackgroundLocationUpdates), Bluetooth (central background mode), фоновое обновление (BGTaskScheduler). Для всех остальных — максимум 30 секунд. В iOS 16+ Apple ужесточила требования даже для разрешённых категорий.
beginBackgroundTask — синхронный API для продления жизни приложения на ~30 секунд после ухода в фон. Вызывается в applicationDidEnterBackground. BGTaskScheduler — асинхронный API для планирования задач в будущем через системные триггеры (время, местоположение, обновление контента). BGTaskScheduler — современный подход, рекомендуемый Apple для iOS 13+.
Начиная с Android 8 (API 26), Background Service завершается через несколько минут после ухода приложения в фон. Решение: используйте Foreground Service с уведомлением для долгих операций или WorkManager для отложенных задач. Проверьте Battery Optimization для вашего приложения в настройках — если оно оптимизировано, система может отложить или отменить фоновые задачи.
Нажмите Cmd+Shift+H для перехода на Home Screen. В Xcode используйте Debug → Simulate Background Fetch. Для проверки beginBackgroundTask откройте консоль (Shift+Cmd+C) и вызовите e UIApplication.shared.backgroundTimeRemaining. В Xcode 15+ доступен Background Execution сценарий в Diagnostics tab симулятора.
Process Death — завершение процесса Android системой при нехватке ресурсов или при простое в фоне. В отличие от iOS, Android не имеет Suspended — процесс либо жив (может быть в фоне), либо мёртв (Not Running). Process Death — нормальное поведение ОС, и приложение должно корректно восстанавливать состояние после него через SavedStateHandle, onSaveInstanceState или DataStore.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также