行為變更:指定 Android 17 以上版本的應用程式

和先前版本一樣,Android 17 也包含可能會影響應用程式的行為變更。以下行為變更僅適用於指定 Android 17 以上版本的應用程式。如果應用程式指定 Android 17 以上版本,建議您視情況修改應用程式,以支援這些行為。

此外,無論應用程式的 targetSdkVersion 為何,請務必查看對所有 Android 17 應用程式有影響的行為變更清單。

使用者體驗和系統 UI

Android 17 包含下列異動項目,旨在打造更一致、直覺的使用者體驗。

記憶體限制小工具

自 Android 17 起,如果應用程式指定 Android 17 (API 級別 37) 以上版本為目標,系統會對 RemoteViews 更新強制執行嚴格的記憶體限制。當應用程式將 RemoteViews 物件傳遞至 AppWidgetManager.updateAppWidget 時,system_server 會計算酬載中所有方向和大小值區的所有圖片資料總記憶體用量。如果總記憶體超過系統上限 (mMaxWidgetBitmapMemory),系統會拒絕更新並擲回 IllegalArgumentException:

java.lang.IllegalArgumentException: RemoteViews for widget update exceeds maximum bitmap memory usage (used: XXXXX, max: YYYYY)

如果應用程式指定 API 級別 36 以下,系統會將這項記憶體違規記錄為警告 (Slog.w),不會擲回例外狀況。

系統如何計算記憶體上限

系統會根據目前顯示設定,將小工具點陣圖記憶體預算設為 6 * width * height 位元組 (1.5 * 4 * width * height,相當於全螢幕 ARGB_8888 緩衝區大小的 1.5 倍)。在 API 級別 37 以上,這項計算會包含下列兩項:

  • 儲存在 RemoteViews.mBitmapCache 中的記憶體內 Bitmap 和點陣圖支援的 Icon 物件 (Icon.TYPE_BITMAP 和 Icon.TYPE_ADAPTIVE_BITMAP),例如呼叫 setImageViewBitmap、Icon.createWithBitmap、Icon.createWithAdaptiveBitmap 或 Jetpack Glance ImageProvider(bitmap)。mBitmapCache 中每個不重複的 Bitmap 或點陣圖支援的 Icon 例項,在每個 RemoteViews 階層中都會計入一次。
  • URI 支援的圖片 (Icon.createWithContentUri、setImageViewUri 或 Glance ImageProvider(uri)) 不會計入 system_server 中的 RemoteViews IPC 位元組上限,但小工具主機程序會將參照的 content:// 檔案以完整解析度解碼至自己的堆積。請務必先將降取樣圖片寫入 context.cacheDir,再透過 FileProvider URI 公開。

緩解步驟

如要確保手機、平板電腦和摺疊式裝置的小工具更新不超過記憶體上限,請按照下列步驟操作:

  1. 從 WindowMetrics 計算執行階段記憶體預算:在 API 級別 30 以上,請從 WindowManager.currentWindowMetrics.bounds 讀取有效視窗邊界,而非 resources.displayMetrics。在多解析度裝置和摺疊式裝置上,displayMetrics 可能會回報未啟用的螢幕尺寸。請將小工具圖片總預算估算為 6L * bounds.width() * bounds.height(),如以下範例所示:

    private const val FALLBACK_MAX_BYTES = 15_000_000L
    
    fun calculateWidgetMemoryCapBytes(context: Context): Long {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            val wm = context.getSystemService(WindowManager::class.java)
                ?: return FALLBACK_MAX_BYTES
            val bounds = wm.currentWindowMetrics.bounds
            return 6L * bounds.width().toLong() * bounds.height().toLong()
        }
        val dm = context.resources.displayMetrics
        return 6L * dm.widthPixels.toLong() * dm.heightPixels.toLong()
    }
    
  2. 將圖片降取樣至小工具的可檢視尺寸,並使用 RGB_565: 使用 2 的乘冪 BitmapFactory.Options.inSampleSize 值解碼點陣圖,其大小應為小工具的最大顯示尺寸 (maxWidthDp 乘以 maxHeightDp),並針對不透明相片和縮圖使用 Bitmap.Config.RGB_565 (每個像素 2 位元組),而非 ARGB_8888 (每個像素 4 位元組)。

  3. 在 Jetpack Glance 中,將點陣圖解碼作業移至 provideContent 外部:使用 SizeMode.Responsive 或 SizeMode.Exact 時,Glance 會針對每個大小值區叫用一次 provideContent lambda。在呼叫 provideContent 之前,在 provideGlance 內解碼每個共用的 Bitmap 一次,讓所有大小值區都參照 RemoteViews.mBitmapCache 中的同一個 Bitmap 執行個體。

  4. 替換圖片時,請使用完整的 updateAppWidget 呼叫:在傳統 AppWidgetProvider 實作中,請避免呼叫 AppWidgetManager.partiallyUpdateAppWidget 來切換 Bitmap 或 Icon 檢視畫面。部分更新會將新動作合併至 system_server 中現有的 RemoteViews 樹狀結構,不會移除先前快取的映像檔動作。請建構完整的 RemoteViews 版面配置,並改為呼叫 updateAppWidget。

  5. 提供錯誤備用版面配置:在 Jetpack Glance 中,覆寫 onCompositionError,在更新失敗時轉譯零點陣圖 RemoteViews 備用版面配置。

