Inactive — uno stato transitorio nel ciclo di vita dell'applicazione tra Active e Background, in cui l'app è visibile sullo schermo ma non riceve eventi tattili. Spieghiamo come Inactive si verifica su iOS e Android, quali metodi delegati lo gestiscono e come elaborare correttamente le interruzioni — chiamate, notifiche e gesti di sistema.
Punti chiave
Inactive è uno stato intermedio nel ciclo di vita dell'applicazione mobile che si verifica durante la transizione tra Active e Background. In questo stato, l'app è ancora in primo piano e visibile all'utente, ma non riceve eventi tattili, pressioni di tasti o altri eventi UI. Il sistema blocca la distribuzione degli eventi all'app, ma l'UI rimane sullo schermo e non viene minimizzata.
La natura di Inactive è temporanea. Questo stato dura esattamente quanto l'interruzione di sistema: da 0,1 secondi quando si chiude rapidamente il Control Center a diversi secondi durante una chiamata in arrivo con schermata di chiamata. Dopo la fine dell'interruzione, l'app torna in Active o passa a Background se l'utente è passato a un'altra app. Inactive è l'unico stato che può transitare in entrambe le direzioni: tornare in Active o proseguire verso Background.
Su iOS, Inactive è gestito automaticamente dal sistema. Lo sviluppatore non può estendere o ridurre il tempo in Inactive — è completamente controllato da UIApplication. L'unica cosa che lo sviluppatore può fare è gestire correttamente la transizione a Inactive tramite applicationWillResignActive e il ritorno tramite applicationDidBecomeActive. Su Android, l'equivalente è onPause, sebbene la semantica differisca: onPause viene chiamato anche quando un'Activity è parzialmente coperta da un altro componente.
Su iOS, Inactive è uno stato separato del ciclo di vita dell'applicazione (uno dei cinque: Not Running, Active, Inactive, Background, Suspended). Su Android non esiste un equivalente diretto — onPause segnala che l'Activity sta perdendo il focus di input ma può rimanere visibile (ad esempio, quando si apre un dialogo). La differenza chiave: Inactive su iOS è uno stato a livello di app, mentre onPause su Android è uno stato per Activity. In multi-finestra Android, un'Activity può essere in onPause (senza focus) mentre un'altra è in onResume (con focus).
| Caratteristica | iOS Inactive | Android onPause |
|---|---|---|
| UI visibile | Sì | Sì (parzialmente o completamente) |
| Eventi tattili | Non riceve | Non riceve |
| Durata | Fino al termine dell'interruzione | Fino al ritorno del focus o passaggio in background |
| Stato successivo | Active o Background | onResume o onStop |
| Livello | App (UIApplication) | Activity |
| Multi-finestra | Una scena attiva | Più Activity in onPause |
Inactive su iOS si verifica in diversi scenari rigorosamente definiti. L'utente apre il Control Center (scorrimento verso il basso dall'angolo in alto a destra su iPhone X+ o verso l'alto sui modelli precedenti). L'utente apre il Notification Center (scorrimento verso il basso dall'angolo in alto a sinistra). Arriva una chiamata in arrivo — il sistema mostra la schermata di chiamata sopra l'app. Viene richiesto un permesso di sistema — geolocalizzazione, microfono, fotocamera, contatti. Su iPad, viene avviato Slide Over o Split View — la scena attiva diventa Inactive.
Su Android, onPause (l'equivalente di Inactive) si verifica in una gamma ancora più ampia di situazioni. Apertura di un dialogo (AlertDialog, DialogFragment). Sovrapposizione parziale di un'Activity da parte di un'altra Activity (ad esempio, un'Activity trasparente per l'autenticazione). Rotazione dello schermo (l'Activity viene ricreata, sequenza: onPause → onStop → onDestroy → onCreate → onStart → onResume). Modalità multi-finestra — la finestra inattiva riceve onPause. Ciascuno di questi eventi richiede la sospensione delle operazioni intensive per preservare la batteria e le prestazioni.
import UIKit
extension Notification.Name {
static let systemInterruptionBegan = Notification.Name("systemInterruptionBegan")
static let systemInterruptionEnded = Notification.Name("systemInterruptionEnded")
}
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillResignActive(_ application: UIApplication) {
// L'applicazione passa in Inactive — interruzione di sistema
print("Interruzione: Control Center, chiamata o avviso di sistema")
// Sospensione delle operazioni sensibili al tempo
pauseVideoPlayback()
stopContinuousDataCollection()
hideSensitiveInformation()
// Notifica dei componenti
NotificationCenter.default.post(name: .systemInterruptionBegan, object: nil)
}
// Ritorno da Inactive a Active
func applicationDidBecomeActive(_ application: UIApplication) {
resumeVideoPlayback()
restartDataCollection()
NotificationCenter.default.post(name: .systemInterruptionEnded, object: nil)
}
private func pauseVideoPlayback() {
// Mettere in pausa il video per evitare sovrapposizione audio
}
private func hideSensitiveInformation() {
// Nascondere dati sensibili nello screenshot
// Control Center/App Switcher acquisiscono uno screenshot dell'UI
}
}Il codice mostra la gestione di Inactive in UIKit. applicationWillResignActive mette in pausa il video, interrompe la raccolta dati e nasconde le informazioni sensibili. Questo è importante perché quando si apre Control Center o App Switcher, il sistema acquisisce uno screenshot dell'UI corrente — l'utente potrebbe vedere dati riservati nell'anteprima. NotificationCenter consente ai componenti dell'app di sottoscrivere eventi di interruzione.
Su iOS, Inactive è gestito da una coppia di metodi: applicationWillResignActive (transizione a Inactive) e applicationDidBecomeActive (ritorno da Inactive). Questi metodi fanno parte di UIApplicationDelegate e vengono chiamati per ogni transizione attraverso Inactive. Da iOS 13 e UISceneDelegate, sono stati aggiunti sceneWillResignActive e sceneDidBecomeActive per scenari multi-finestra.
Su iPad con iOS 13+, un'app può avere più scene (finestre). Ogni scena ha il proprio ciclo di vita. Una scena può diventare Inactive (l'utente è passato a un'altra scena) mentre un'altra rimane Active. Questa è una differenza importante rispetto all'iPhone, dove Inactive è uno stato globale per l'intera app. Quando si sviluppa per iPad, è necessario gestire Inactive per ogni scena separatamente.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// La scena diventa inattiva
func sceneWillResignActive(_ scene: UIScene) {
// Su iPad questa scena perde il focus, ma altre possono essere attive
print("La scena perde attività")
// Sospensione delle attività di questa scena
pauseSceneSpecificOperations()
}
// La scena diventa attiva
func sceneDidBecomeActive(_ scene: UIScene) {
print("La scena è diventata attiva")
resumeSceneSpecificOperations()
}
private func pauseSceneSpecificOperations() {
// Sospensione delle operazioni specifiche di questa scena
}
private func resumeSceneSpecificOperations() {
// Ripresa delle operazioni al ritorno del focus
}
}
// AppDelegate rimane il punto di ingresso, delega alle scene
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
return UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role
)
}
}Il codice mostra uno SceneDelegate per gestire Inactive a livello di scena. sceneWillResignActive viene chiamato quando una finestra specifica perde il focus — questo può accadere quando si passa da una finestra all'altra su iPad. AppDelegate configura UISceneConfiguration per supportare il multi-finestra. Ogni scena ha uno stato indipendente e lo sviluppatore deve gestirle separatamente.
Su Android, l'equivalente diretto di Inactive su iOS è il metodo onPause() del ciclo di vita dell'Activity. Viene chiamato quando l'Activity perde il focus di input ma può rimanere visibile. Scenari tipici: apertura di un dialogo, avvio di un'altra Activity nella stessa app, chiamata in arrivo, pressione del pulsante Home o Recents. In onPause, lo sviluppatore deve sospendere le operazioni intensive — animazioni, riproduzione video, lavoro con la fotocamera.
Una differenza importante di Android è che onPause precede sempre onStop, ma non viceversa. Un'Activity può ricevere onPause senza onStop (ad esempio, quando si apre un'Activity trasparente). Inoltre, onPause può essere chiamato più volte durante la vita di un'Activity — ad ogni cambio di focus. Non inserire logica monouso in onPause — usa onStop per le operazioni finali e onPause solo per sospendere le azioni interattive.
class VideoPlayerActivity : AppCompatActivity() {
private var exoPlayer: ExoPlayer? = null
private var currentPosition: Long = 0L
override fun onPause() {
super.onPause()
// L'app perde il focus — mettiamo in pausa il video
exoPlayer?.let { player ->
if (player.isPlaying) {
currentPosition = player.currentPosition
player.pause()
}
}
// Nascondiamo dati sensibili (GDPR/schermate bancarie)
if (window.decorView.systemUiVisibility and
View.SYSTEM_UI_FLAG_SECURE == 0
) {
hideSensitiveOverlay()
}
}
override fun onResume() {
super.onResume()
// Il focus ritorna — riprendiamo la riproduzione
exoPlayer?.seekTo(currentPosition)
exoPlayer?.play()
showSensitiveOverlay()
}
private fun hideSensitiveOverlay() {
// Sovrapponiamo uno schermo nero sui dati finanziari
}
}Il codice mostra la corretta gestione di onPause per un lettore video. ExoPlayer viene messo in pausa quando il focus viene perso e la posizione di riproduzione viene salvata. Al ritorno in onResume, il lettore riprende la riproduzione dalla posizione salvata. Inoltre, viene mostrato un pattern per nascondere i dati sensibili — importante per le app finanziarie e mediche che richiedono protezione dagli screenshot durante il cambio di app.
Prima regola — nascondere i dati riservati quando si transita a Inactive. Quando l'utente apre Control Center o App Switcher, iOS acquisisce uno screenshot dello schermo corrente. Su Android, analogamente, il sistema mostra un'anteprima dell'ultima Activity in Recents. Utilizza UIApplication.shouldSnapshotSecureApp (iOS 16+) o FLAG_SECURE (Android) per proteggere gli schermi riservati.
Seconda regola — mettere in pausa animazioni e media. Inactive non è un buon momento per riprodurre video o animazioni, poiché l'utente non può vederli. Inoltre, la riproduzione in background può sovrapporre l'audio ai suoni di sistema (suoneria, notifica). Ferma AVPlayer, ExoPlayer e UIView.animate quando vai in Inactive e riprendili quando torni in Active.
Terza regola — bloccare l'input di dati. Se l'app contiene moduli di input o bozze, blocca la tastiera e i campi di input quando vai in Inactive. Questo previene input accidentali al ritorno e protegge dall'intercettazione dei dati tramite overlay di sistema. Su iOS, dimetti il primo responder (view.endEditing(true)), su Android — cancella il focus (currentFocus?.clearFocus()).
Quarta regola — non eseguire operazioni lunghe in applicationWillResignActive o onPause. Questi metodi dovrebbero completarsi in frazioni di secondo. Se devi salvare una grande quantità di dati, inizia il salvataggio in un thread in background e completalo in applicationDidEnterBackground o onStop. iOS dà 5 secondi per eseguire applicationWillResignActive, dopo i quali il sistema può terminare forzatamente l'app.
import UIKit
final class SecureOverlayManager {
private var blurView: UIVisualEffectView?
func showBlurOverlay() {
guard let window = UIApplication.shared.keyWindow,
blurView == nil
else { return }
let blur = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
blur.frame = window.bounds
blur.autoresizingMask = [.flexibleWidth, .flexibleHeight]
window.addSubview(blur)
blurView = blur
}
func removeBlurOverlay() {
blurView?.removeFromSuperview()
blurView = nil
}
}
// Utilizzo in AppDelegate
func applicationWillResignActive(_ application: UIApplication) {
SecureOverlayManager().showBlurOverlay()
}
func applicationDidBecomeActive(_ application: UIApplication) {
SecureOverlayManager().removeBlurOverlay()
}Il codice mostra l'implementazione di un overlay sicuro per la protezione dei dati durante la transizione a Inactive. Un UIVisualEffectView con effetto sfocatura viene sovrapposto all'intera UI quando si va in Inactive e rimosso quando si torna in Active. Questo garantisce che i dati riservati non siano visibili negli screenshot di App Switcher e Control Center. Analogamente, puoi usare UIImageView con un logo per un overlay personalizzato.
Domande frequenti
Sì. Inactive è uno stato intermedio obbligatorio prima di passare a Background su iOS. Un'app non può andare direttamente da Active a Background — prima diventa Inactive, poi Background. Su Android, analogamente, onPause viene sempre chiamato prima di onStop. Questo dà allo sviluppatore l'opportunità di preparare i dati per il salvataggio prima di andare completamente in background.
Sì. Su iPad, quando si avvia Slide Over o Split View, la scena attiva diventa Inactive, anche se non si verifica alcuna interruzione di sistema — l'utente sta semplicemente interagendo con un'altra scena. Questa è una funzionalità di iPadOS multi-finestra. Su iPhone, Inactive è sempre innescato da un'interruzione di sistema — chiamata, notifica, Control Center o Notification Center.
Di solito da 0,1 a 2 secondi. Durante una chiamata in arrivo con schermata di chiamata — fino a 30 secondi (finché l'utente non risponde o rifiuta la chiamata). iOS non limita forzatamente il tempo in Inactive, ma il sistema può terminare l'app se non risponde agli eventi (watchdog). Su Android, onPause non ha limiti di tempo, ma si consiglia di completare il lavoro entro 200 ms.
ScenePhase.inactive — il valore dell'enum ScenePhase impostato quando la scena è in primo piano ma non riceve eventi. In SwiftUI, puoi osservarlo tramite @Environment(\.scenePhase) e reagire tramite onChange. Quando si transita da .active a .inactive, metti in pausa timer e animazioni. Quando si torna a .active, riprendili. Quando si va in .background, salva lo stato.
No, solo per le app che gestiscono dati riservati: bancarie, mediche, aziendali e di messaggistica con chat private. Per giochi e app di intrattenimento, nascondere l'UI non è necessario. Tuttavia, mettere in pausa il gioco e l'audio durante Inactive è una buona pratica per evitare la sovrapposizione dell'audio con le notifiche di sistema. Apple raccomanda di nascondere i dati sensibili ma non lo richiede.
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