Davranış değişiklikleri: Android 14 veya sonraki bir sürümü hedefleyen uygulamalar

Önceki sürümlerde olduğu gibi Android 14 de uygulamanızı etkileyebilecek davranış değişiklikleri içerir. Aşağıdaki davranış değişiklikleri yalnızca Android 14 veya sonraki sürümleri hedefleyen uygulamalar için geçerlidir. Uygulamanız Android 14 veya sonraki bir sürümü hedefliyorsa uygun durumlarda bu davranışları doğru bir şekilde destekleyecek şekilde uygulamanızı değiştirmeniz gerekir.

Uygulamanın targetSdkVersion özelliğinden bağımsız olarak, Android 14'te çalışan tüm uygulamaları etkileyen davranış değişiklikleri listesini de incelemeyi unutmayın.

Temel işlevler

Ön plan hizmeti türleri gereklidir

Uygulamanız Android 14'ü hedefliyorsa uygulamanızdaki her ön plan hizmeti için en az bir ön plan hizmet türü belirtmelidir. Uygulamanızın kullanım alanını temsil eden bir ön plan hizmet türü seçmelisiniz. Sistem, belirli bir kullanım alanını karşılamak için belirli bir türe sahip ön plan hizmetlerinin olmasını bekler.

Uygulamanızdaki bir kullanım alanı bu türlerden hiçbiriyle ilişkili değilse mantığınızı WorkManager'ı veya kullanıcı tarafından başlatılan veri aktarımı işlerini kullanacak şekilde taşımanız önemle tavsiye edilir.

BluetoothAdapter'da BLUETOOTH_CONNECT izninin uygulanması

Android 14, Android 14'ü (API düzeyi 34) hedefleyen uygulamalar için BluetoothAdapter getProfileConnectionState() yöntemini çağırırken BLUETOOTH_CONNECT iznini uygular.

Bu yöntem zaten BLUETOOTH_CONNECT izni gerektiriyordu ancak zorunlu kılınmadı. Uygulamanızın aşağıdaki snippet'te gösterildiği gibi, uygulamanızın AndroidManifest.xml dosyasında BLUETOOTH_CONNECT beyan ettiğinden emin olun ve getProfileConnectionState çağrısı yapmadan önce kullanıcının izin verip vermediğini kontrol edin.

<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

OpenJDK 17 güncellemeleri

Android 14, uygulama ve platform geliştiricileri için hem kitaplık güncellemeleri hem de Java 17 dil desteği dahil olmak üzere Android'in temel kitaplıklarını en son OpenJDK LTS sürümlerindeki özelliklere uygun olacak şekilde yenileme çalışmalarına devam ediyor.

Bu değişikliklerden birkaçı uygulama uyumluluğunu etkileyebilir:

  • Normal ifadelerde yapılan değişiklikler: Geçersiz grup referanslarının OpenJDK'nin anlamlarını daha yakından takip etmesine artık izin verilmemektedir. java.util.regex.Matcher sınıfının IllegalArgumentException attığı yeni durumlar görebilirsiniz. Bu nedenle uygulamanızı normal ifadelerin kullanıldığı alanlar için test ettiğinizden emin olun. Test sırasında bu değişikliği etkinleştirmek veya devre dışı bırakmak için uyumluluk çerçevesi araçlarını kullanarak DISALLOW_INVALID_GROUP_REFERENCE işaretini değiştirin.
  • UUID işleme: java.util.UUID.fromString() yöntemi, giriş bağımsız değişkenini doğrularken artık daha katı denetimler gerçekleştirir. Bu nedenle, serileştirme sırasında bir IllegalArgumentException görebilirsiniz. Test sırasında bu değişikliği etkinleştirmek veya devre dışı bırakmak için uyumluluk çerçevesi araçlarını kullanarak ENABLE_STRICT_VALIDATION işaretini değiştirin.
  • ProGuard sorunları: Bazı durumlarda, ProGuard'ı kullanarak uygulamanızı küçültmeye, gizlemeye ve optimize etmeye çalışırsanız java.lang.ClassValue sınıfının eklenmesi soruna neden olur. Sorun, Class.forName("java.lang.ClassValue") ürününün bir sınıfı döndürüp döndürmediğine bağlı olarak çalışma zamanı davranışını değiştiren bir Kotlin kitaplığından kaynaklanır. Uygulamanız, çalışma zamanının java.lang.ClassValue sınıfının kullanılmadığı eski bir sürüme dayalı olarak geliştirildiyse bu optimizasyonlar, computeValue yöntemini java.lang.ClassValue kaynağından türetilen sınıflardan kaldırabilir.

JobScheduler geri çağırmayı ve ağ davranışını güçlendirir

JobScheduler, kullanıma sunulduğundan beri uygulamanızın birkaç saniye içinde onStartJob veya onStopJob ürününden geri dönmesini bekler. Android 14'ten önce, bir iş çok uzun sürerse durur ve sessizce başarısız olur. Uygulamanız Android 14 veya sonraki bir sürümü hedefliyorsa ve ana iş parçacığında verilen süreyi aşıyorsa uygulama, "onStartJob için yanıt yok" veya "onStopJob öğesine yanıt yok" hata mesajıyla bir ANR'yi tetikler. Eşzamansız işleme veya tüm ağır işleri arka plan iş parçacığına taşıma desteği sunan WorkManager'a geçiş yapmayı düşünebilirsiniz.

setRequiredNetworkType veya setRequiredNetwork kısıtlaması kullanılıyorsa JobScheduler, ACCESS_NETWORK_STATE iznini beyan etme zorunluluğu da sunar. Uygulamanız işi planlarken ACCESS_NETWORK_STATE iznini beyan etmiyorsa ve Android 14 veya sonraki bir sürümü hedefliyorsa SecurityException sonucunu verir.

Güvenlik

Örtülü ve bekleyen intent'lerle ilgili kısıtlamalar

Android, Android 14'ü hedefleyen uygulamalar için uygulamaların gizli niyetleri dahili uygulama bileşenlerine aşağıdaki şekillerde göndermesini kısıtlar:

  • Dolaylı amaçlar yalnızca dışa aktarılan bileşenlere yayınlanır. Uygulamalar dışa aktarılmayan bileşenlere yayın yapmak için açık bir intent kullanmalı veya bileşeni dışa aktarılmış olarak işaretlemelidir.
  • Bir uygulama, bileşen veya paket belirtmeyen bir niyetle değişken bir beklemedeki intent oluşturursa sistem artık bir istisna atar.

Bu değişiklikler, kötü amaçlı uygulamaların, uygulamanın dahili bileşenleri tarafından kullanılması amaçlanan gizli amaçlara müdahale etmesini önler.

Örneğin, uygulamanızın manifest dosyasında tanımlanabilecek bir niyet filtresi aşağıda verilmiştir:

<activity
    android:name=".AppActivity"
    android:exported="false">
    <intent-filter>
        <action android:name="com.example.action.APP_ACTION" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Uygulamanız bu etkinliği dolaylı intent kullanarak başlatmaya çalışırsa bir istisna verilir:

Kotlin

// Throws an exception when targeting Android 14.
context.startActivity(Intent("com.example.action.APP_ACTION"))

Java

// Throws an exception when targeting Android 14.
context.startActivity(new Intent("com.example.action.APP_ACTION"));

Uygulamanızın, dışa aktarılmayan etkinliği başlatmak için bunun yerine açık bir amaç kullanması gerekir:

Kotlin

// This makes the intent explicit.
val explicitIntent =
        Intent("com.example.action.APP_ACTION")
explicitIntent.apply {
    package = context.packageName
}
context.startActivity(explicitIntent)

Java

// This makes the intent explicit.
Intent explicitIntent =
        new Intent("com.example.action.APP_ACTION")
explicitIntent.setPackage(context.getPackageName());
context.startActivity(explicitIntent);

Çalışma zamanına kayıtlı yayın alıcıları, dışa aktarma davranışını belirtmelidir

Android 14'ü hedefleyen ve bağlama kayıtlı alıcıları kullanan uygulama ve hizmetlerin, alıcının cihazdaki diğer tüm uygulamalara (sırasıyla RECEIVER_EXPORTED veya RECEIVER_NOT_EXPORTED) aktarılıp aktarılmayacağını belirtmek için bir işaret belirtmesi gerekir. Bu şart, bu alıcılar için Android 13'te kullanıma sunulan özelliklerden yararlanarak uygulamaların güvenlik açıklarına karşı korunmasına yardımcı olur.

Yalnızca sistem yayınlarını alan alıcılar için istisna

Uygulamanız, bir alıcıyı yalnızca Context#registerReceiver yöntemleriyle (ör. Context#registerReceiver()) sistem yayınları için kaydediyorsa alıcıyı kaydederken bir işaret belirtilmemelidir.

Daha güvenli dinamik kod yükleme

Uygulamanız Android 14'ü hedefliyorsa ve Dinamik Kod Yükleme (DCL) kullanıyorsa dinamik olarak yüklenen tüm dosyaların salt okunur olarak işaretlenmesi gerekir. Aksi takdirde, sistem bir istisna atar. Uygulamaların mümkün olduğunca dinamik olarak kod yüklemekten kaçınmasını öneririz. Aksi takdirde, kod yerleştirme veya kodda değişiklik yapılması sonucunda uygulamanın güvenliğinin ihlal edilmesi riski büyük ölçüde artar.

Kodu dinamik olarak yüklemeniz gerekiyorsa dinamik olarak yüklenen dosyayı (DEX, JAR veya APK dosyası gibi) dosya açılır açılmaz ve herhangi bir içerik yazılmadan önce salt okunur olarak ayarlamak için aşağıdaki yaklaşımı uygulayın:

Kotlin

val jar = File("DYNAMICALLY_LOADED_FILE.jar")
val os = FileOutputStream(jar)
os.use {
    // Set the file to read-only first to prevent race conditions
    jar.setReadOnly()
    // Then write the actual file content
}
val cl = PathClassLoader(jar, parentClassLoader)

Java

File jar = new File("DYNAMICALLY_LOADED_FILE.jar");
try (FileOutputStream os = new FileOutputStream(jar)) {
    // Set the file to read-only first to prevent race conditions
    jar.setReadOnly();
    // Then write the actual file content
} catch (IOException e) { ... }
PathClassLoader cl = new PathClassLoader(jar, parentClassLoader);

Halihazırda mevcut olan dinamik olarak yüklenen dosyaları işleyin

Dinamik olarak yüklenen mevcut dosyalar için istisnalar atanmasını önlemek amacıyla, uygulamanızda dinamik olarak tekrar yüklemeyi denemeden önce dosyaları silip yeniden oluşturmanızı öneririz. Dosyaları yeniden oluştururken, yazma zamanında dosyaları salt okunur olarak işaretlemek için yukarıdaki kılavuzu uygulayın. Alternatif olarak, mevcut dosyaları salt okunur olarak yeniden etiketleyebilirsiniz. Ancak bu durumda, uygulamanızı kötü amaçlı işlemlerden korumaya yardımcı olmak için öncelikle dosyaların bütünlüğünü doğrulamanızı (örneğin, dosyanın imzasını güvenilir bir değerle karşılaştırarak) doğrulamanızı önemle tavsiye ederiz.

Etkinliklerin arka planda başlatılmasıyla ilgili ek kısıtlamalar

Sistem, Android 14'ü hedefleyen uygulamalarda uygulamaların arka planda etkinlik başlatmasına izin verilen durumları daha da kısıtlar:

  • Bir uygulama, PendingIntent#send() veya benzer yöntemlerle PendingIntent gönderdiğinde uygulama, bekleyen amacı başlatmak için kendi arka plan etkinliği başlatma ayrıcalıklarını vermek istiyorsa artık bu ayarı etkinleştirmelidir. Kaydolmak için uygulamanın setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED) içeren bir ActivityOptions paketi iletmesi gerekir.
  • Görünür bir uygulama, arka plandaki başka bir uygulamanın bir hizmetini bindService() yöntemini kullanarak bağladığında, görünür uygulamanın bağlı hizmete kendi arka plan etkinliğini başlatma ayrıcalıklarını vermek istemesi durumunda artık bu hizmeti etkinleştirmesi gerekir. İzin verilebilmesi için bindService() yöntemi çağrılırken uygulamanın BIND_ALLOW_ACTIVITY_STARTS işaretini içermesi gerekir.

Bu değişiklikler, kötü amaçlı uygulamaların arka planda rahatsız edici etkinlikler başlatmak üzere API'leri kötüye kullanmasını önleyerek kullanıcıları korumak için mevcut kısıtlamaların kapsamını genişletmektedir.

Sıkıştırılmış yol geçişi

Android 14'ü hedefleyen uygulamalar için Android, Zip Path Traversal Güvenlik Açığını şu şekilde engeller: Zip dosyası giriş adları ".." içeriyorsa veya "/" ile başlıyorsa ZipFile(String) ve ZipInputStream.getNextEntry() bir ZipException atar.

Uygulamalar dalvik.system.ZipPathValidator.clearCallback() yöntemini çağırarak bu doğrulamanın kapsamı dışında kalmayı seçebilir.

Android 14'ü (API düzeyi 34) hedefleyen uygulamalarda MediaProjection#createVirtualDisplay aşağıdaki senaryolardan birinde SecurityException atar:

Uygulamanız, her yakalama oturumundan önce kullanıcıdan izin vermesini istemelidir. Tek bir yakalama oturumu, MediaProjection#createVirtualDisplay üzerindeki tek bir çağrıdır ve her MediaProjection örneği yalnızca bir kez kullanılmalıdır.

Yapılandırma değişikliklerini işleme

Uygulamanızın, yapılandırma değişikliklerini (ekran yönü veya ekran boyutunun değişmesi gibi) gerçekleştirmek için MediaProjection#createVirtualDisplay yöntemini çağırması gerekiyorsa mevcut MediaProjection örneği için VirtualDisplay güncellemesi yapmak üzere aşağıdaki adımları uygulayabilirsiniz:

  1. VirtualDisplay#resize değerini yeni genişlik ve yükseklikle çağırın.
  2. VirtualDisplay#setSurface için yeni genişlik ve yükseklik değerine sahip yeni bir Surface sağlayın.

Geri çağırmayı kaydet

Uygulamanız, kullanıcının yakalama oturumuna devam etmek için izin vermediği durumları ele almak üzere bir geri çağırma kaydetmelidir. Bunu yapmak için Callback#onStop aracını uygulayın ve uygulamanızın ilgili kaynakları (VirtualDisplay ve Surface gibi) yayınlamasını sağlayın.

Uygulamanız bu geri çağırmayı kaydetmezse MediaProjection#createVirtualDisplay tarafından bir IllegalStateException çağrılır.

Güncellenen SDK dışı kısıtlamalar

Android 14, Android geliştiricileriyle yapılan ortak çalışmalara ve en son dahili testlere göre kısıtlanmış SDK dışı arayüzlerin güncellenmiş listelerini içerir. Mümkün olduğunda, SDK olmayan arayüzleri kısıtlamadan önce herkese açık alternatiflerin kullanılabildiğinden emin oluyoruz.

Uygulamanız Android 14'ü hedeflemiyorsa bu değişikliklerden bazıları sizi hemen etkilemeyebilir. Bununla birlikte, şu anda bazı SDK dışı arayüzleri de (uygulamanızın hedef API düzeyine bağlı olarak) kullanabiliyor olsanız da SDK olmayan herhangi bir yöntemi veya alanı kullanmak her zaman uygulamanızın bozulma riskini taşır.

Uygulamanızın SDK olmayan arayüzler kullanıp kullanmadığından emin değilseniz öğrenmek için uygulamanızı test edebilirsiniz. Uygulamanız SDK olmayan arayüzleri kullanıyorsa SDK alternatiflerine geçiş planlamaya başlamanız gerekir. Yine de, bazı uygulamaların SDK dışı arayüzler için geçerli kullanım alanları olduğunu biliyoruz. Uygulamanızdaki bir özellik için SDK dışı arayüz kullanmaya alternatif bulamıyorsanız yeni bir herkese açık API istemeniz gerekir.

Android'in bu sürümündeki değişiklikler hakkında daha fazla bilgi edinmek için Android 14'teki SDK dışı arayüz kısıtlamalarıyla ilgili güncellemeler bölümüne göz atın. Genel olarak SDK olmayan arayüzler hakkında daha fazla bilgi edinmek için SDK olmayan arayüzlerle ilgili kısıtlamalar bölümünü inceleyin.