如要檢查已連結裝置上小工具目前的序列化點陣圖記憶體用量,請執行下列指令:

adb shell dumpsys appwidget

核心功能

Android 17 包含下列異動項目,這類變更會修改或擴充 Android 系統的各種核心功能。

MessageQueue 的新無鎖定實作

從 Android 17 開始,指定 Android 17 (API 級別 37) 以上版本的應用程式會收到新的無鎖定 android.os.MessageQueue 實作。新實作方式可提升效能並減少影格遺漏,但可能會破壞反映 MessageQueue 私人欄位和方法的用戶端。

如需更多資訊 (包括緩解策略),請參閱 MessageQueue 行為變更指南。

靜態最終欄位現在無法修改

在 Android 17 或更高版本上运行且以 Android 17(API 级别 37)或更高版本为目标平台的应用无法更改 static final 字段。如果应用尝试使用反射来更改 static final 字段,则会导致 IllegalAccessException。尝试通过 JNI API(例如 SetStaticLongField())修改其中一个字段会导致应用崩溃。

無障礙設定

Android 17 進行下列變更,提升無障礙功能。

支援複雜輸入法實體鍵盤輸入的無障礙功能

這項功能導入了新的 AccessibilityEvent 和 TextAttribute API,可強化 CJKV 語言輸入的螢幕閱讀器互動朗讀功能。中日韓越文輸入法應用程式現在可以指出,在文字組合期間是否已選取文字轉換候選字。具有編輯欄位的應用程式,可在傳送文字變更無障礙事件時,指定文字變更類型。舉例來說,應用程式可以指定在文字組合期間發生文字變更,或文字變更是由修訂版本造成。這樣一來,螢幕閱讀器等無障礙服務就能根據文字修改的性質,提供更精確的回饋。

應用程式採用數

  • IME 應用程式:在編輯欄位中設定撰寫文字時,IME 可以使用 TextAttribute.Builder.setTextSuggestionSelected() 指出是否已選取特定轉換候選字。

  • 具有編輯欄位的應用程式:維護自訂 InputConnection 的應用程式可以呼叫 TextAttribute.isTextSuggestionSelected() 擷取候選字詞選取資料。這類應用程式應在調度 TYPE_VIEW_TEXT_CHANGED 事件時呼叫 AccessibilityEvent.setTextChangeTypes()。如果應用程式指定 Android 17 (API 級別 37) 為目標,並使用標準 TextView,則預設會啟用這項功能。(也就是說,TextView 會處理從 IME 擷取資料,並在傳送事件至無障礙服務時設定文字變更類型)。

  • 無障礙服務:處理 TYPE_VIEW_TEXT_CHANGED 事件的無障礙服務可以呼叫 AccessibilityEvent.getTextChangeTypes(),以識別修改的性質並相應調整其回饋策略。

隱私權

Android 17 包含下列異動,可提升使用者隱私。

已啟用 ECH (Encrypted Client Hello)

Android 17 引入了对加密客户端问候 (ECH) 的平台支持,这是一种 TLS 扩展,可通过在 TLS 握手中加密服务器名称指示 (SNI) 来增强用户隐私。这种加密有助于防止网络观察者轻易识别出应用连接到的特定网域。

对于以 Android 17(API 级别 37)或更高版本为目标平台的应用,ECH 用于 TLS 连接。只有在应用使用的网络库(例如 HttpEngine、WebView 或 OkHttp)集成了 ECH 支持,并且远程服务器也支持 ECH 协议时,ECH 才会处于活跃状态。如果无法协商 ECH,客户端会发送包含随机内容的 ECH 扩展程序(一种称为 ECH GREASE 的机制)。如需详细了解 ECH GREASE 的运作方式,请参阅 RFC 9849。

为了允许应用自定义此行为,Android 17 向网络安全配置文件添加了新的 <domainEncryption> 元素。开发者可以在 <base-config> 或 <domain-config> 标记中使用 <domainEncryption>,以全局或按网域选择 ECH 模式(例如 "enabled" 或 "disabled")。

如需了解详情,请参阅加密客户端问候文档。

指定 Android 17 的應用程式需要區域網路權限

Android 17 引入了 ACCESS_LOCAL_NETWORK 运行时权限,以保护用户免遭未经授权的本地网络访问。由于此权限属于现有的 NEARBY_DEVICES 权限组,因此系统不会再次提示已授予其他 NEARBY_DEVICES 权限的用户。这项新要求可防止恶意应用利用不受限制的本地网络访问权限进行隐蔽的用户跟踪和指纹识别。通过声明和请求此权限,您的应用可以发现并连接到局域网 (LAN) 上的设备,例如智能家居设备或投屏接收器。

以 Android 17(API 级别 37)或更高版本为目标平台的应用现在可以通过两种方式与局域网设备保持通信:采用系统介导、可保护隐私的设备选择器来跳过权限提示,或在运行时明确请求这项新权限,以保持本地网络通信。

如需了解详情,请参阅本地网络权限文档。

在實體裝置上隱藏密碼

如果应用以 Android 17(API 级别 37)或更高版本为目标平台,并且用户使用的是实体输入设备(例如外接键盘),则 Android 操作系统会将新的 show_passwords_physical 设置应用于密码字段中的所有字符。默认情况下,该设置会隐藏所有密码字符。

Android 系统会显示最后输入的密码字符,以帮助用户查看是否输错了密码。不过,对于较大的外接键盘,这种需求要小得多。此外,配备外接键盘的设备通常具有更大的显示屏,这会增加他人看到所输入密码的风险。

如果用户使用的是设备的触摸屏,系统会应用新的 show_passwords_touch 设置。

標準簡訊動態密碼防護

從 Android 17 開始,Android 將擴大簡訊動態密碼保護功能,適用於標準簡訊 (包含動態密碼,但不使用 WebOTP 或簡訊擷取器格式的簡訊)。對於大多數指定 Android 17 (API 級別 37) 以上版本的應用程式,這些簡訊在收到後三小時內無法使用。這項延遲措施旨在防止動態密碼遭劫持。在這三小時的延遲期間,系統會保留 SMS_RECEIVED_ACTION 廣播,並篩選簡訊供應商資料庫查詢。延遲時間過後,這些應用程式就能取得簡訊。

某些應用程式 (例如預設簡訊小幫手應用程式、連結裝置隨附應用程式等) 不受這項延遲限制。所有需要讀取簡訊來擷取動態密碼的應用程式,都應改用 SMS Retriever 或 SMS User Consent API,確保功能持續運作。

安全性

Android 17 對裝置和應用程式安全性進行了以下改善。

Activity 安全性

在 Android 17 中,平台持續朝向「預設安全」架構發展,推出一系列強化功能,旨在緩解高嚴重性漏洞,例如網路釣魚、互動劫持和混淆代理攻擊。開發人員必須明確選擇加入新的安全性標準,才能維持應用程式相容性並保護使用者。

對開發人員的主要影響包括:

  • 強化 BAL 並改善選擇加入機制:我們正在調整背景活動啟動 (BAL) 限制,將保護措施擴展至 IntentSender。開發人員必須停止使用舊版 MODE_BACKGROUND_ACTIVITY_START_ALLOWED 常數。建議改用 MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE 等精細控制項,限制只有在呼叫端應用程式可見時,才能啟動活動,大幅縮小攻擊面。
  • 採用工具:開發人員應使用嚴格模式和更新後的 Lint 檢查,找出舊版模式,確保能因應未來的目標 SDK 規定。

預設啟用 CT

如果应用以 Android 17(API 级别 37)或更高版本为目标平台,则默认启用证书透明度 (CT)。(在 Android 16 中,CT 可用,但应用必须选择启用。)

更安全的原生 DCL - C

如果您的应用以 Android 17(API 级别 37)或更高版本为目标平台,Android 14 中针对 DEX 和 JAR 文件引入的更安全的动态代码加载 (DCL) 保护机制现在也适用于原生库。

使用 System.load() 加载的所有原生文件都必须标记为只读。 否则,系统会抛出 UnsatisfiedLinkError。

我们建议应用尽可能避免动态加载代码,因为这样做会大大增加应用因代码注入或代码篡改而遭到入侵的风险。

限制 CP2 資料檢視中的 PII 欄位

如果應用程式指定 Android 17 (API 級別 37) 以上版本,聯絡人供應程式 2 (CP2) 會限制資料檢視中包含個人識別資訊 (PII) 的特定資料欄。這項異動生效後,系統會從資料檢視中移除這些資料欄,進一步保護使用者隱私。受限制的資料欄包括:

如果應用程式使用 ContactsContract.Data 中的這些資料欄,可以改為與 RAW_CONTACT_ID 彙整,從 ContactsContract.RawContacts 擷取這些資料欄。

在 CP2 中強制執行嚴格的 SQL 檢查

对于以 Android 17(API 级别 37)及更高版本为目标平台的应用,如果在没有 READ_CONTACTS 权限的情况下访问 ContactsContract.Data 表,Contacts Provider 2 (CP2) 会强制执行严格的 SQL 查询验证。

做出此项更改后,如果应用没有 READ_CONTACTS 权限,则在查询 ContactsContract.Data 表时会设置 StrictColumns 和 StrictGrammar 选项。如果查询使用的模式与这些模式不兼容,则会被拒绝并导致抛出异常。

情報

Android 17 對系統智慧功能進行了下列變更。

setContentCaptureEnabled 淘汰

部分裝置預設會啟用內容擷取功能,讓裝置端 AI 功能分析畫面內容,提供智慧型體驗。

自 Android 17 起,ContentCaptureManager.setContentCaptureEnabled(boolean) API 方法已淘汰。如果應用程式指定 Android 17 (API 級別 37) 以上版本,呼叫 setContentCaptureEnabled(false) 不會再停用內容擷取功能。

如果應用程式需要繼續停用內容擷取功能,或限制系統擷取螢幕內容,請改用 FLAG_SECURE 視窗版面配置參數。

如要停用內容擷取功能,請在視窗中設定 FLAG_SECURE 標記,如以下範例所示:

Kotlin

window.setFlags(
    WindowManager.LayoutParams.FLAG_SECURE,
    WindowManager.LayoutParams.FLAG_SECURE
)

Java

getWindow().setFlags(
    WindowManager.LayoutParams.FLAG_SECURE,
    WindowManager.LayoutParams.FLAG_SECURE
);

詳情請參閱 WindowManager.LayoutParams.FLAG_SECURE 參考文件。

媒體

Android 17 包含下列媒體行為變更。

背景音訊強化

从 Android 17 开始,音频框架会对后台音频互动(包括音频播放、音频焦点请求和音量更改 API)施加限制,以确保这些更改是由用户有意发起的。

部分音频限制适用于所有应用。不过,如果应用以 Android 17(API 级别 37)为目标平台,则限制会更加严格。如果其中一个应用在后台运行时与音频互动,则必须运行前台服务。此外,应用还必须满足以下一项或两项要求:

  • 前台服务必须具有“仅在使用时允许”(WIU) 功能。
  • 应用必须具有精确闹钟权限,并且正在与 USAGE_ALARM 音频串流互动。

如需了解详情(包括缓解措施),请参阅后台音频安全加固。

裝置板型規格

Android 17 包含下列異動項目,可改善各種裝置尺寸和板型規格的使用者體驗。

平台 API 異動:在大螢幕 (sw>=600dp) 上忽略螢幕方向、大小調整和顯示比例限制

我們在 Android 16 中變更平台 API,針對指定目標 API 級別 36 以上版本的應用程式,忽略大螢幕 (sw >= 600dp) 的螢幕方向、大小調整和顯示比例限制。開發人員可以選擇不採用 SDK 36 的這些變更,但如果應用程式指定 Android 17 (API 級別 37) 以上版本,就無法再選擇不採用。

詳情請參閱「系統會忽略螢幕方向和大小調整限制」。

連線能力

Android 17 推出下列異動,提升藍牙 RFCOMM 通訊端的一致性,並與標準 Java InputStream 行為保持一致。

RFCOMM 的 BluetoothSocket read() 行為一致

如果應用程式指定 Android 17 (API 級別 37) 為目標版本,當通訊端關閉或連線中斷時,從 RFCOMM 型 BluetoothSocket 取得的 InputStream 的 read() 方法現在會傳回 -1。

這項異動可讓 RFCOMM 通訊端行為與 LE CoC 通訊端保持一致,並符合標準 InputStream.read() 說明文件,其中指出到達串流結尾時會傳回 -1。

如果應用程式僅依賴擷取 IOException 來中斷讀取迴圈,可能會受到這項異動影響,因此應更新 BluetoothSocket 讀取迴圈,明確檢查傳回值是否為 -1。這可確保遠端裝置中斷連線或通訊端關閉時,迴圈能正確終止。如需建議導入方式的範例,請參閱「傳輸藍牙資料」指南中的程式碼片段。