Thay đổi về hành vi: Ứng dụng nhắm đến Android 17 trở lên

Giống như các bản phát hành trước, Android 17 có các thay đổi về hành vi có thể ảnh hưởng đến ứng dụng của bạn. Những thay đổi về hành vi sau đây chỉ áp dụng cho ứng dụng nhắm đến Android 17 trở lên. Nếu ứng dụng của bạn nhắm đến Android 17 trở lên, bạn nên điều chỉnh ứng dụng để hỗ trợ những hành vi này (nếu cần).

Ngoài ra, hãy nhớ tham khảo danh sách thay đổi về hành vi ảnh hưởng đến tất cả ứng dụng chạy trên Android 17 bất kể targetSdkVersion của ứng dụng.

Trải nghiệm người dùng và giao diện người dùng hệ thống

Android 17 có những thay đổi sau đây nhằm mang lại trải nghiệm người dùng nhất quán và trực quan hơn.

Tiện ích giới hạn bộ nhớ

从 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),而不会抛出异常。

系统如何计算内存上限

系统会将活跃显示配置的 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 Glance ImageProvider(bitmap) 的调用。mBitmapCache 中每个唯一的 Bitmap 或位图支持的 Icon 实例在每个 RemoteViews 层次结构中都会被计数一次。
  • URI 支持的图片(Icon.createWithContentUri、setImageViewUri 或 Glance ImageProvider(uri))不计入 system_server 中的 RemoteViews IPC 字节上限,但 widget 宿主进程会以完整分辨率将引用的 content:// 文件解码到其自己的堆中。在通过 FileProvider URI 公开降采样图片之前,请务必先将其写入 context.cacheDir。

缓解步骤

为了确保在手机、平板电脑和可折叠设备上,微件更新不会超出内存上限,请执行以下操作:

  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 x 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

Chức năng cốt lõi

Android 17 có những thay đổi sau đây nhằm sửa đổi hoặc mở rộng nhiều chức năng cốt lõi của hệ thống Android.

Cách triển khai MessageQueue mới không cần khoá

Kể từ Android 17, các ứng dụng nhắm đến Android 17 (cấp độ API 37) trở lên sẽ nhận được một phương thức triển khai mới không khoá của android.os.MessageQueue. Cách triển khai mới giúp cải thiện hiệu suất và giảm số khung hình bị bỏ lỡ, nhưng có thể làm hỏng các ứng dụng khách phản ánh trên các trường và phương thức riêng tư của MessageQueue.

Để biết thêm thông tin, bao gồm cả các chiến lược giảm thiểu, hãy xem Hướng dẫn về thay đổi hành vi của MessageQueue.

Các trường cuối cùng tĩnh hiện không thể sửa đổi

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

Hỗ trợ tiếp cận

Android 17 có những thay đổi sau đây để cải thiện khả năng hỗ trợ tiếp cận.

Hỗ trợ tiếp cận cho thao tác nhập phức tạp bằng bàn phím vật lý IME

Tính năng này giới thiệu các API AccessibilityEvent và TextAttribute mới để cải thiện tính năng phản hồi bằng giọng nói của trình đọc màn hình cho phương thức nhập ngôn ngữ CJKV. Giờ đây, các ứng dụng IME CJKV có thể báo hiệu liệu một đề xuất chuyển đổi văn bản đã được chọn trong quá trình soạn văn bản hay chưa. Ứng dụng có trường chỉnh sửa có thể chỉ định loại thay đổi văn bản khi gửi sự kiện hỗ trợ tiếp cận đã thay đổi văn bản. Ví dụ: ứng dụng có thể chỉ định rằng thay đổi văn bản đã xảy ra trong quá trình soạn văn bản hoặc thay đổi văn bản là kết quả của một thay đổi. Việc này cho phép các dịch vụ hỗ trợ tiếp cận (chẳng hạn như trình đọc màn hình) cung cấp ý kiến phản hồi chính xác hơn dựa trên bản chất của việc sửa đổi văn bản.

Số ứng dụng sử dụng

  • Ứng dụng IME: Khi đặt văn bản soạn thảo trong các trường chỉnh sửa, IME có thể sử dụng TextAttribute.Builder.setTextSuggestionSelected() để cho biết liệu một đề xuất chuyển đổi cụ thể đã được chọn hay chưa.

  • Ứng dụng có trường chỉnh sửa: Ứng dụng duy trì InputConnection tuỳ chỉnh có thể truy xuất dữ liệu lựa chọn đề xuất bằng cách gọi TextAttribute.isTextSuggestionSelected(). Sau đó, các ứng dụng này sẽ gọi AccessibilityEvent.setTextChangeTypes() khi gửi sự kiện TYPE_VIEW_TEXT_CHANGED. Những ứng dụng nhắm đến Android 17 (API cấp 37) sử dụng TextView tiêu chuẩn sẽ được bật tính năng này theo mặc định. (Tức là TextView sẽ xử lý việc truy xuất dữ liệu từ IME và đặt các loại thay đổi văn bản khi gửi sự kiện đến dịch vụ hỗ trợ tiếp cận).

  • Dịch vụ hỗ trợ tiếp cận: Các dịch vụ hỗ trợ tiếp cận xử lý sự kiện TYPE_VIEW_TEXT_CHANGED có thể gọi AccessibilityEvent.getTextChangeTypes() để xác định bản chất của nội dung sửa đổi và điều chỉnh chiến lược phản hồi cho phù hợp.

Quyền riêng tư

Android 17 có những thay đổi sau đây để cải thiện quyền riêng tư của người dùng.

Đã bật 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")。

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

Cần có quyền truy cập vào mạng cục bộ đối với các ứng dụng nhắm đến Android 17

Android 17 ra mắt quyền khi bắt đầu chạy ACCESS_LOCAL_NETWORK để bảo vệ người dùng khỏi hành vi truy cập trái phép vào mạng cục bộ. Vì quyền này thuộc nhóm quyền NEARBY_DEVICES hiện có, nên những người dùng đã cấp các quyền NEARBY_DEVICES khác sẽ không được nhắc lại. Yêu cầu mới này ngăn các ứng dụng độc hại khai thác quyền truy cập không hạn chế vào mạng cục bộ để theo dõi người dùng và thu thập vân tay số một cách lén lút. Bằng cách khai báo và yêu cầu quyền này, ứng dụng của bạn có thể khám phá và kết nối với các thiết bị trên mạng cục bộ (LAN), chẳng hạn như thiết bị nhà thông minh hoặc thiết bị nhận truyền.

Các ứng dụng nhắm đến Android 17 (cấp độ API 37) trở lên hiện có hai cách để duy trì hoạt động giao tiếp với các thiết bị LAN: Sử dụng bộ chọn thiết bị do hệ thống điều phối, đảm bảo quyền riêng tư để bỏ qua lời nhắc cấp quyền hoặc yêu cầu rõ ràng quyền mới này trong thời gian chạy để duy trì hoạt động giao tiếp trong mạng cục bộ.

Để biết thêm thông tin, hãy xem tài liệu về Quyền truy cập vào mạng cục bộ.

Ẩn mật khẩu khỏi thiết bị thực

Nếu một ứng dụng nhắm đến Android 17 (API cấp 37) trở lên và người dùng đang sử dụng một thiết bị đầu vào thực (ví dụ: bàn phím ngoài), thì hệ điều hành Android sẽ áp dụng chế độ cài đặt show_passwords_physical mới cho tất cả ký tự trong trường mật khẩu. Theo mặc định, chế độ cài đặt đó sẽ ẩn tất cả ký tự mật khẩu.

Hệ thống Android hiển thị ký tự mật khẩu được nhập gần đây nhất để giúp người dùng biết liệu họ có nhập sai mật khẩu hay không. Tuy nhiên, điều này ít cần thiết hơn nhiều đối với bàn phím ngoài lớn hơn. Ngoài ra, các thiết bị có bàn phím ngoài thường có màn hình lớn hơn, làm tăng nguy cơ người khác nhìn thấy mật khẩu đã nhập.

Nếu người dùng đang sử dụng màn hình cảm ứng của thiết bị, thì hệ thống sẽ áp dụng chế độ cài đặt show_passwords_touch mới.

Bảo vệ OTP cho tin nhắn SMS thông thường

从 Android 17 开始,Android 将扩展其短信动态密码保护功能,使其适用于标准短信(包含动态密码但不使用 WebOTP 或短信检索器格式的短信)。对于大多数以 Android 17(API 级别 37)或更高版本为目标平台的应用,这些短信在收到 3 小时后才可供使用。此延迟旨在帮助防止动态密码被劫持。在这 3 小时的延迟期间,SMS_RECEIVED_ACTION 广播会被扣留,短信提供商数据库查询会被过滤。延迟后,这些应用便可收到短信。

某些应用(例如默认短信助理应用、已连接设备的配套应用等)不受此延迟的影响。所有依赖读取短信来提取动态密码的应用都应改用 SMS Retriever 或 SMS User Consent API,以确保功能正常运行。

Bảo mật

Android 17 mang đến những điểm cải tiến sau đây về khả năng bảo mật của thiết bị và ứng dụng.

Bảo mật hoạt động

Trong Android 17, nền tảng này tiếp tục chuyển sang kiến trúc "bảo mật theo mặc định", giới thiệu một bộ tính năng nâng cao được thiết kế để giảm thiểu các hành vi khai thác có mức độ nghiêm trọng cao, chẳng hạn như lừa đảo, chiếm đoạt hoạt động tương tác và tấn công uỷ quyền nhầm lẫn. Bản cập nhật này yêu cầu nhà phát triển phải chọn sử dụng các tiêu chuẩn bảo mật mới một cách rõ ràng để duy trì khả năng tương thích của ứng dụng và bảo vệ người dùng.

Sau đây là những tác động chính đối với nhà phát triển:

  • Tăng cường BAL và cải thiện tính năng chọn sử dụng: Chúng tôi đang tinh chỉnh các quy định hạn chế về việc Chạy hoạt động ở chế độ nền (BAL) bằng cách mở rộng các biện pháp bảo vệ cho IntentSender. Nhà phát triển phải ngừng sử dụng hằng số MODE_BACKGROUND_ACTIVITY_START_ALLOWED cũ. Thay vào đó, bạn nên sử dụng các chế độ kiểm soát chi tiết như MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE, giúp hạn chế việc bắt đầu hoạt động trong các trường hợp ứng dụng gọi điện hiển thị, nhờ đó giảm đáng kể bề mặt tấn công.
  • Công cụ áp dụng: Nhà phát triển nên sử dụng chế độ nghiêm ngặt và các quy trình kiểm tra tìm lỗi mã nguồn mới nhất để xác định các mẫu cũ và đảm bảo sẵn sàng đáp ứng các yêu cầu về SDK mục tiêu trong tương lai.

Bật CT theo mặc định

Nếu một ứng dụng nhắm đến Android 17 (API cấp 37) trở lên, thì tính minh bạch của chứng chỉ (CT) sẽ được bật theo mặc định. (Trên Android 16, CT có sẵn nhưng ứng dụng phải chọn sử dụng.)

Safer Native DCL – C

Nếu ứng dụng của bạn nhắm đến Android 17 (cấp độ API 37) trở lên, thì biện pháp bảo vệ Tải mã động an toàn hơn (DCL) được giới thiệu trong Android 14 cho các tệp DEX và JAR hiện sẽ áp dụng cho cả thư viện gốc.

Tất cả tệp gốc được tải bằng System.load() phải được đánh dấu là chỉ đọc. Nếu không, hệ thống sẽ gửi ra UnsatisfiedLinkError.

Bất cứ khi nào có thể thì bạn nên tránh tải mã động, vì làm như vậy sẽ làm tăng đáng kể nguy cơ ứng dụng có thể bị xâm phạm do bị chèn mã hoặc can thiệp vào mã.

Hạn chế các trường thông tin nhận dạng cá nhân (PII) trong chế độ xem dữ liệu CP2

对于以 Android 17(API 级别 37)及更高版本为目标平台的应用,Contacts Provider 2 (CP2) 会限制数据视图中包含个人身份信息 (PII) 的某些列。启用此变更后,系统会从数据视图中移除这些列,以加强用户隐私保护。 受限列包括:

使用 ContactsContract.Data 中这些列的应用可以改为通过与 RAW_CONTACT_ID 联接,从 ContactsContract.RawContacts 中提取这些列。

Thực thi các quy trình kiểm tra SQL nghiêm ngặt trong CP2

Đối với các ứng dụng nhắm đến Android 17 (API cấp 37) trở lên, Trình cung cấp danh bạ 2 (CP2) thực thi quy trình xác thực truy vấn SQL nghiêm ngặt khi bảng ContactsContract.Data được truy cập mà không có quyền READ_CONTACTS.

Với thay đổi này, nếu một ứng dụng không có quyền READ_CONTACTS, thì các tuỳ chọn StrictColumns và StrictGrammar sẽ được đặt khi truy vấn bảng ContactsContract.Data. Nếu một truy vấn sử dụng mẫu không tương thích với các mẫu này, thì truy vấn đó sẽ bị từ chối và gây ra ngoại lệ.

Phân tích thông tin

Android 17 có những thay đổi sau đây đối với hệ thống thông minh.

Ngừng sử dụng setContentCaptureEnabled

Tính năng Ghi lại nội dung được bật theo mặc định trên một số thiết bị để cho phép các tính năng AI trên thiết bị phân tích nội dung trên màn hình nhằm mang đến trải nghiệm thông minh.

Kể từ Android 17, phương thức API ContentCaptureManager.setContentCaptureEnabled(boolean) không còn được dùng nữa. Đối với các ứng dụng nhắm đến Android 17 (cấp độ API 37) trở lên, việc gọi setContentCaptureEnabled(false) sẽ không còn tắt tính năng Chụp nội dung nữa.

Nếu ứng dụng của bạn cần tiếp tục tắt tính năng Chụp nội dung hoặc hạn chế hệ thống chụp nội dung trên màn hình, thì bạn phải chuyển sang sử dụng tham số bố cục cửa sổ FLAG_SECURE.

Để tắt tính năng Ghi lại nội dung, hãy đặt cờ FLAG_SECURE trên cửa sổ của bạn như trong ví dụ sau:

Kotlin

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

Java

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

Để biết thêm thông tin, hãy xem tài liệu tham khảo về WindowManager.LayoutParams.FLAG_SECURE.

Nội dung nghe nhìn

Android 17 có những thay đổi sau đây đối với hành vi của nội dung nghe nhìn.

Tăng cường bảo mật âm thanh nền

Kể từ Android 17, khung âm thanh sẽ thực thi các quy định hạn chế đối với các hoạt động tương tác âm thanh trong nền, bao gồm cả việc phát âm thanh, yêu cầu lấy tiêu điểm âm thanh và các API thay đổi âm lượng để đảm bảo rằng những thay đổi này được bắt đầu một cách có chủ đích bởi người dùng.

Một số quy định hạn chế về âm thanh áp dụng cho tất cả ứng dụng. Tuy nhiên, các quy định hạn chế sẽ nghiêm ngặt hơn nếu ứng dụng nhắm đến Android 17 (cấp độ API 37). Nếu một trong các ứng dụng này tương tác với âm thanh khi đang chạy ở chế độ nền, thì ứng dụng đó phải có một dịch vụ trên nền trước đang chạy. Ngoài ra, ứng dụng phải đáp ứng một hoặc cả hai yêu cầu sau:

  • Dịch vụ nền trước phải có các chức năng khi đang sử dụng (WIU).
  • Ứng dụng phải có quyền chuông báo chính xác và đang tương tác với các luồng âm thanh USAGE_ALARM.

Để biết thêm thông tin, bao gồm cả các chiến lược giảm thiểu, hãy xem phần Tăng cường bảo mật âm thanh nền.

Kiểu dáng thiết bị

Android 17 có những thay đổi sau đây để cải thiện trải nghiệm người dùng trên nhiều kích thước và kiểu dáng thiết bị.

Các thay đổi về API nền tảng để bỏ qua các quy tắc hạn chế về hướng, khả năng đổi kích thước và tỷ lệ khung hình trên màn hình lớn (sw>=600dp)

Chúng tôi đã giới thiệu các thay đổi đối với API nền tảng trong Android 16 để bỏ qua các quy tắc hạn chế về hướng, khả năng đổi kích thước và tỷ lệ khung hình trên màn hình lớn (sw >= 600dp) cho các ứng dụng nhắm đến API cấp 36 trở lên. Nhà phát triển có thể chọn không tham gia những thay đổi này bằng SDK 36, nhưng lựa chọn này sẽ không còn áp dụng cho các ứng dụng nhắm đến Android 17 (cấp độ API 37) trở lên.

Để biết thêm thông tin, hãy xem phần Bỏ qua các quy định hạn chế về hướng và khả năng đổi kích thước.

Khả năng kết nối

Android 17 ra mắt thay đổi sau đây để cải thiện tính nhất quán và phù hợp với hành vi InputStream chuẩn của Java cho các cổng Bluetooth RFCOMM.

Hành vi read() nhất quán của BluetoothSocket cho RFCOMM

对于以 Android 17(API 级别 37)为目标平台的应用,当套接字关闭或连接断开时,从基于 RFCOMM 的 BluetoothSocket 获取的 InputStream 的 read() 方法现在会返回 -1。

此项变更使 RFCOMM 套接字行为与 LE CoC 套接字保持一致,并与标准 InputStream.read() 文档保持一致,该文档指出,当到达数据流末尾时,会返回 -1。

仅依赖于捕获 IOException 来跳出读取循环的应用可能会受到此变更的影响,应更新 BluetoothSocket 读取循环,以明确检查返回值是否为 -1。这样可确保在远程设备断开连接或套接字关闭时,循环正确终止。如需查看推荐实现的示例,请参阅传输蓝牙数据指南中的代码段。