和先前版本一樣,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),而不会抛出异常。
Android skills
在 GitHub 上查看管理 AppWidget 更新和位图内存
android skills add glance-appwidget-updates-and-memory系统如何计算内存上限
系统会将活跃显示配置的 widget 位图内存预算设置为 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 GlanceImageProvider(bitmap)的调用。mBitmapCache中每个唯一的Bitmap或位图支持的Icon实例在每个RemoteViews层次结构中都会被计数一次。 - URI 支持的图片(
Icon.createWithContentUri、setImageViewUri或 GlanceImageProvider(uri))不计入system_server中的RemoteViewsIPC 字节上限,但 widget 宿主进程会以完整分辨率将引用的content://文件解码到其自己的堆中。在通过FileProviderURI 公开降采样图片之前,请务必先将其写入context.cacheDir。
缓解步骤
为了确保在手机、平板电脑和可折叠设备上,微件更新不会超出内存上限,请执行以下操作:
根据
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() }将图片降采样到微件的可查看尺寸,并使用
RGB_565:使用 2 的幂BitmapFactory.Options.inSampleSize值(大小为微件的最大显示尺寸 [maxWidthDpxmaxHeightDp])解码位图,并对不透明的照片和缩略图使用Bitmap.Config.RGB_565(每个像素2字节)而不是ARGB_8888(每个像素4字节)。在 Jetpack Glance 中,将位图解码提升到
provideContent之外:使用SizeMode.Responsive或SizeMode.Exact时,Glance 会针对每个尺寸分桶调用一次provideContentlambda。在调用provideContent之前,在provideGlance中对每个共享的Bitmap解码一次,以便所有大小存储桶都引用RemoteViews.mBitmapCache中的同一Bitmap实例。替换图片时使用完整的
updateAppWidget调用:在传统AppWidgetProvider实现中,避免调用AppWidgetManager.partiallyUpdateAppWidget来交换Bitmap或Icon视图。部分更新会将新操作合并到system_server中的现有RemoteViews树中,而不会逐出之前缓存的映像操作。构建完整的RemoteViews布局,并改为调用updateAppWidget。提供错误后备布局:在 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)或更高版本为目标平台的应用,这些短信在收到 3 小时后才可供使用。此延迟旨在帮助防止动态密码被劫持。在这 3 小时的延迟期间,SMS_RECEIVED_ACTION 广播会被扣留,短信提供商数据库查询会被过滤。延迟后,这些应用便可收到短信。
某些应用(例如默认短信助理应用、已连接设备的配套应用等)不受此延迟的影响。所有依赖读取短信来提取动态密码的应用都应改用 SMS Retriever 或 SMS User Consent API,以确保功能正常运行。
安全性
Android 17 對裝置和應用程式安全性進行了以下改善。
Activity 安全性
在 Android 17 中,平台继续向“默认安全”架构转变,引入了一系列旨在缓解高严重性漏洞利用(例如钓鱼式攻击、互动劫持和混淆代理攻击)的增强功能。此次更新要求开发者明确选择启用新的安全标准,以保持应用兼容性并保护用户。
对开发者产生的主要影响包括:
- BAL 强化和改进的选择启用:我们正在优化后台 activity 启动 (BAL) 限制,将保护范围扩展到
IntentSender。开发者必须停止使用旧版MODE_BACKGROUND_ACTIVITY_START_ALLOWED常量。相反,您应该采用精细控制,例如MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE,它会将 activity 启动限制在调用应用可见的场景中,从而显著减少攻击面。 - 采用工具:开发者应利用严格模式和更新后的 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。這可確保遠端裝置中斷連線或通訊端關閉時,迴圈能正確終止。如需建議導入方式的範例,請參閱「傳輸藍牙資料」指南中的程式碼片段。