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 baru. Jika aplikasi menargetkan Android 14 atau yang lebih tinggi, Anda harus memodifikasi aplikasi agar mendukung perilaku ini dengan benar, jika berlaku.
Selain itu, pastikan Anda 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
如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台,则必须为应用中的每项前台服务指定至少一个前台服务类型。您应该选择一个能够代表应用用例的前台服务类型。系统需要特定类型的前台服务满足特定用例。
如果应用中的用例与这些类型均不相关,强烈建议您迁移逻辑以使用 WorkManager 或用户发起的数据传输作业。
Penerapan izin BLUETOOTH_CONNECT di BluetoothAdapter
Android 14 在调用BLUETOOTH_CONNECT
BluetoothAdapter
用于应用定位的 getProfileConnectionState()
方法
Android 14(API 级别 34)或更高版本。
此方法已需要 BLUETOOTH_CONNECT
权限,但这不是必需的
强制执行。请确保您的应用在应用的BLUETOOTH_CONNECT
AndroidManifest.xml
文件(如以下代码段所示)检查
在调用之前
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 memperkenalkan Akses Foto yang Dipilih, yang memungkinkan pengguna memberikan akses ke gambar dan video tertentu di galeri foto mereka, bukan memberikan akses ke semua media dari jenis tertentu.
Perubahan ini hanya diaktifkan jika aplikasi Anda menargetkan Android 14 (API level 34) atau yang lebih tinggi. Jika Anda belum menggunakan pemilih foto, sebaiknya terapkan di aplikasi Anda untuk memberikan pengalaman yang konsisten saat memilih gambar dan video yang juga meningkatkan privasi pengguna tanpa harus meminta izin penyimpanan apa pun.
Jika Anda mengelola alat pilih galeri sendiri menggunakan izin penyimpanan dan perlu
memiliki kontrol penuh atas penerapan Anda, sesuaikan penerapan Anda
untuk menggunakan izin READ_MEDIA_VISUAL_USER_SELECTED
yang baru. Jika aplikasi
tidak menggunakan izin baru, sistem akan menjalankan aplikasi dalam mode
kompatibilitas.
Pengalaman pengguna
Notifikasi Intent layar penuh yang aman
Dengan Android 11 (level API 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
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
对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,Android 会限制应用 将隐式 intent 发送到内部应用组件:
- 隐式 intent 只能传送到导出的组件。应用必须使用显式 intent 传送到未导出的组件,或将该组件标记为已导出。
- 如果应用使用 指定组件或软件包,系统会抛出异常。
这些变更可防止恶意应用拦截意在供应用内部组件使用的隐式 intent。
例如,下面是可以在应用的清单文件中声明的 intent 过滤器:
<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>
如果应用尝试使用隐式 intent 启动此 activity,则系统会抛出异常:
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"));
如需启动非导出的 activity,应用应改用显式 intent:
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 (level API 34) atau yang lebih tinggi dan menggunakan
penerima yang terdaftar dalam konteks wajib menentukan tanda
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 ini yang diperkenalkan di Android 13.
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 tersebut.
Pemuatan kode dinamis yang lebih aman
Jika aplikasi Anda menargetkan Android 14 (API level 34) atau yang lebih baru dan menggunakan Dynamic Code Memuat (DCL), semua file yang dimuat secara dinamis harus ditandai sebagai hanya baca. Jika tidak, sistem akan menampilkan pengecualian. Sebaiknya aplikasi menghindari memuat kode secara dinamis jika memungkinkan, karena hal itu akan sangat meningkatkan risiko aplikasi disusupi oleh injeksi kode atau sabotase kode.
Jika Anda harus memuat kode secara dinamis, gunakan pendekatan berikut untuk menetapkan file yang dimuat secara dinamis (seperti file DEX, JAR, atau APK) sebagai file hanya baca, segera setelah file dibuka dan sebelum konten apa pun ditulis:
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);
Menangani file yang dimuat secara dinamis dan sudah ada
Agar pengecualian tidak ditampilkan untuk file yang dimuat secara dinamis dan sudah ada, sebaiknya hapus dan buat ulang file sebelum Anda mencoba lagi memuatnya secara dinamis di aplikasi Anda. Saat Anda membuat ulang file, ikuti panduan sebelumnya untuk menandai file sebagai hanya baca pada waktu penulisan. Atau, Anda dapat melabeli ulang file yang ada sebagai hanya baca, tetapi dalam kasus ini, kami sangat menyarankan Anda untuk memverifikasi integritas file terlebih dahulu (misalnya dengan memeriksa tanda tangan file terhadap nilai tepercaya) untuk membantu melindungi aplikasi Anda dari tindakan berbahaya.
Batasan tambahan dalam memulai aktivitas dari latar belakang
对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,系统会进一步限制允许应用在后台启动 activity 的时间:
- 现在,当应用使用
PendingIntent#send()
或类似方法发送PendingIntent
时,如果它想要授予自己的后台 activity 启动待处理 intent 的启动特权,则必须选择启用。如需选择启用,应用应通过setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
传递ActivityOptions
软件包。 - 当可见应用绑定了另一个后台应用的服务时
bindService()
方法,可见应用现在必须 如果它想要将自己的后台活动 绑定服务。要选择启用,应用应包含BIND_ALLOW_ACTIVITY_STARTS
标志,在调用bindService()
方法。
这些更改扩大了一组现有限制条件的范围,目的是防止恶意应用滥用 API 以在后台启动干扰性活动,从而保护用户。
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 diawali
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
ditampilkan oleh MediaProjection#createVirtualDisplay
dalam salah satu skenario
berikut:
- Aplikasi Anda meng-cache
Intent
yang ditampilkan dariMediaProjectionManager#createScreenCaptureIntent
, dan meneruskannya beberapa kali keMediaProjectionManager#getMediaProjection
. - Aplikasi Anda memanggil
MediaProjection#createVirtualDisplay
beberapa kali pada instanceMediaProjection
yang sama.
Aplikasi Anda harus meminta pengguna untuk memberikan izin sebelum setiap sesi pengambilan gambar. Sesi pengambilan tunggal adalah panggilan tunggal pada MediaProjection#createVirtualDisplay
, dan setiap instance MediaProjection
hanya boleh digunakan sekali.
Menangani perubahan konfigurasi
Jika aplikasi perlu memanggil MediaProjection#createVirtualDisplay
untuk menangani
perubahan konfigurasi (seperti orientasi layar atau perubahan ukuran layar),
Anda dapat mengikuti langkah-langkah berikut untuk mengupdate VirtualDisplay
untuk instance
MediaProjection
yang sudah ada:
- Panggil
VirtualDisplay#resize
dengan lebar dan tinggi yang baru. - Berikan
Surface
baru dengan lebar dan tinggi yang baru keVirtualDisplay#setSurface
.
Mendaftarkan callback
Aplikasi Anda harus mendaftarkan callback untuk menangani kasus saat pengguna tidak memberikan izin untuk melanjutkan sesi perekaman. Untuk melakukannya, implementasikan
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 memanggil callback tersebut.
Pembatasan non-SDK yang diperbarui
Android 14 包含更新后的受限非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。在限制使用非 SDK 接口之前,我们会尽可能确保有可用的公开替代方案。
如果您的应用并非以 Android 14 为目标平台,其中一些变更可能不会立即对您产生影响。然而,虽然您目前仍可以使用一些非 SDK 接口(具体取决于应用的目标 API 级别),但只要您使用任何非 SDK 方法或字段,终归存在导致应用出问题的显著风险。
如果您不确定自己的应用是否使用了非 SDK 接口,则可以测试您的应用来进行确认。如果您的应用依赖于非 SDK 接口,您应该开始计划迁移到 SDK 替代方案。然而,我们知道某些应用具有使用非 SDK 接口的有效用例。如果您无法为应用中的某项功能找到使用非 SDK 接口的替代方案,应请求新的公共 API。
Untuk mempelajari perubahan dalam rilis Android ini lebih lanjut, baca Pembaruan pembatasan antarmuka non-SDK di Android 14. Untuk mempelajari lebih lanjut antarmuka non-SDK secara umum, baca Pembatasan antarmuka non-SDK.