Android 17 平台包含可能對應用程式造成影響的行為變更。無論 targetSdkVersion 為何,凡是在 Android 17 上執行的應用程式,「一律」都會受到下列行為變更所影響。您必須測試自己的應用程式,並視需要進行修改,以便在適當情況下支援這些變更。
另請務必查看僅對指定 Android 17 為目標版本的應用程式造成影響的行為變更。
核心功能
Android 17 (API 級別 37) 包含下列異動項目,這類變更會修改或擴充 Android 系統的各種核心功能。
應用程式記憶體限制
Android 17 根據裝置的總 RAM 推出應用程式記憶體限制,為應用程式和 Android 使用者打造更穩定、更確定的環境。這些限制著重於記憶體流失和其他異常狀況,避免觸發系統不穩定,導致 UI 延遲、電池耗電量增加,以及應用程式遭到終止。雖然我們預期絕大多數應用程式工作階段受到的影響微乎其微,但仍建議您遵循下列記憶體最佳做法,包括建立記憶體基準。
您可以呼叫 ApplicationExitInfo 中的 getDescription,判斷應用程式工作階段是否受到影響。如果應用程式受到影響,結束原因會是 REASON_OTHER,說明則會包含 "MemoryLimiter:AnonSwap" 字串和其他資訊。您也可以搭配 TRIGGER_TYPE_ANOMALY 使用觸發條件式剖析,取得在達到記憶體限制時收集的記憶體快照資料。
「管理應用程式的記憶體」說明文件提供相關資訊,協助您診斷應用程式的記憶體問題,並最佳化資源消耗量。
測試應用程式在記憶體限制下的行為
您可以使用 Android Debug Bridge (adb),在任何裝置上調整或停用記憶體限制。殼層指令 am 提供三個子指令,可用於調整記憶體限制。(如果裝置未施加記憶體限制,這些指令就不會產生任何作用)。
am memory-limiter ignore <uid>|none|allam memory-limiter manual <pid> <limit>|max|noneam memory-limiter status
ignore指示記憶體限制器忽略部分或所有程序。傳遞 UID (Android 使用者 ID),指示記憶體限制器忽略與該 UID 相關聯的所有程序。您也可以傳遞
all(忽略所有應用程式) 或none(不忽略任何應用程式)。傳遞none會覆寫先前對am memory-limiter ignore的任何呼叫。如果指示記憶體限制器忽略 UID,您仍可呼叫
am memory-limiter manual,對應用程式中的程序套用手動記憶體限制。manual指示系統對指定 PID (程序 ID) 的程序施加記憶體限制。記憶體限制是以 MB 為單位的整數,例如傳遞
30會指定程序限制為 30 MB 的記憶體。傳遞max會移除該程序的所有記憶體限制。傳遞none會移除程序中設定的所有手動限制,並還原系統的預設限制 (如有)。status回報記憶體限制器的目前狀態。狀態包括對可見和不可見程序施加的記憶體限制。
隱私權
Android 17 包含下列異動,可提升使用者隱私。
簡訊動態密碼防護
從 Android 17 開始,Android 將擴大保護含有動態密碼 (OTP) 的簡訊。
在舊版 Android 中,這項保護措施主要著重於簡訊擷取器格式。對於大多數應用程式,含有簡訊擷取器雜湊的訊息傳送作業延遲了三小時。不過,某些應用程式 (例如預設簡訊處理常式) 和擁有雜湊的應用程式不受延遲影響。
從 Android 17 開始,這項保護措施也適用於 WebOTP 格式訊息。如果應用程式有權讀取簡訊,但不是 WebOTP 訊息的預定接收者 (由網域驗證決定),則在收到訊息後三小時內,應用程式無法存取該訊息。這項異動旨在提升使用者安全性,確保只有與訊息中提及的網域相關聯的應用程式,才能以程式輔助方式讀取驗證碼。
在這三小時的延遲期間,系統會暫緩 SMS_RECEIVED_ACTION 廣播,並篩除「簡訊供應商」資料庫查詢。延遲時間過後,這些應用程式就能取得簡訊。這項異動適用於所有應用程式,無論目標 API 級別為何。
某些應用程式 (例如預設簡訊小幫手應用程式、連結裝置隨附應用程式等) 不受這項延遲限制。所有需要讀取簡訊來擷取動態密碼的應用程式,都應改用 SMS Retriever 或 SMS User Consent API,確保功能持續運作。
安全性
Android 17 對裝置和應用程式安全性進行了下列改善。
usesClearTraffic 淘汰計畫
In a future release, we plan to deprecate the usesCleartextTraffic element.
Apps that need to make unencrypted (HTTP) connections should migrate to
using a network security configuration file, which lets you
specify which domains your app needs to make cleartext connections to.
Be aware that network security configuration files are only supported on API levels 24 and higher. If your app has a minimum API level lower than 24, you should do both of the following:
- Set the
usesCleartextTrafficattribute totrue - Use a network configuration file
If your app's minimum API level is 24 or higher, you can use a network
configuration file and you don't need to set usesCleartextTraffic.
限制隱含 URI 授權
目前,如果應用程式啟動的意圖含有動作 ACTION_SEND、ACTION_SEND_MULTIPLE 或 ACTION_IMAGE_CAPTURE 的 URI,系統會自動將讀取和寫入 URI 權限授予目標應用程式。從 Android 18 開始,系統不會再自動授予這些權限。因此,建議應用程式明確授予相關 URI 權限,而非依賴系統授予。
如要偵測應用程式中這些意圖的使用情形,請搭配使用 StrictMode 和 detectImplicitUriPermissionGrant() 觸發違規:
Kotlin
val policy = StrictMode.VmPolicy.Builder() .detectImplicitUriPermissionGrant() .penaltyLog() .build() StrictMode.setVmPolicy(policy)
Java
StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder() .detectImplicitUriPermissionGrant() .penaltyLog() .build(); StrictMode.setVmPolicy(policy);
或者,您也可以監控記錄的例外狀況,其中包含系統隱含設定授權時顯示的訊息 Please set the grant explicitly in the app。您可以使用下列 adb 指令監控這些記錄:
adb logcat | grep "Please set the grant explicitly in the app"
如要明確授予必要權限,請將 FLAG_GRANT_READ_URI_PERMISSION 旗標新增至 ACTION_SEND 和 ACTION_SEND_MULTIPLE 意圖:
Kotlin
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
Java
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
為 ACTION_IMAGE_CAPTURE 意圖加入 FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION 旗標:
Kotlin
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
Java
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
個別應用程式金鑰庫限制
应用应避免在 Android 密钥库中创建过多密钥,因为密钥库是设备上所有应用的共享资源。从 Android 17 开始,系统会强制限制应用可以拥有的密钥数量。对于以 Android 17(API 级别 37)或更高版本为目标平台的非系统应用,此限制为 50,000 个键;对于所有其他应用,此限制为 200,000 个键。系统应用的密钥数量上限为 20 万,无论其目标 API 级别为何。
如果应用尝试创建超出限制的密钥,则创建会失败,并显示 KeyStoreException。异常的消息字符串包含有关键限制的信息。如果应用对异常调用 getNumericErrorCode(),则返回值取决于应用的目标 API 级别:
- 以 Android 17(API 级别 37)或更高版本为目标平台的应用:
getNumericErrorCode()会返回新的ERROR_TOO_MANY_KEYS值。 - 所有其他应用:
getNumericErrorCode()会返回ERROR_INCORRECT_USAGE。
封鎖跨設定檔回送流量
自 Android 17 起,系統預設不再允許跨設定檔回送流量。同一設定檔內的回送流量不受影響。無論應用程式指定的 API 級別為何,這項異動適用於在 Android 17 以上版本執行的所有應用程式。
使用者體驗和系統 UI
Android 17 包含下列異動項目,旨在打造更一致、直覺的使用者體驗。
裝置旋轉後自動恢復預設的 IME 版面空間
从 Android 17 开始,当设备的配置发生变化(例如,通过旋转)且应用本身未处理此变化时,系统不会恢复之前的 IME 可见性。
如果您的应用发生其无法处理的配置更改,并且应用需要在更改后显示键盘,您必须明确请求显示键盘。您可以通过以下任一方式提出此请求:
- 将
android:windowSoftInputMode属性设置为stateAlwaysVisible。 - 在 activity 的
onCreate()方法中以编程方式请求软键盘,或添加onConfigurationChanged()方法。
手動輸入
Android 17 包含下列異動項目,會影響應用程式與鍵盤和觸控板等人機輸入裝置互動的方式。
在指標擷取期間,觸控板預設會傳送相對事件
Beginning with Android 17, if an app requests pointer capture using
View.requestPointerCapture() and the user uses a touchpad, the system
recognizes pointer movement and scrolling gestures from the user's touches and
reports them to the app in the same way as pointer and scroll wheel movements
from a captured mouse. In most cases, this removes the need for apps that
support captured mice to add special handling logic for touchpads. For more
details, see the documentation for View.POINTER_CAPTURE_MODE_RELATIVE.
Previously, the system did not attempt to recognize gestures from the touchpad,
and instead delivered the raw, absolute finger locations to the app in a similar
format to touchscreen touches. If an app still requires this absolute data, it
should call the new View.requestPointerCapture(int) method with
View.POINTER_CAPTURE_MODE_ABSOLUTE instead.
媒體
Android 17 包含下列媒體行為變更。
背景音訊強化
从 Android 17 开始,音频框架会对后台音频互动(包括音频播放、音频焦点请求和音量更改 API)施加限制,以确保这些更改是由用户有意发起的。
如果应用在不处于有效生命周期时尝试调用音频 API,音频播放和音量更改 API 会静默失败,而不会抛出异常或提供失败消息。音频焦点 API 失败,结果代码为 AUDIOFOCUS_REQUEST_FAILED。
如需了解详情(包括缓解措施),请参阅后台音频安全加固。
連線能力
Android 17 包含下列異動項目,可強化裝置連線能力。
藍牙連線中斷時自動重新配對
Android 17 introduces autonomous re-pairing, a system-level enhancement designed to automatically resolve Bluetooth bond loss.
Previously, if a bond was lost, users had to manually navigate to Settings to unpair and then re-pair the peripheral. This feature builds upon the security improvement of Android 16 by enabling the system to re-establish bonds after user consent is granted. This eliminates the need for users to manually navigate to Settings to unpair and re-pair peripherals.
While most apps will not require code changes, developers should be aware of the following behavior changes in Bluetooth stack:
- New pairing context: The
ACTION_PAIRING_REQUESTnow includes theEXTRA_PAIRING_CONTEXTextra which allows apps to distinguish between a standard pairing request and an autonomous system-initiated re-pairing attempt. - Conditional key updates: Existing security keys will only be replaced if the re-pairing is successful and new connection meets or exceeds the security level of the previous bond.
- Modified intent timing: The
ACTION_KEY_MISSINGintent is now broadcast only if the autonomous re-pairing attempt fails. This reduces unnecessary error handling in the app if the system successfully recovers the bond in the background. - User notification: The system manages re-pairing via new UI notifications and dialogs. Users will be prompted to confirm the re-pairing attempt to ensure they are aware of the reconnection.
Peripheral device manufacturers and companion app developers should verify that hardware and app gracefully handle bond transitions. To test this behavior, simulate a remote bond loss using either of the following methods:
- Manually remove the bond information from the peripheral device
- Manually unpair the device in: Settings > Connected devices