Inactive — Active ve Background arasında uygulama yaşam döngüsünde, uygulamanın ekranda görünür olduğu ancak dokunma olaylarını almadığı bir geçiş durumudur. Inactive'in iOS ve Android'de nasıl oluştuğunu, hangi delegate yöntemlerinin bundan sorumlu olduğunu ve kesintileri — aramalar, bildirimler ve sistem hareketleri — nasıl doğru şekilde işleyeceğimizi açıklıyoruz.
Önemli Noktalar
Inactive, Active ve Background arasındaki geçiş sırasında oluşan mobil uygulama yaşam döngüsünde bir ara durumdur. Bu durumda, uygulama hala ön plandadır ve kullanıcıya görünür, ancak dokunma olayları, tuş basışları veya diğer UI olaylarını almaz. Sistem, uygulamaya olay iletimini engeller, ancak UI ekranda kalır ve küçültülmez.
Inactive'in doğası geçicidir. Bu durum, sistem kesintisi sürdüğü sürece devam eder: Control Center'ı hızlıca kapatırken 0,1 saniyeden, arama ekranıyla gelen arama sırasında birkaç saniyeye kadar. Kesinti sona erdiğinde, uygulama Active'e döner veya kullanıcı başka bir uygulamaya geçtiyse Background'a geçer. Inactive, her iki yönde de geçiş yapabilen tek durumdur: Active'e geri veya Background'a ileri.
iOS'ta Inactive, sistem tarafından otomatik olarak yönetilir. Geliştirici, Inactive'de geçirilen süreyi uzatamaz veya kısaltamaz — tamamen UIApplication tarafından kontrol edilir. Geliştiricinin yapabileceği tek şey, applicationWillResignActive aracılığıyla Inactive'e geçişi ve applicationDidBecomeActive aracılığıyla dönüşü doğru şekilde yönetmektir. Android'de eşdeğeri onPause'dır, ancak anlambilim farklıdır: onPause, bir Activity başka bir bileşen tarafından kısmen kaplandığında bile çağrılır.
iOS'ta Inactive, uygulama yaşam döngüsünün ayrı bir durumudur (beşten biri: Not Running, Active, Inactive, Background, Suspended). Android'de doğrudan bir eşdeğer yoktur — onPause, Activity'nin giriş odağını kaybettiğini ancak görünür kalabileceğini bildirir (örneğin, bir iletişim kutusu açıldığında). Temel fark: iOS Inactive, uygulama çapında bir durumdur, Android onPause ise Activity başına bir durumdur. Android çoklu pencerede, bir Activity onPause'da (odaksız) olabilirken diğeri onResume'da (odaklı) olabilir.
| Özellik | iOS Inactive | Android onPause |
|---|---|---|
| UI görünür | Evet | Evet (kısmen veya tamamen) |
| Dokunma olayları | Almaz | Almaz |
| Süre | Kesinti sonlanana kadar | Odak dönene veya arka plana gidene kadar |
| Sonraki durum | Active veya Background | onResume veya onStop |
| Seviye | Uygulama (UIApplication) | Activity |
| Çoklu pencere | Bir sahne aktif | Birden çok Activity onPause'da |
Inactive iOS'ta birkaç kesin olarak tanımlanmış senaryoda oluşur. Kullanıcı Control Center'ı açar (iPhone X+'da sağ üst köşeden aşağı kaydırma veya eski modellerde yukarı kaydırma). Kullanıcı Notification Center'ı açar (sol üst köşeden aşağı kaydırma). Gelen bir arama gelir — sistem uygulamanın üzerinde arama ekranını gösterir. Bir sistem izni istenir — konum, mikrofon, kamera, kişiler. iPad'de Slide Over veya Split View başlatılır — aktif sahne Inactive olur.
Android'de onPause (Inactive'in eşdeğeri) daha da geniş bir durum yelpazesinde oluşur. Bir iletişim kutusu açma (AlertDialog, DialogFragment). Bir Activity'nin başka bir Activity tarafından kısmen kaplanması (örneğin, kimlik doğrulama için şeffaf Activity). Ekran döndürme (Activity yeniden oluşturulur, sıra: onPause → onStop → onDestroy → onCreate → onStart → onResume). Çoklu pencere modu — etkin olmayan pencere onPause alır. Bu olayların her biri, pil ve performansı korumak için kaynak yoğun işlemlerin askıya alınmasını gerektirir.
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) {
// Uygulama Inactive'e geçiyor — sistem kesintisi
print("Kesinti: Control Center, arama veya sistem uyarısı")
// Zamana duyarlı işlemleri askıya alma
pauseVideoPlayback()
stopContinuousDataCollection()
hideSensitiveInformation()
// Bileşenleri bilgilendirme
NotificationCenter.default.post(name: .systemInterruptionBegan, object: nil)
}
// Inactive'den Active'e dönüş
func applicationDidBecomeActive(_ application: UIApplication) {
resumeVideoPlayback()
restartDataCollection()
NotificationCenter.default.post(name: .systemInterruptionEnded, object: nil)
}
private func pauseVideoPlayback() {
// Ses örtüşmemesi için videoyu duraklatma
}
private func hideSensitiveInformation() {
// Ekran görüntüsünde hassas verileri gizleme
// Control Center/App Switcher UI'nin ekran görüntüsünü alır
}
}Kod, UIKit'te Inactive yönetimini gösterir. applicationWillResignActive videoyu duraklatır, veri toplamayı durdurur ve hassas bilgileri gizler. Bu önemlidir çünkü Control Center veya App Switcher açıldığında, sistem mevcut UI'nin ekran görüntüsünü alır — kullanıcı ön izlemede gizli verileri görebilir. NotificationCenter, uygulama bileşenlerinin kesinti olaylarına abone olmasına izin verir.
iOS'ta Inactive, bir çift yöntemle yönetilir: applicationWillResignActive (Inactive'e geçiş) ve applicationDidBecomeActive (Inactive'den dönüş). Bu yöntemler UIApplicationDelegate'in bir parçasıdır ve Inactive üzerinden her geçişte çağrılır. iOS 13 ve UISceneDelegate'den bu yana, çoklu pencere senaryoları için sceneWillResignActive ve sceneDidBecomeActive eklenmiştir.
iOS 13+ ile iPad'de bir uygulama birden çok sahneye (pencereye) sahip olabilir. Her sahnenin kendi yaşam döngüsü vardır. Bir sahne Inactive olabilir (kullanıcı başka bir sahneye geçti) while another remains Active. Bu, iPhone'dan önemli bir farktır; iPhone'da Inactive tüm uygulama için küresel bir durumdur. iPad için geliştirme yaparken, Inactive'i her sahne için ayrı ayrı yönetmeniz gerekir.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// Sahne etkin değil hale gelir
func sceneWillResignActive(_ scene: UIScene) {
// iPad'de bu sahne odağı kaybeder, ancak diğerleri aktif kalabilir
print("Sahne etkinliği kaybeder")
// Bu sahnenin görevlerini askıya alma
pauseSceneSpecificOperations()
}
// Sahne aktif hale gelir
func sceneDidBecomeActive(_ scene: UIScene) {
print("Sahne aktif hale geldi")
resumeSceneSpecificOperations()
}
private func pauseSceneSpecificOperations() {
// Bu sahneye özgü işlemleri askıya alma
}
private func resumeSceneSpecificOperations() {
// Odak döndüğünde işlemleri sürdürme
}
}
// AppDelegate giriş noktası olarak kalır, sahnelere yetki verir
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
return UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role
)
}
}Kod, sahne düzeyinde Inactive'i yönetmek için SceneDelegate'i gösterir. sceneWillResignActive, belirli bir pencere odağı kaybettiğinde çağrılır — bu, iPad'de pencereler arasında geçiş yaparken meydana gelebilir. AppDelegate, çoklu pencereyi desteklemek için UISceneConfiguration'ı yapılandırır. Her sahnenin bağımsız bir durumu vardır ve geliştirici bunları ayrı ayrı yönetmelidir.
Android'de iOS Inactive'in doğrudan eşdeğeri, Activity yaşam döngüsünün onPause() yöntemidir. Activity giriş odağını kaybettiğinde ancak görünür kalabileceğinde çağrılır. Tipik senaryolar: bir iletişim kutusu açma, aynı uygulamada başka bir Activity başlatma, gelen arama, Home veya Recents düğmesine basma. onPause'da geliştirici, kaynak yoğun işlemleri — animasyonlar, video oynatma, kamera çalışması — askıya almalıdır.
Android'in önemli bir farkı, onPause'un her zaman onStop'tan önce gelmesidir, ancak bunun tersi geçerli değildir. Bir Activity, onStop olmadan onPause alabilir (örneğin, şeffaf bir Activity açarken). Ayrıca, onPause bir Activity'nin ömrü boyunca birden çok kez çağrılabilir — her odak değişiminde. onPause'a tek seferlik mantık koymayın — son işlemler için onStop kullanın ve onPause'u yalnızca etkileşimli eylemleri askıya almak için kullanın.
class VideoPlayerActivity : AppCompatActivity() {
private var exoPlayer: ExoPlayer? = null
private var currentPosition: Long = 0L
override fun onPause() {
super.onPause()
// Uygulama odağı kaybeder — videoyu duraklatıyoruz
exoPlayer?.let { player ->
if (player.isPlaying) {
currentPosition = player.currentPosition
player.pause()
}
}
// Hassas verileri gizliyoruz (GDPR/banka ekranları)
if (window.decorView.systemUiVisibility and
View.SYSTEM_UI_FLAG_SECURE == 0
) {
hideSensitiveOverlay()
}
}
override fun onResume() {
super.onResume()
// Odak dönüyor — oynatmayı sürdürüyoruz
exoPlayer?.seekTo(currentPosition)
exoPlayer?.play()
showSensitiveOverlay()
}
private fun hideSensitiveOverlay() {
// Finansal verilerin üzerine siyah ekran koyuyoruz
}
}Kod, bir video oynatıcı için doğru onPause yönetimini gösterir. ExoPlayer duraklatılır odak kaybedildiğinde ve oynatma konumu kaydedilir. onResume'a dönüldüğünde, oynatıcı kaydedilen konumdan oynatmaya devam eder. Ayrıca, hassas verileri gizlemek için bir desen gösterilir — geçiş yaparken ekran görüntülerine karşı koruma gerektiren finansal ve tıbbi uygulamalar için önemlidir.
Birinci kural — Inactive'e geçerken gizli verileri gizleyin. Kullanıcı Control Center veya App Switcher'ı açtığında, iOS mevcut ekranın ekran görüntüsünü alır. Android'de benzer şekilde, sistem Recents'teki son Activity'nin ön izlemesini gösterir. Gizli ekranları korumak için UIApplication.shouldSnapshotSecureApp (iOS 16+) veya FLAG_SECURE (Android) kullanın.
İkinci kural — animasyonları ve medyayı duraklatın. Inactive, video veya animasyon oynatmak için iyi bir zaman değildir, çünkü kullanıcı bunları göremez. Ayrıca, arka planda oynatma, sesin sistem sesleriyle (zil sesi, bildirim) örtüşmesine neden olabilir. Inactive'e giderken AVPlayer, ExoPlayer ve UIView.animate'i durdurun ve Active'e döndüğünüzde devam edin.
Üçüncü kural — veri girişini engelleyin. Uygulama giriş formları veya taslaklar içeriyorsa, Inactive'e giderken klavyeyi ve giriş alanlarını kilitleyin. Bu, dönüşte yanlışlıkla giriş yapılmasını önler ve sistem katmanları aracılığıyla veri ele geçirilmesine karşı korur. iOS'ta ilk yanıtlayıcıyı bırakın (view.endEditing(true)), Android'de — odağı temizleyin (currentFocus?.clearFocus()).
Dördüncü kural — applicationWillResignActive veya onPause'da uzun işlemler yapmayın. Bu yöntemler saniyenin kesirlerinde tamamlanmalıdır. Büyük miktarda veri kaydetmeniz gerekiyorsa, kaydetmeye bir arka plan iş parçacığında başlayın ve applicationDidEnterBackground veya onStop'ta tamamlayın. iOS, applicationWillResignActive'in yürütülmesi için 5 saniye verir, ardından sistem uygulamayı zorla sonlandırabilir.
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
}
}
// AppDelegate'te kullanım
func applicationWillResignActive(_ application: UIApplication) {
SecureOverlayManager().showBlurOverlay()
}
func applicationDidBecomeActive(_ application: UIApplication) {
SecureOverlayManager().removeBlurOverlay()
}Kod, Inactive'e geçiş sırasında veri koruması için güvenli bir katmanın uygulanmasını gösterir. Bulanıklık efektli UIVisualEffectView, Inactive'e giderken tüm UI'nin üzerine yerleştirilir ve Active'e dönerken kaldırılır. Bu, gizli verilerin App Switcher ve Control Center ekran görüntülerinde görünmemesini sağlar. Benzer şekilde, markalı bir katman için logolu UIImageView kullanabilirsiniz.
Sıkça Sorulan Sorular
Evet. Inactive, iOS'ta Background'a geçmeden önce zorunlu bir ara durumdur. Bir uygulama Active'den doğrudan Background'a geçemez — önce Inactive olur, sonra Background. Android'de benzer şekilde, onPause her zaman onStop'tan önce çağrılır. Bu, geliştiriciye tamamen arka plana geçmeden önce verileri kaydetmeye hazırlama fırsatı verir.
Evet. iPad'de Slide Over veya Split View başlatıldığında, aktif sahne Inactive olur, hiçbir sistem kesintisi olmamasına rağmen — kullanıcı sadece başka bir sahneyle etkileşime geçiyordur. Bu, çoklu pencere iPadOS'un bir özelliğidir. iPhone'da Inactive her zaman bir sistem kesintisi — arama, bildirim, Control Center veya Notification Center — tarafından tetiklenir.
Genellikle 0,1 ila 2 saniye. Arama ekranıyla gelen arama sırasında — 30 saniyeye kadar (kullanıcı aramayı yanıtlayana veya reddedene kadar). iOS, Inactive'de geçen süreyi zorla sınırlamaz, ancak uygulama olaylara yanıt vermezse (watchdog) sistem uygulamayı sonlandırabilir. Android'de onPause'un zaman sınırı yoktur, ancak işin 200 ms içinde tamamlanması önerilir.
ScenePhase.inactive — sahne ön plandayken ancak olay almıyorken ayarlanan ScenePhase enum değeridir. SwiftUI'de bunu @Environment(\.scenePhase) aracılığıyla gözlemleyebilir ve onChange aracılığıyla tepki verebilirsiniz. .active'den .inactive'e geçerken zamanlayıcıları ve animasyonları duraklatın. .active'e döndüğünüzde devam ettirin. .background'a giderken durumu kaydedin.
Hayır, yalnızca gizli verileri işleyen uygulamalar için: bankacılık, tıbbi, kurumsal ve özel sohbetli mesajlaşma uygulamaları. Oyunlar ve eğlence uygulamaları için, UI'yi gizlemek gerekli değildir. Ancak, Inactive sırasında oyun ve sesi duraklatmak, sistem bildirimleriyle ses örtüşmesini önlemek için iyi bir uygulamadır. Apple hassas verilerin gizlenmesini önerir ancak zorunlu kılmaz.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun