Background è uno stato del ciclo di vita dell'app in cui continua a essere eseguita ma non viene visualizzata sullo schermo. Spieghiamo le basi del lavoro in background su iOS e Android: limitazioni, timeout, attività in background tramite beginBackgroundTask, WorkManager e Service, e le migliori pratiche per la corretta gestione di Background.
Punti Chiave
Background è uno stato dell'app in cui continua a esistere nel sistema operativo, esegue codice e consuma risorse, ma non viene visualizzata sullo schermo del dispositivo. L'utente si trova sulla schermata Home, in un'altra app o lo schermo del dispositivo è bloccato. Su iOS, Background segue Inactive — la catena di transizione è: Active → Inactive → Background. Su Android, onStop segnala la transizione di un Activity in Background.
Entrambe le piattaforme impongono restrizioni severe al lavoro in background. iOS fornisce una finestra limitata (di solito 30 secondi) per eseguire codice dopo essere entrato in Background, dopodiché l'app passa a Suspended. Android è più flessibile: un Foreground Service con una notifica visibile può funzionare indefinitamente, ma un normale Background Service è limitato a pochi minuti. Il compito principale dello sviluppatore è salvare correttamente lo stato e pianificare la continuazione del lavoro tramite le API di sistema per attività in background.
Il sistema può terminare un'app in background in qualsiasi momento quando la memoria è scarsa. Alla terminazione, tutti i dati non salvati vengono persi. È quindi fondamentale salvare lo stato in applicationDidEnterBackground (iOS) o onStop (Android). Dopo la terminazione, il successivo avvio parte da Not Running con un avvio a freddo e ripristina lo stato salvato.
È importante distinguere Background da Suspended. Background — l'app sta eseguendo attivamente codice. Suspended — l'app è in memoria ma non esegue codice — è congelata. Su iOS, l'app passa da Background a Suspended dopo aver completato le attività in background. Android non ha Suspended — il processo esiste (incluso Background) o è terminato (Not Running). Tuttavia, Android può sospendere l'esecuzione dei thread tramite LMK (Low Memory Killer).
| Caratteristica | iOS Background | Android Background |
|---|---|---|
| Codice eseguito | Sì, fino a 30 secondi | Sì, dipende dall'API |
| UI visibile | No | No |
| Timeout predefinito | ~30 sec (beginBackgroundTask) | Diversi minuti (Service) |
| Lavoro illimitato | Solo categorie speciali (audio, VoIP, navigazione) | Foreground Service con notifica |
| Garanzia di esecuzione | No — il sistema può terminare in qualsiasi momento | WorkManager garantisce l'esecuzione |
| Permesso richiesto | Sì — capabilities in Info.plist | Sì — permesso FOREGROUND_SERVICE |
| Stato successivo | Suspended → Not Running | Not Running (o riavvio) |
Su iOS, Background viene gestito tramite il metodo delegato applicationDidEnterBackground. In questo metodo, lo sviluppatore deve salvare lo stato dell'utente, liberare risorse e completare le attività in background. Per eseguire codice dopo essere entrati in Background, si utilizza beginBackgroundTask(expirationHandler:) — un'API che richiede tempo aggiuntivo al sistema (di solito 30 secondi). Se l'attività non viene completata entro questo tempo, viene chiamato expirationHandler e l'app viene forzata a passare a Suspended.
Con iOS 13, Apple ha introdotto BGTaskScheduler — un'API moderna per pianificare attività in background. A differenza di beginBackgroundTask, che dà solo tempo per terminare dopo essere andati in background, BGTaskScheduler consente di pianificare l'esecuzione di attività nel futuro — ad esempio, aggiornare il contenuto una volta all'ora o caricare analisi di notte. BGTaskScheduler è l'approccio consigliato per nuovi progetti, poiché è più efficiente in termini di batteria.
import UIKit
import BackgroundTasks
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
// L'app è andata in background — avvio attività in background
func applicationDidEnterBackground(_ application: UIApplication) {
saveAppState()
startBackgroundTask()
}
private func startBackgroundTask() {
backgroundTaskID = UIApplication.shared.beginBackgroundTask { [weak self] in
// Tempo scaduto — terminazione forzata
self?.endBackgroundTask()
}
// Simulazione lavoro in background (salvataggio dati sul server)
DispatchQueue.global().async { [weak self] in
uploadAnalyticsData()
self?.endBackgroundTask()
}
}
private func endBackgroundTask() {
guard backgroundTaskID != .invalid else { return }
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// Registrazione 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)
}
}
}Il codice mostra la gestione completa di Background su iOS. applicationDidEnterBackground avvia un'attività in background tramite beginBackgroundTask con un timeout e expirationHandler. Parallelamente, BGTaskScheduler viene registrato per aggiornamenti periodici dei contenuti. beginBackgroundTask viene utilizzato per attività di spegnimento immediato, BGTaskScheduler per la pianificazione a lungo termine. Entrambe le API richiedono una corretta gestione degli identificatori delle attività.
Su Android, Background viene gestito tramite diverse API. Il Service tradizionale consente di eseguire codice in background, ma da Android 8+ (API 26), il Background Service è limitato: il sistema lo termina pochi minuti dopo che l'app va in background. Un Foreground Service con una notifica persistente può funzionare indefinitamente. WorkManager è la soluzione consigliata per attività in background con garanzia di esecuzione anche dopo il riavvio del dispositivo.
Android, a differenza di iOS, supporta processi in background di lunga durata. Foreground Service viene utilizzato per attività che l'utente deve vedere — riproduzione musicale, navigazione, tracciamento degli allenamenti. JobScheduler e WorkManager vengono utilizzati per attività che possono essere rinviate: sincronizzazione dati, caricamento log, aggiornamento cache. La differenza chiave: Android consente di pianificare attività con condizioni — Wi-Fi, ricarica, inattività del dispositivo — risparmiando batteria e traffico.
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.work.*
// 1. Foreground Service per lavoro in background prolungato
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 {
// Sincronizzazione dati con il server
syncDataToServer()
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
}.start()
}
override fun onBind(intent: Intent?): IBinder? = null
}
// 2. WorkManager per attività in background rinviate
class DataSyncWorker(
private val context: Context,
private val params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
// Caricamento analisi sul server
uploadAnalytics()
Result.success()
} catch (e: Exception) {
if (runAttemptCount < 3) Result.retry() else Result.failure()
}
}
}
// Pianificazione attività 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)
}Il codice mostra due approcci al lavoro in background su Android. SyncService — un Foreground Service con notifica per lavoro immediato e prolungato in background. DataSyncWorker — WorkManager per attività rinviate con condizioni (Wi-Fi, ricarica). WorkManager garantisce l'esecuzione anche dopo il riavvio del dispositivo e supporta il backoff esponenziale per i tentativi. Foreground Service richiede una notifica persistente nella barra di stato.
Entrambe le piattaforme mobili stanno costantemente inasprendo le regole sul lavoro in background. Su iOS, ogni nuova generazione di OS riduce il tempo di esecuzione in background e aggiunge nuove restrizioni. Su Android, Google introduce modalità di risparmio energetico sempre più severe (Doze, App Standby). Gli sviluppatori devono rimanere aggiornati sulle limitazioni correnti per evitare che l'app venga terminata prematuramente dal sistema.
Su iOS, a partire da iOS 13, il sistema disabilita le attività in background per le app che abusano del tempo in background. Ogni app riceve determinati limiti basati sul comportamento dell'utente. BGTaskScheduler pianifica l'esecuzione in momenti ottimali — ad esempio, quando il dispositivo è connesso al Wi-Fi e in carica. Le app che utilizzano correttamente BGTaskScheduler ottengono più tempo in background.
Su Android, a partire da Android 9 (API 28), il lavoro in background è limitato dalla modalità Doze, che si attiva quando il dispositivo è inattivo. Le app in Doze non possono eseguire attività in background, la rete viene disconnessa, JobScheduler e WorkManager rimandano le attività fino all'uscita da Doze. Foreground Service è l'unico modo per bypassare Doze, ma l'abuso porta al blocco dell'app da parte dell'utente e alla revoca dei permessi.
| Limitazione | iOS | Android |
|---|---|---|
| Timeout attività in background | ~30 secondi (beginBackgroundTask) | Diversi minuti (JobScheduler) |
| Background illimitato | Audio, VoIP, navigazione, Bluetooth | Foreground Service + notifica |
| Risparmio energetico | Low Power Mode — disabilita attività in background | Doze, App Standby, Ottimizzazione batteria |
| Pianificazione | BGTaskScheduler (iOS 13+) | WorkManager (Android Jetpack) |
| Dopo riavvio | Solo notifica push | WorkManager conserva le attività |
| Tempo massimo di esecuzione | ~30 minuti (audio) | Illimitato (Foreground Service) |
Prima regola — minimizzare il consumo di risorse in background. La maggior parte delle attività in background può essere rimandata a quando il dispositivo è in carica e connesso al Wi-Fi. Utilizzare BGTaskScheduler (iOS) e WorkManager (Android) per pianificare attività con condizioni. Non eseguire calcoli pesanti in background — questo scarica la batteria e porta alla limitazione della CPU.
Seconda regola — specificare sempre un expirationHandler per beginBackgroundTask. Se l'app non completa l'attività nel tempo assegnato, il sistema la forzerà a passare a Suspended o la terminerà. L'expirationHandler è l'ultima possibilità per salvare dati e terminare correttamente il lavoro. Su Android, utilizzare setForegroundAsync in WorkManager per convertire un'attività normale in primo piano se è necessario più tempo.
Terza regola — verificare le restrizioni al lavoro in background prima di avviare. Su iOS, utilizzare UIApplication.shared.backgroundTimeRemaining per controllare il tempo rimanente. Su Android, verificare ActivityManager.isBackgroundRestricted() — se true, l'app non può eseguire attività in background e si dovrebbe suggerire all'utente di rimuovere le restrizioni nelle impostazioni. Questo è particolarmente importante per le app con funzioni critiche in background — sveglie, calendari, sincronizzazione.
Quarta regola — testare le attività in background su un dispositivo reale. I simulatori e gli emulatori non riproducono le reali restrizioni del lavoro in background. Su iOS, utilizzare Debug → Simulate Background Fetch in Xcode. Su Android, utilizzare adb shell am broadcast -a android.intent.action.ACTION_BOOT_COMPLETED per testare WorkManager dopo il riavvio. Test reali su un dispositivo con batteria scarica rivelano la maggior parte dei problemi del lavoro in background.
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("Tempo rimanente in background: \(remaining) sec")
let task = UIApplication.shared.beginBackgroundTask { [weak self] in
print("Tempo scaduto per l'attività: \(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)
}
}Il codice mostra un gestore di attività in background che traccia il tempo rimanente e gestisce gli identificatori. backgroundTimeRemaining restituisce il numero di secondi prima della terminazione forzata — se il valore è infinito, l'app è in esecuzione senza restrizioni (audio, navigazione). Il gestore consente di avviare più attività in background con nomi diversi e completare ciascuna correttamente. Questo approccio previene perdite di attività in background e garantisce che il sistema non termini l'app a causa di attività non chiuse.
Domande Frequenti
Sì, per un numero limitato di categorie: audio (categoria AVAudioSession .playback), VoIP (PushKit), navigazione (CLLocationManager con allowsBackgroundLocationUpdates), Bluetooth (modalità background centrale), aggiornamento in background (BGTaskScheduler). Per tutte le altre — massimo 30 secondi. In iOS 16+, Apple ha inasprito i requisiti anche per le categorie consentite.
beginBackgroundTask è un'API sincrona per estendere la vita dell'app di circa 30 secondi dopo essere andata in background. Viene chiamato in applicationDidEnterBackground. BGTaskScheduler è un'API asincrona per pianificare attività nel futuro tramite trigger di sistema (tempo, posizione, aggiornamento contenuto). BGTaskScheduler è l'approccio moderno, raccomandato da Apple per iOS 13+.
A partire da Android 8 (API 26), un Background Service viene terminato pochi minuti dopo che l'app va in background. Soluzione: utilizzare un Foreground Service con notifica per operazioni lunghe o WorkManager per attività rinviate. Controllare l'Ottimizzazione della batteria per la propria app nelle impostazioni — se ottimizzata, il sistema potrebbe rimandare o annullare le attività in background.
Premere Cmd+Shift+H per andare alla schermata Home. In Xcode, utilizzare Debug → Simulate Background Fetch. Per verificare beginBackgroundTask, aprire la console (Shift+Cmd+C) e chiamare e UIApplication.shared.backgroundTimeRemaining. In Xcode 15+, uno scenario Background Execution è disponibile nella scheda Diagnostics del simulatore.
Process Death è la terminazione di un processo Android da parte del sistema quando le risorse sono scarse o quando è inattivo in background. A differenza di iOS, Android non ha Suspended — il processo è vivo (può essere in background) o morto (Not Running). Process Death è un comportamento normale del OS e l'app deve ripristinare correttamente lo stato dopo tramite SavedStateHandle, onSaveInstanceState o DataStore.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche