Background — starea ciclului de viață al aplicației în care aceasta continuă să ruleze, dar nu este afișată pe ecran. Explicăm noțiunile de bază ale lucrului în fundal pe iOS și Android: restricții, timeout-uri, sarcini în fundal prin beginBackgroundTask, WorkManager și Service, precum și cele mai bune practici pentru procesarea corectă a Background.
Principalele puncte
Background — starea aplicației în care aceasta continuă să existe în sistemul de operare, să execute cod și să consume resurse, dar nu este afișată pe ecranul dispozitivului. Utilizatorul se află pe Ecranul de pornire, într-o altă aplicație sau ecranul dispozitivului este blocat. Pe iOS Background urmează după Inactive — lanțul de tranziție: Active → Inactive → Background. Pe Android onStop semnalează trecerea Activity în Background.
Ambele platforme impun restricții stricte asupra lucrului în fundal. iOS oferă o fereastră limitată (de obicei 30 de secunde) pentru executarea codului după trecerea în Background, după care aplicația este trecută în Suspended. Android este mai flexibil: Foreground Service cu notificare vizibilă poate funcționa nelimitat, dar Background Service obișnuit este limitat la câteva minute. Sarcina cheie a dezvoltatorului — să salveze corect starea și să planifice continuarea lucrului prin API-urile sistemice de sarcini în fundal.
Sistemul poate termina aplicația în fundal în orice moment când memoria este insuficientă. La terminare, toate datele nesalvate se pierd. De aceea este critic să salvați starea în applicationDidEnterBackground (iOS) sau onStop (Android). După terminare, la următoarea pornire aplicația pornește din Not Running cu un start la rece și restabilește starea salvată.
Este important să distingeți Background și Suspended. Background — aplicația execută activ cod. Suspended — aplicația se află în memorie, dar nu execută cod — este înghețată. Pe iOS aplicația trece din Background în Suspended după finalizarea sarcinilor în fundal. Pe Android nu există Suspended — procesul fie există (inclusiv în fundal), fie este terminat (Not Running). Totuși, Android poate suspenda execuția thread-urilor prin LMK (Low Memory Killer).
| Caracteristică | iOS Background | Android Background |
|---|---|---|
| Codul se execută | Da, până la 30 de secunde | Da, depinde de API |
| UI vizibil | Nu | Nu |
| Timeout implicit | ~30 sec (beginBackgroundTask) | Câteva minute (Service) |
| Lucru nelimitat | Doar categorii speciale (audio, VoIP, navigație) | Foreground Service cu notificare |
| Garanție de execuție | Nu — sistemul poate termina oricând | WorkManager garantează execuția |
| Necesită permisiune | Da — capabilities în Info.plist | Da — permisiunea FOREGROUND_SERVICE |
| Starea următoare | Suspended → Not Running | Not Running (sau restart) |
În iOS Background este gestionat prin metoda delegat applicationDidEnterBackground. În această metodă, dezvoltatorul trebuie să salveze starea utilizatorului, să elibereze resursele și să finalizeze sarcinile în fundal. Pentru executarea codului după trecerea în Background se folosește beginBackgroundTask(expirationHandler:) — API care solicită sistemului timp suplimentar (de obicei 30 de secunde). Dacă sarcina nu se finalizează în acest timp, expirationHandler este apelat, iar aplicația este trecută forțat în Suspended.
Începând cu iOS 13, Apple a introdus BGTaskScheduler — un API modern pentru planificarea sarcinilor în fundal. Spre deosebire de beginBackgroundTask, care oferă timp doar pentru finalizare după trecerea în fundal, BGTaskScheduler permite planificarea executării sarcinilor în viitor — de exemplu, actualizarea conținutului o dată pe oră sau încărcarea analiticelor noaptea. BGTaskScheduler este abordarea recomandată pentru proiecte noi, deoarece este mai eficient din punct de vedere al bateriei.
import UIKit
import BackgroundTasks
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
// Aplicația a intrat în fundal — începem sarcina în fundal
func applicationDidEnterBackground(_ application: UIApplication) {
saveAppState()
startBackgroundTask()
}
private func startBackgroundTask() {
backgroundTaskID = UIApplication.shared.beginBackgroundTask { [weak self] in
// Timpul a expirat — forțăm finalizarea
self?.endBackgroundTask()
}
// Simulăm lucrul în fundal (salvarea datelor pe server)
DispatchQueue.global().async { [weak self] in
uploadAnalyticsData()
self?.endBackgroundTask()
}
}
private func endBackgroundTask() {
guard backgroundTaskID != .invalid else { return }
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// Înregistrare 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)
}
}
}Codul arată gestionarea completă a Background pe iOS. applicationDidEnterBackground pornește o sarcină în fundal prin beginBackgroundTask cu timeout și expirationHandler. În paralel, BGTaskScheduler este înregistrat pentru actualizarea periodică a conținutului. beginBackgroundTask este folosit pentru finalizarea imediată a lucrului, BGTaskScheduler — pentru planificarea pe termen lung. Ambele API necesită gestionarea corectă a identificatorilor de sarcini.
În Android Background este gestionat prin mai multe API-uri. Service tradițional permite executarea codului în fundal, dar din Android 8+ (API 26) Background Service este limitat: sistemul îl termină la câteva minute după ce aplicația trece în fundal. Foreground Service cu notificare permanentă poate funcționa nelimitat. WorkManager — soluția recomandată pentru sarcini în fundal cu garanție de execuție chiar și după repornirea dispozitivului.
Android, spre deosebire de iOS, suportă procese de fundal de lungă durată. Foreground Service este folosit pentru sarcini pe care utilizatorul trebuie să le vadă — redarea muzicii, navigația, înregistrarea antrenamentului. JobScheduler și WorkManager — pentru sarcini care pot fi amânate: sincronizarea datelor, încărcarea logurilor, actualizarea cache-ului. Diferența cheie: Android permite planificarea sarcinilor cu condiții — Wi-Fi, încărcare, inactivitatea dispozitivului, ceea ce economisește bateria și traficul.
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.work.*
// 1. Foreground Service pentru lucru lung în fundal
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 {
// Sincronizarea datelor cu serverul
syncDataToServer()
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
}.start()
}
override fun onBind(intent: Intent?): IBinder? = null
}
// 2. WorkManager pentru sarcini amânate în fundal
class DataSyncWorker(
private val context: Context,
private val params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
// Încărcarea analiticelor pe server
uploadAnalytics()
Result.success()
} catch (e: Exception) {
if (runAttemptCount < 3) Result.retry() else Result.failure()
}
}
}
// Planificarea sarcinii 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)
}Codul arată două abordări pentru lucrul în fundal pe Android. SyncService — Foreground Service cu notificare pentru lucru imediat și lung în fundal. DataSyncWorker — WorkManager pentru sarcini amânate cu condiții (Wi-Fi, încărcare). WorkManager garantează execuția chiar și după repornirea dispozitivului și suportă exponential backoff pentru reîncercări. Foreground Service necesită o notificare permanentă în bara de status.
Ambele platforme mobile înăspresc constant regulile de lucru în fundal. Pe iOS fiecare nouă generație de sistem de operare reduce timpul de lucru în fundal și adaugă restricții noi. Pe Android Google introduce moduri de economisire a energiei din ce în ce mai stricte (Doze, App Standby). Dezvoltatorul trebuie să fie la curent cu restricțiile actuale pentru ca aplicația să nu fie terminată prematur de sistem.
Pe iOS, începând cu iOS 13, sistemul dezactivează sarcinile în fundal pentru aplicațiile care abuzează de timpul în fundal. Fiecare aplicație primește limite specifice bazate pe comportamentul utilizatorului. BGTaskScheduler planifică execuția la momentul optim — de exemplu, când dispozitivul este conectat la Wi-Fi și se încarcă. Aplicațiile care folosesc corect BGTaskScheduler primesc mai mult timp în fundal.
Pe Android, începând cu Android 9 (API 28), lucrul în fundal este limitat de modul Doze, care se activează la inactivitatea dispozitivului. Aplicațiile în Doze nu pot executa sarcini în fundal, rețeaua este dezactivată, JobScheduler și WorkManager amână sarcinile până la ieșirea din Doze. Foreground Service este singura modalitate de a ocoli Doze, dar abuzul duce la blocarea aplicației de către utilizator și eliminarea permisiunilor.
| Restricție | iOS | Android |
|---|---|---|
| Timeout sarcină în fundal | ~30 secunde (beginBackgroundTask) | Câteva minute (JobScheduler) |
| Fundal nelimitat | Audio, VoIP, navigație, Bluetooth | Foreground Service + notificare |
| Economisire energie | Low Power Mode — dezactivează sarcinile în fundal | Doze, App Standby, Battery Optimization |
| Planificare | BGTaskScheduler (iOS 13+) | WorkManager (Android Jetpack) |
| După repornire | Doar notificare push | WorkManager păstrează sarcinile |
| Timp max. de execuție | ~30 minute (audio) | Nelimitat (Foreground Service) |
Prima regulă — minimizați consumul de resurse în fundal. Majoritatea sarcinilor în fundal pot fi amânate pentru momentul când dispozitivul se încarcă și este conectat la Wi-Fi. Folosiți BGTaskScheduler (iOS) și WorkManager (Android) pentru planificarea sarcinilor cu condiții. Nu rulați calcule grele în fundal — acest lucru descarcă bateria și duce la throttling-ul CPU.
A doua regulă — specificați întotdeauna expirationHandler pentru beginBackgroundTask. Dacă aplicația nu finalizează sarcina în timpul alocat, sistemul o va trece forțat în Suspended sau o va termina. ExpirationHandler este ultima șansă de a salva datele și de a finaliza corect lucrul. Pe Android folosiți setForegroundAsync în WorkManager pentru a transforma o sarcină obișnuită în foreground, dacă este necesar mai mult timp.
A treia regulă — verificați restricțiile de lucru în fundal înainte de pornire. Pe iOS folosiți UIApplication.shared.backgroundTimeRemaining pentru a verifica timpul rămas. Pe Android verificați ActivityManager.isBackgroundRestricted() — dacă este true, aplicația nu va putea rula sarcini în fundal și trebuie să sugerați utilizatorului să elimine restricțiile în setări. Acest lucru este deosebit de important pentru aplicațiile cu funcții critice în fundal — ceasuri deșteptătoare, calendare, sincronizare.
A patra regulă — testați sarcinile în fundal pe un dispozitiv real. Simulatorul și emulatorul nu reproduc restricțiile reale de lucru în fundal. Pe iOS folosiți Debug → Simulate Background Fetch în Xcode. Pe Android — adb shell am broadcast -a android.intent.action.ACTION_BOOT_COMPLETED pentru testarea WorkManager după repornire. Testele reale pe un dispozitiv cu baterie scăzută dezvăluie majoritatea problemelor de lucru în fundal.
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("Timp rămas în fundal: \(remaining) sec")
let task = UIApplication.shared.beginBackgroundTask { [weak self] in
print("Timpul a expirat pentru sarcina: \(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)
}
}Codul arată un manager de sarcini în fundal care urmărește timpul rămas și gestionează identificatorii. backgroundTimeRemaining returnează numărul de secunde până la terminarea forțată — dacă valoarea este infinită, aplicația funcționează fără restricții (audio, navigație). Managerul permite rularea mai multor sarcini în fundal cu nume diferite și finalizarea corectă a fiecăreia. Această abordare previne scurgerea sarcinilor în fundal și garantează că sistemul nu va termina aplicația din cauza sarcinilor neînchise.
Întrebări frecvente
Da, pentru un număr limitat de categorii: audio (AVAudioSession categoria .playback), VoIP (PushKit), navigație (CLLocationManager cu allowsBackgroundLocationUpdates), Bluetooth (mod fundal central), actualizare în fundal (BGTaskScheduler). Pentru toate celelalte — maximum 30 de secunde. În iOS 16+ Apple a înăsprit cerințele chiar și pentru categoriile permise.
beginBackgroundTask — API sincron pentru prelungirea vieții aplicației cu ~30 de secunde după trecerea în fundal. Se apelează în applicationDidEnterBackground. BGTaskScheduler — API asincron pentru planificarea sarcinilor în viitor prin declanșatoare sistemice (timp, locație, actualizare conținut). BGTaskScheduler este abordarea modernă recomandată de Apple pentru iOS 13+.
Începând cu Android 8 (API 26), Background Service este terminat la câteva minute după ce aplicația trece în fundal. Soluție: folosiți Foreground Service cu notificare pentru operații lungi sau WorkManager pentru sarcini amânate. Verificați Battery Optimization pentru aplicația dvs. în setări — dacă este optimizată, sistemul poate amâna sau anula sarcinile în fundal.
Apăsați Cmd+Shift+H pentru a trece la ecranul de pornire. În Xcode folosiți Debug → Simulate Background Fetch. Pentru a verifica beginBackgroundTask deschideți consola (Shift+Cmd+C) și apelați e UIApplication.shared.backgroundTimeRemaining. În Xcode 15+ este disponibil scenariul Background Execution în fila Diagnostics a simulatorului.
Process Death — terminarea procesului Android de către sistem la insuficiență de resurse sau la inactivitate în fundal. Spre deosebire de iOS, Android nu are Suspended — procesul fie este viu (poate fi în fundal), fie este mort (Not Running). Process Death este un comportament normal al sistemului de operare, iar aplicația trebuie să restabilească corect starea după acesta prin SavedStateHandle, onSaveInstanceState sau DataStore.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și