Background — de toestand van de levenscyclus van een app waarin deze blijft draaien, maar niet op het scherm wordt weergegeven. We leggen de basis van achtergrondwerk op iOS en Android uit: beperkingen, time-outs, achtergrondtaken via beginBackgroundTask, WorkManager en Service, en de beste praktijken voor correcte verwerking van Background.
Belangrijkste punten
Background — de toestand van de app waarin deze blijft bestaan in het besturingssysteem, code uitvoert en bronnen verbruikt, maar niet wordt weergegeven op het apparaatscherm. De gebruiker bevindt zich op het startscherm, in een andere app of het scherm is vergrendeld. In iOS volgt Background op Inactive — de overgangsketen: Active → Inactive → Background. In Android signaleert onStop de overgang van Activity naar Background.
Beide platforms leggen strikte beperkingen op aan achtergrondwerk. iOS biedt een beperkt venster (meestal 30 seconden) om code uit te voeren na het gaan naar Background, waarna de app naar Suspended gaat. Android is flexibeler: Foreground Service met zichtbare melding kan onbeperkt werken, maar gewone Background Service is beperkt tot enkele minuten. De belangrijkste taak van de ontwikkelaar — de status correct opslaan en voortzetting van het werk plannen via systeem-API's voor achtergrondtaken.
Het systeem kan de achtergrondapp op elk moment beëindigen bij geheugentekort. Bij beëindiging gaan alle niet-opgeslagen gegevens verloren. Daarom is het van cruciaal belang om de status op te slaan in applicationDidEnterBackground (iOS) of onStop (Android). Na beëindiging start de app bij de volgende lancering vanuit Not Running met een koude start en herstelt de opgeslagen status.
Het is belangrijk om Background en Suspended te onderscheiden. Background — de app voert actief code uit. Suspended — de app bevindt zich in het geheugen maar voert geen code uit — hij is bevroren. In iOS gaat de app van Background naar Suspended na voltooiing van achtergrondtaken. In Android bestaat Suspended niet — het proces bestaat (ook op de achtergrond) of is beëindigd (Not Running). Android kan echter de uitvoering van threads onderbreken via LMK (Low Memory Killer).
| Kenmerk | iOS Background | Android Background |
|---|---|---|
| Code wordt uitgevoerd | Ja, tot 30 seconden | Ja, afhankelijk van API |
| UI zichtbaar | Nee | Nee |
| Standaard time-out | ~30 sec (beginBackgroundTask) | Enkele minuten (Service) |
| Onbeperkt werk | Alleen speciale categorieën (audio, VoIP, navigatie) | Foreground Service met melding |
| Uitvoeringsgarantie | Nee — systeem kan op elk moment beëindigen | WorkManager garandeert uitvoering |
| Vereist toestemming | Ja — capabilities in Info.plist | Ja — FOREGROUND_SERVICE toestemming |
| Volgende status | Suspended → Not Running | Not Running (of herstart) |
In iOS wordt Background verwerkt via de delegatemethode applicationDidEnterBackground. In deze methode moet de ontwikkelaar de gebruikersstatus opslaan, bronnen vrijmaken en achtergrondtaken voltooien. Voor het uitvoeren van code na het gaan naar Background wordt beginBackgroundTask(expirationHandler:) gebruikt — een API die extra tijd (meestal 30 seconden) aanvraagt bij het systeem. Als de taak niet binnen deze tijd wordt voltooid, wordt expirationHandler aangeroepen en wordt de app gedwongen naar Suspended overgeschakeld.
Sinds iOS 13 heeft Apple BGTaskScheduler geïntroduceerd — een moderne API voor het plannen van achtergrondtaken. In tegenstelling tot beginBackgroundTask, dat alleen tijd geeft voor voltooiing na het gaan naar de achtergrond, biedt BGTaskScheduler de mogelijkheid om taken in de toekomst te plannen — bijvoorbeeld inhoud eenmaal per uur bijwerken of 's nachts analytics uploaden. BGTaskScheduler is de aanbevolen aanpak voor nieuwe projecten, omdat het efficiënter is voor de batterij.
import UIKit
import BackgroundTasks
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
// App is naar de achtergrond gegaan — starten achtergrondtaak
func applicationDidEnterBackground(_ application: UIApplication) {
saveAppState()
startBackgroundTask()
}
private func startBackgroundTask() {
backgroundTaskID = UIApplication.shared.beginBackgroundTask { [weak self] in
// Tijd verstreken — dwingen af te sluiten
self?.endBackgroundTask()
}
// Simuleren achtergrondwerk (gegevens opslaan op server)
DispatchQueue.global().async { [weak self] in
uploadAnalyticsData()
self?.endBackgroundTask()
}
}
private func endBackgroundTask() {
guard backgroundTaskID != .invalid else { return }
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// Registratie 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)
}
}
}De code toont volledige verwerking van Background in iOS. applicationDidEnterBackground start een achtergrondtaak via beginBackgroundTask met time-out en expirationHandler. Parallel wordt BGTaskScheduler geregistreerd voor periodieke inhoudsupdates. beginBackgroundTask wordt gebruikt voor onmiddellijke voltooiing van het werk, BGTaskScheduler — voor langetermijnplanning. Beide API's vereisen correct beheer van taakidentificatoren.
In Android wordt Background beheerd via verschillende API's. Traditionele Service maakt het mogelijk code op de achtergrond uit te voeren, maar sinds Android 8+ (API 26) is Background Service beperkt: het systeem beëindigt het enkele minuten nadat de app naar de achtergrond gaat. Foreground Service met een permanente melding kan onbeperkt werken. WorkManager — de aanbevolen oplossing voor achtergrondtaken met uitvoeringsgarantie, zelfs na het opnieuw opstarten van het apparaat.
Android ondersteunt, in tegenstelling tot iOS, langdurige achtergrondprocessen. Foreground Service wordt gebruikt voor taken die de gebruiker moet zien — muziek afspelen, navigatie, training opnemen. JobScheduler en WorkManager — voor taken die kunnen worden uitgesteld: gegevens synchroniseren, logs uploaden, cache bijwerken. Het belangrijkste verschil: Android maakt het mogelijk taken met voorwaarden te plannen — Wi-Fi, opladen, inactiviteit van het apparaat, wat batterij en verkeer bespaart.
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.work.*
// 1. Foreground Service voor lang achtergrondwerk
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 {
// Gegevens synchroniseren met server
syncDataToServer()
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
}.start()
}
override fun onBind(intent: Intent?): IBinder? = null
}
// 2. WorkManager voor uitgestelde achtergrondtaken
class DataSyncWorker(
private val context: Context,
private val params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
// Analytics uploaden naar server
uploadAnalytics()
Result.success()
} catch (e: Exception) {
if (runAttemptCount < 3) Result.retry() else Result.failure()
}
}
}
// WorkManager-taak plannen
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)
}De code toont twee benaderingen voor achtergrondwerk in Android. SyncService — Foreground Service met melding voor onmiddellijk en lang achtergrondwerk. DataSyncWorker — WorkManager voor uitgestelde taken met voorwaarden (Wi-Fi, opladen). WorkManager garandeert uitvoering, zelfs na het opnieuw opstarten van het apparaat en ondersteunt exponential backoff voor herhaalde pogingen. Foreground Service vereist een permanente melding in de statusbalk.
Beide mobiele platforms verscherpen voortdurend de regels voor achtergrondwerk. In iOS verkort elke nieuwe generatie van het besturingssysteem de achtergrondwerktijd en voegt nieuwe beperkingen toe. In Android voert Google steeds strengere energiebesparingsmodi in (Doze, App Standby). De ontwikkelaar moet op de hoogte zijn van de huidige beperkingen zodat de app niet voortijdig door het systeem wordt beëindigd.
In iOS schakelt het systeem sinds iOS 13 achtergrondtaken uit voor apps die hun achtergrondtijd misbruiken. Elke app krijgt specifieke limieten op basis van gebruikersgedrag. BGTaskScheduler plant uitvoering op het optimale tijdstip — bijvoorbeeld wanneer het apparaat is verbonden met Wi-Fi en wordt opgeladen. Apps die BGTaskScheduler correct gebruiken, krijgen meer achtergrondtijd.
In Android is achtergrondwerk sinds Android 9 (API 28) beperkt door de Doze-modus, die wordt geactiveerd bij inactiviteit van het apparaat. Apps in Doze kunnen geen achtergrondtaken uitvoeren, het netwerk wordt uitgeschakeld, JobScheduler en WorkManager stellen taken uit tot het verlaten van Doze. Foreground Service is de enige manier om Doze te omzeilen, maar misbruik leidt tot blokkering van de app door de gebruiker en verwijdering van toestemmingen.
| Beperking | iOS | Android |
|---|---|---|
| Time-out achtergrondtaak | ~30 seconden (beginBackgroundTask) | Enkele minuten (JobScheduler) |
| Onbeperkte achtergrond | Audio, VoIP, navigatie, Bluetooth | Foreground Service + melding |
| Energiebesparing | Low Power Mode — schakelt achtergrondtaken uit | Doze, App Standby, Battery Optimization |
| Planning | BGTaskScheduler (iOS 13+) | WorkManager (Android Jetpack) |
| Na herstart | Alleen pushmelding | WorkManager behoudt taken |
| Max. uitvoeringstijd | ~30 minuten (audio) | Onbeperkt (Foreground Service) |
Eerste regel — minimaliseer het bronnengebruik op de achtergrond. De meeste achtergrondtaken kunnen worden uitgesteld tot het apparaat wordt opgeladen en is verbonden met Wi-Fi. Gebruik BGTaskScheduler (iOS) en WorkManager (Android) voor het plannen van taken met voorwaarden. Voer geen zware berekeningen uit op de achtergrond — dit ontlaadt de batterij en leidt tot CPU-throttling.
Tweede regel — specificeer altijd expirationHandler voor beginBackgroundTask. Als de app de taak niet binnen de toegewezen tijd voltooit, zal het systeem deze gedwongen naar Suspended schakelen of beëindigen. ExpirationHandler is de laatste kans om gegevens op te slaan en het werk correct te beëindigen. Gebruik in Android setForegroundAsync in WorkManager om een gewone taak naar foreground te converteren als er meer tijd nodig is.
Derde regel — controleer de beperkingen van achtergrondwerk voordat u start. Gebruik in iOS UIApplication.shared.backgroundTimeRemaining om de resterende tijd te controleren. Controleer in Android ActivityManager.isBackgroundRestricted() — als dit true is, kan de app geen achtergrondtaken starten en moet u de gebruiker voorstellen de beperkingen in de instellingen op te heffen. Dit is vooral belangrijk voor apps met kritieke achtergrondfuncties — wekkers, agenda's, synchronisatie.
Vierde regel — test achtergrondtaken op een echt apparaat. De simulator en emulator reproduceren de echte beperkingen van achtergrondwerk niet. Gebruik in iOS Debug → Simulate Background Fetch in Xcode. In Android — adb shell am broadcast -a android.intent.action.ACTION_BOOT_COMPLETED voor het testen van WorkManager na herstart. Echte tests op een apparaat met een lage batterijspanning onthullen de meeste problemen met achtergrondwerk.
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("Resterende tijd op achtergrond: \(remaining) sec")
let task = UIApplication.shared.beginBackgroundTask { [weak self] in
print("Tijd verlopen voor taak: \(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)
}
}De code toont een achtergrondtaakbeheerder die de resterende tijd bijhoudt en identificatoren beheert. backgroundTimeRemaining geeft het aantal seconden terug tot gedwongen beëindiging — als de waarde oneindig is, werkt de app zonder beperking (audio, navigatie). De beheerder maakt het mogelijk meerdere achtergrondtaken met verschillende namen te starten en elke correct te voltooien. Deze aanpak voorkomt het lekken van achtergrondtaken en garandeert dat het systeem de app niet beëindigt vanwege niet-gesloten taken.
Veelgestelde vragen
Ja, voor een beperkt aantal categorieën: audio (AVAudioSession categorie .playback), VoIP (PushKit), navigatie (CLLocationManager met allowsBackgroundLocationUpdates), Bluetooth (centrale achtergrondmodus), achtergrondupdate (BGTaskScheduler). Voor alle andere — maximaal 30 seconden. In iOS 16+ heeft Apple de vereisten zelfs voor toegestane categorieën verscherpt.
beginBackgroundTask — synchrone API om de levensduur van de app met ~30 seconden te verlengen na het gaan naar de achtergrond. Wordt aangeroepen in applicationDidEnterBackground. BGTaskScheduler — asynchrone API voor het plannen van taken in de toekomst via systeemtriggers (tijd, locatie, inhoudsupdate). BGTaskScheduler is de moderne aanpak die door Apple wordt aanbevolen voor iOS 13+.
Sinds Android 8 (API 26) wordt Background Service enkele minuten nadat de app naar de achtergrond gaat beëindigd. Oplossing: gebruik Foreground Service met melding voor lange bewerkingen of WorkManager voor uitgestelde taken. Controleer Battery Optimization voor uw app in de instellingen — als deze is geoptimaliseerd, kan het systeem achtergrondtaken uitstellen of annuleren.
Druk op Cmd+Shift+H om naar het startscherm te gaan. Gebruik in Xcode Debug → Simulate Background Fetch. Om beginBackgroundTask te controleren, opent u de console (Shift+Cmd+C) en roept u e UIApplication.shared.backgroundTimeRemaining aan. In Xcode 15+ is het Background Execution-scenario beschikbaar in het Diagnostics-tabblad van de simulator.
Process Death — beëindiging van een Android-proces door het systeem bij gebrek aan bronnen of bij inactiviteit op de achtergrond. In tegenstelling tot iOS heeft Android geen Suspended — het proces bestaat (kan op de achtergrond zijn) of is dood (Not Running). Process Death is normaal gedrag van het besturingssysteem en de app moet de status daarna correct herstellen via SavedStateHandle, onSaveInstanceState of DataStore.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook