Seperti rilis sebelumnya, Android 14 menyertakan perubahan perilaku yang mungkin memengaruhi aplikasi Anda. Perubahan perilaku berikut ini berlaku khusus bagi aplikasi yang menargetkan Android 14 (level API 34) atau yang lebih tinggi. Jika aplikasi Anda menargetkan Android 14 atau yang lebih tinggi, Anda harus memodifikasi aplikasi untuk mendukung perilaku ini dengan benar, jika berlaku.
Pastikan Anda juga meninjau daftar perubahan perilaku yang memengaruhi semua aplikasi yang berjalan di Android 14, terlepas dari targetSdkVersion aplikasi.
Fungsi inti
Jenis layanan latar depan wajib diisi
Jika menargetkan Android 14 (API level 34) atau yang lebih tinggi, aplikasi Anda harus menentukan setidaknya satu jenis layanan latar depan untuk setiap layanan latar depan dalam aplikasi Anda. Anda harus memilih jenis layanan latar depan yang mewakili kasus penggunaan aplikasi. Sistem mengharapkan layanan latar depan yang memiliki jenis tertentu untuk memenuhi kasus penggunaan tertentu.
Jika kasus penggunaan di aplikasi Anda tidak terkait dengan salah satu jenis ini, sebaiknya migrasikan logika untuk menggunakan WorkManager atau tugas transfer data yang dimulai pengguna
Penerapan izin BLUETOOTH_CONNECT di BluetoothAdapter
Android 14 menerapkan izin BLUETOOTH_CONNECT saat memanggil
metode getProfileConnectionState() BluetoothAdapter untuk aplikasi yang menargetkan
Android 14 (level API 34) atau yang lebih tinggi.
Metode ini sudah memerlukan izin BLUETOOTH_CONNECT, tetapi tidak
diterapkan. Pastikan aplikasi Anda mendeklarasikan BLUETOOTH_CONNECT dalam file
AndroidManifest.xml aplikasi seperti yang ditunjukkan dalam cuplikan berikut dan periksa apakah
pengguna telah memberikan izin sebelum memanggil
getProfileConnectionState.
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
Update OpenJDK 17
Android 14 将继续更新 Android 的核心库,以与最新 OpenJDK LTS 版本中的功能保持一致,包括适合应用和平台开发者的库更新和 Java 17 语言支持。
以下变更可能会影响应用兼容性:
- 对正则表达式的更改:现在,为了更严格地遵循 OpenJDK 的语义,不允许无效的组引用。您可能会看到
java.util.regex.Matcher类抛出IllegalArgumentException的新情况,因此请务必测试应用中使用正则表达式的情形。如需在测试期间启用或停用此变更,请使用兼容性框架工具切换DISALLOW_INVALID_GROUP_REFERENCE标志。 - UUID 处理:现在,验证输入参数时,
java.util.UUID.fromString()方法会执行更严格的检查,因此您可能会在反序列化期间看到IllegalArgumentException。如需在测试期间启用或停用此变更,请使用兼容性框架工具切换ENABLE_STRICT_VALIDATION标志。 - ProGuard 问题:有时,在您尝试使用 ProGuard 缩减、混淆和优化应用时,添加
java.lang.ClassValue类会导致问题。问题源自 Kotlin 库,该库会根据Class.forName("java.lang.ClassValue")是否会返回类更改运行时行为。如果您的应用是根据没有java.lang.ClassValue类的旧版运行时开发的,则这些优化可能会将computeValue方法从派生自java.lang.ClassValue的类中移除。
JobScheduler memperkuat perilaku callback dan jaringan
自从引入后,JobScheduler 期望您的应用从
onStartJob 或 onStopJob。在 Android 14 之前,如果作业运行时间过长,系统会停止作业并静默失败。如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台,
超过在主线程上授予的时间,应用会触发 ANR
显示“没有响应 onStartJob”错误消息或
“onStopJob没有回复”。
此 ANR 可能是由以下 2 种情况造成的:
1.有工作阻塞主线程,阻止回调 onStartJob
或者onStopJob在预期时间内执行并完成。
2. 开发者在 JobScheduler 中运行阻塞工作
回调 onStartJob 或 onStopJob,阻止从
在预期的时限内完成
要解决第 1 个问题,您需要进一步调试阻塞主线程的因素
您可以使用以下代码
ApplicationExitInfo#getTraceInputStream(),用于获取 Tombstone
ANR 发生时的跟踪信息如果您能够手动重现 ANR 问题
您可以录制系统轨迹,并使用
Android Studio 或 Perfetto,以便更好地了解应用上运行的
在发生 ANR 时调用主线程
请注意,直接使用 JobScheduler API 或使用 androidx 库 WorkManager 时可能会发生这种情况。
如需解决问题 2,请考虑迁移到 WorkManager,它支持将 onStartJob 或 onStopJob 中的任何处理封装在异步线程中。
JobScheduler 还引入了一项要求,即如果使用 setRequiredNetworkType 或 setRequiredNetwork 约束条件,则必须声明 ACCESS_NETWORK_STATE 权限。如果您的应用未声明
ACCESS_NETWORK_STATE 权限
Android 14 或更高版本,则会导致 SecurityException。
API peluncuran kartu
Untuk aplikasi yang menargetkan 14 dan yang lebih tinggi,
TileService#startActivityAndCollapse(Intent) tidak digunakan lagi dan kini menampilkan
pengecualian saat dipanggil. Jika aplikasi Anda meluncurkan aktivitas dari kartu, gunakan
TileService#startActivityAndCollapse(PendingIntent) sebagai gantinya.
Privasi
Akses sebagian ke foto dan video
Android 14 引入了“已选照片访问权限”,让用户可以向应用授予对其媒体库中特定图片和视频的访问权限,而不是授予对给定类型的所有媒体的访问权限。
只有当您的应用以 Android 14(API 级别 34)或更高版本为目标平台时,此更改才会启用。如果您尚未使用照片选择器,我们建议您在应用中实现照片选择器,以提供一致的图片和视频选择体验,同时增强用户隐私保护,而无需请求任何存储权限。
如果您使用存储权限维护自己的图库选择器,并且需要对实现保持完全控制,请调整实现以使用新的 READ_MEDIA_VISUAL_USER_SELECTED 权限。如果您的应用不使用新权限,系统会以兼容模式运行您的应用。
Pengalaman pengguna
Notifikasi Intent layar penuh yang aman
Dengan Android 11 (API level 30), aplikasi apa pun dapat menggunakan
Notification.Builder.setFullScreenIntent untuk mengirim intent
layar penuh saat ponsel terkunci. Anda dapat memberikannya secara otomatis saat penginstalan aplikasi dengan
mendeklarasikan izin USE_FULL_SCREEN_INTENT di
AndroidManifest.
Notifikasi intent layar penuh dirancang untuk notifikasi dengan prioritas sangat tinggi
yang meminta perhatian segera pengguna, seperti setelan
panggilan telepon masuk atau jam alarm yang dikonfigurasi oleh pengguna. Untuk aplikasi yang menargetkan
Android 14 (API level 34) atau yang lebih tinggi, aplikasi yang diizinkan untuk menggunakan
izin ini terbatas pada aplikasi yang hanya menyediakan panggilan dan alarm. Google
Play Store mencabut izin USE_FULL_SCREEN_INTENT default untuk aplikasi
apa pun yang tidak sesuai dengan profil ini. Batas waktu untuk perubahan kebijakan ini adalah 31 Mei
2024.
Izin ini tetap diaktifkan untuk aplikasi yang diinstal di ponsel sebelum pengguna mengupdate ke Android 14. Pengguna dapat mengaktifkan dan menonaktifkan izin ini.
Anda dapat menggunakan API baru
NotificationManager.canUseFullScreenIntent untuk memeriksa apakah aplikasi
Anda memiliki izin. Jika tidak, aplikasi Anda dapat menggunakan intent baru
ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT untuk meluncurkan halaman
setelan tempat pengguna dapat memberikan izin.
Keamanan
Pembatasan ke intent yang implisit dan tertunda
Untuk aplikasi yang menargetkan Android 14 (API level 34) atau yang lebih tinggi, Android membatasi pengiriman intent implisit ke komponen aplikasi internal dengan cara berikut:
- Intent implisit hanya dikirim ke komponen yang diekspor. Aplikasi harus menggunakan intent eksplisit untuk mengirim ke komponen yang tidak diekspor, atau menandai komponen sebagai diekspor.
- Jika aplikasi membuat intent tertunda yang dapat berubah dengan intent yang tidak menentukan komponen atau paket, sistem akan menampilkan pengecualian.
Perubahan ini mencegah aplikasi berbahaya agar tidak mencegat intent implisit yang dimaksudkan untuk digunakan oleh komponen internal aplikasi.
Misalnya, berikut ini filter intent yang dapat dideklarasikan dalam file manifes aplikasi Anda:
<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>
Jika aplikasi Anda mencoba meluncurkan aktivitas ini menggunakan intent implisit, pengecualian ActivityNotFoundException akan ditampilkan:
Kotlin
// Throws an ActivityNotFoundException exception when targeting Android 14. context.startActivity(Intent("com.example.action.APP_ACTION"))
Java
// Throws an ActivityNotFoundException exception when targeting Android 14. context.startActivity(new Intent("com.example.action.APP_ACTION"));
Untuk meluncurkan aktivitas yang tidak diekspor, aplikasi Anda harus menggunakan intent eksplisit:
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);
Penerima siaran yang terdaftar runtime harus menentukan perilaku ekspor
Aplikasi dan layanan yang menargetkan Android 14 (API level 34) atau yang lebih tinggi dan menggunakan
penerima yang terdaftar dalam konteks harus menentukan flag
untuk menunjukkan apakah penerima harus diekspor ke semua aplikasi lain di
perangkat: RECEIVER_EXPORTED atau RECEIVER_NOT_EXPORTED.
Persyaratan ini membantu melindungi aplikasi dari kerentanan keamanan dengan memanfaatkan
fitur untuk penerima yang diperkenalkan di Android 13 ini.
Pengecualian untuk penerima yang hanya menerima siaran sistem
Jika aplikasi Anda mendaftarkan penerima hanya untuk
siaran sistem melalui metode
Context#registerReceiver, seperti Context#registerReceiver(), aplikasi
tidak boleh menentukan flag saat mendaftarkan penerima.
Pemuatan kode dinamis yang lebih aman
如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台并使用动态代码 正在加载 (DCL),所有动态加载的文件都必须标记为只读。 否则,系统会抛出异常。我们建议应用尽可能避免动态加载代码,因为这样做会大大增加应用因代码注入或代码篡改而遭到入侵的风险。
如果必须动态加载代码,请使用以下方法,在动态文件(例如 DEX、JAR 或 APK 文件)打开并写入任何内容之前立即将其设为只读:
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);
处理已存在的动态加载文件
为防止系统对现有动态加载的文件抛出异常,我们建议您先删除并重新创建文件,然后再尝试在应用中重新动态加载这些文件。重新创建文件时,请按照上述指南在写入时将文件标记为只读。或者,您可以将现有文件重新标记为只读,但在这种情况下,我们强烈建议您先验证文件的完整性(例如,对照可信值检查文件的签名)以保护应用免遭恶意操作的影响。
Batasan tambahan dalam memulai aktivitas dari latar belakang
Untuk aplikasi yang menargetkan Android 14 (API level 34) atau yang lebih tinggi, sistem akan lebih membatasi kapan aplikasi diizinkan untuk memulai aktivitas dari latar belakang:
- Saat mengirim
PendingIntentmenggunakanPendingIntent#send()atau metode serupa, aplikasi harus memilih ikut serta jika ingin memberikan hak istimewa peluncuran aktivitas latar belakangnya sendiri untuk memulai intent yang tertunda. Untuk ikut serta, aplikasi harus meneruskan paketActivityOptionsdengansetPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED). - Saat aplikasi yang terlihat mengikat layanan dari aplikasi lain yang ada di latar belakang
menggunakan metode
bindService(), aplikasi yang terlihat kini harus memilih ikut serta jika ingin memberikan hak istimewa peluncuran aktivitas latar belakangnya ke layanan terikat. Untuk ikut serta, aplikasi harus menyertakan flagBIND_ALLOW_ACTIVITY_STARTSsaat memanggil metodebindService().
Perubahan ini memperluas rangkaian pembatasan yang ada untuk melindungi pengguna dengan mencegah aplikasi berbahaya agar tidak menyalahgunakan API untuk memulai aktivitas yang mengganggu dari latar belakang.
Zip path traversal
Untuk aplikasi yang menargetkan Android 14 (API level 34) atau yang lebih tinggi, Android mencegah Kerentanan Zip
Path Traversal dengan cara berikut:
ZipFile(String) dan
ZipInputStream.getNextEntry() menampilkan
ZipException jika nama entri file zip berisi ".." atau dimulai
dengan "/".
Aplikasi dapat memilih untuk tidak mengikuti validasi ini dengan memanggil
dalvik.system.ZipPathValidator.clearCallback().
Izin pengguna diperlukan untuk setiap sesi pengambilan MediaProjection
Untuk aplikasi yang menargetkan Android 14 (API level 34) atau yang lebih tinggi, SecurityException
akan ditampilkan oleh MediaProjection#createVirtualDisplay dalam salah satu skenario
berikut:
- Aplikasi Anda menyimpan dalam cache
Intentyang ditampilkan dariMediaProjectionManager#createScreenCaptureIntent, dan meneruskannya beberapa kali keMediaProjectionManager#getMediaProjection. - Aplikasi Anda memanggil
MediaProjection#createVirtualDisplaybeberapa kali pada instanceMediaProjectionyang sama.
Aplikasi Anda harus meminta pengguna untuk memberikan izin sebelum setiap sesi pengambilan. Satu sesi pengambilan adalah satu pemanggilan di MediaProjection#createVirtualDisplay, dan setiap instance MediaProjection hanya boleh digunakan satu kali.
Menangani perubahan konfigurasi
Jika aplikasi Anda perlu memanggil MediaProjection#createVirtualDisplay untuk menangani
perubahan konfigurasi (seperti perubahan orientasi layar atau ukuran layar),
Anda dapat mengikuti langkah-langkah berikut untuk mengupdate VirtualDisplay untuk instance
MediaProjection yang ada:
- Panggil
VirtualDisplay#resizedengan lebar dan tinggi baru. - Berikan
Surfacebaru dengan lebar dan tinggi baru keVirtualDisplay#setSurface.
Mendaftarkan callback
Aplikasi Anda harus mendaftarkan callback untuk menangani kasus saat pengguna tidak memberikan
izin untuk melanjutkan sesi pengambilan. Untuk melakukannya, terapkan
Callback#onStop dan minta aplikasi Anda merilis resource terkait (seperti
VirtualDisplay dan Surface).
Jika aplikasi Anda tidak mendaftarkan callback ini,
MediaProjection#createVirtualDisplay akan menampilkan IllegalStateException
saat aplikasi Anda memanggilnya.
Pembatasan non-SDK yang diperbarui
Android 14 menyertakan daftar terbaru antarmuka non-SDK yang dibatasi berdasarkan kolaborasi dengan developer Android dan pengujian internal terbaru. Jika memungkinkan, kami akan memastikan ketersediaan alternatif publik sebelum membatasi antarmuka non-SDK.
Jika aplikasi Anda tidak menargetkan Android 14, beberapa perubahan ini mungkin tidak langsung memengaruhi Anda. Namun, meskipun saat ini Anda dapat menggunakan beberapa antarmuka non-SDK (bergantung pada API level target aplikasi Anda), penggunaan metode atau kolom non-SDK tetap sangat berisiko merusak aplikasi Anda.
Jika tidak yakin apakah aplikasi Anda menggunakan antarmuka non-SDK atau tidak, Anda dapat menguji aplikasi untuk mencari tahu. Jika aplikasi Anda mengandalkan antarmuka non-SDK, sebaiknya mulailah merencanakan migrasi ke alternatif SDK. Meskipun begitu, kami paham bahwa beberapa aplikasi memiliki kasus penggunaan yang valid untuk menggunakan antarmuka non-SDK. Jika tidak dapat menemukan alternatif penggunaan antarmuka non-SDK untuk fitur dalam aplikasi Anda, sebaiknya minta API publik baru.
如需详细了解此 Android 版本中的变更,请参阅 Android 14 中有关限制非 SDK 接口的更新。如需全面了解有关非 SDK 接口的详细信息,请参阅对非 SDK 接口的限制。