Background — стање животног циклуса апликације у којем она наставља да се извршава, али се не приказује на екрану. Објашњавамо основе позадинског рада на iOS и Android: ограничења, тајмауте, позадинске задатке путем beginBackgroundTask, WorkManager и Service, као и најбоље праксе за коректну обраду 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 и Suspended. Background — апликација активно извршава код. Suspended — апликација се налази у меморији, али не извршава код — замрзнута је. На iOS-у апликација прелази из Background у Suspended након завршетка позадинских задатака. На Android-у нема Suspended — процес или постоји (укључујући позадину) или је прекинут (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 (или рестарт) |
На 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) за планирање задатака са условима. Не покрећите тешка израчунавања у позадини — то празни батерију и доводи до throttling-а 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 за прелазак на почетни екран. У Xcode-у користите Debug → Simulate Background Fetch. За проверу beginBackgroundTask отворите конзолу (Shift+Cmd+C) и позовите e UIApplication.shared.backgroundTimeRemaining. У Xcode 15+ доступан је Background Execution сценарио у Diagnostics картици симулатора.
Process Death — прекид Android процеса од стране система при недостатку ресурса или при неактивности у позадини. За разлику од iOS-а, Android нема Suspended — процес или постоји (може бити у позадини) или је мртав (Not Running). Process Death је нормално понашање ОС-а и апликација треба правилно да врати стање након њега путем SavedStateHandle, onSaveInstanceState или DataStore-а.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође