Изменения в поведении: все приложения

В Android 17 есть изменения, которые могут повлиять на работу вашего приложения. Они касаются всех приложений, запущенных на устройствах с Android 17, независимо от targetSdkVersion. Протестируйте приложение и при необходимости измените его, чтобы оно поддерживало эти изменения.

Также ознакомьтесь со списком изменений в поведении, которые затрагивают только приложения для Android 17.

Основные функции

В Android 17 (уровень API 37) внесены изменения, которые модифицируют или расширяют различные основные возможности системы Android.

Ограничения памяти для приложений

Android 17 引入了基于设备 RAM 总容量的应用内存限制,旨在为应用和 Android 用户打造更稳定、更确定的环境。这些限制侧重于在内存泄漏和其他异常值触发系统级不稳定(导致界面卡顿、耗电量增加和应用被终止)之前,对其进行检测。虽然我们预计对绝大多数应用会话的影响微乎其微,但我们建议您遵循以下内存最佳实践,包括建立内存基准。

您可以通过在 ApplicationExitInfo 中调用 getDescription 来确定应用会话是否受到影响;如果应用受到影响,退出原因将为 REASON_OTHER,说明将包含字符串 "MemoryLimiter:AnonSwap" 以及其他信息。您还可以将基于触发器的性能分析与 TRIGGER_TYPE_ANOMALY 搭配使用,以获取在达到内存限制时收集的堆转储。

管理应用的内存文档提供了相关信息,可帮助您诊断应用的内存问题并优化其资源消耗。

测试应用在内存限制下的行为

您可以使用 Android 调试桥 (adb) 调整或停用任何设备上的内存限制。shell 命令 am 提供了三个子命令来调整内存限制。(这些命令对不施加内存限制的设备没有影响。)

  • am memory-limiter ignore <uid>|none|all
  • am memory-limiter manual <pid> <limit>|max|none
  • am 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 внесены следующие изменения, направленные на повышение конфиденциальности пользователей.

Защита одноразовых кодов из SMS

从 Android 17 开始,Android 将扩大对包含动态密码 (OTP) 的短信的保护范围。

在之前的 Android 版本中,此保护机制主要针对 SMS Retriever 格式。对于大多数应用,包含短信检索器哈希的消息延迟了 3 小时才送达。不过,某些应用(例如默认短信处理程序)不受延迟影响,拥有哈希的应用也不受延迟影响。

从 Android 17 开始,此保护措施也适用于 WebOTP 格式的消息。如果应用有权读取短信,但不是 WebOTP 消息的预期接收者(由网域验证确定),则应用在收到消息 3 小时后才能访问该消息。此项变更旨在提高用户安全性,确保只有与消息中提及的网域相关联的应用才能以编程方式读取验证码。

在这 3 小时的延迟期间,SMS_RECEIVED_ACTION 广播会被扣留,短信提供程序数据库查询会被过滤。延迟后,这些应用便可收到短信。此项变更适用于所有应用,无论其目标 API 级别如何。

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

Безопасность

В Android 17 улучшена безопасность устройств и приложений.

План прекращения поддержки usesClearTraffic

在未来发布的版本中,我们计划弃用 usesCleartextTraffic 元素。 需要建立未加密 (HTTP) 连接的应用应迁移到使用网络安全配置文件,该文件可让您指定应用需要与哪些网域建立明文连接。

请注意,只有 API 级别 24 及更高级别支持网络安全配置文件。如果应用的最低 API 级别低于 24,您应执行以下两项操作:

  • 将 usesCleartextTraffic 属性设置为 true
  • 使用网络配置文件

如果应用的最低 API 级别为 24 或更高级别,您可以使用网络配置文件,而无需设置 usesCleartextTraffic。

Ограничить неявные разрешения URI

Сейчас, если приложение запускает намерение с URI, у которого есть действие ACTION_SEND, ACTION_SEND_MULTIPLE или ACTION_IMAGE_CAPTURE, система автоматически предоставляет целевому приложению разрешения на чтение и запись 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);

Включите флаги FLAG_GRANT_READ_URI_PERMISSION и FLAG_GRANT_WRITE_URI_PERMISSION для намерений ACTION_IMAGE_CAPTURE:

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 开始,默认情况下不再允许跨资料环回流量。同一配置文件内的环回流量不受影响。 此变更适用于在 Android 17 或更高版本上运行的所有应用,无论应用的目标 API 级别如何。

Удобство для пользователей и системный интерфейс

В Android 17 внесены следующие изменения, призванные сделать работу с системой более единообразной и интуитивно понятной.

Восстановление видимости IME по умолчанию после поворота

从 Android 17 开始,当设备的配置发生变化(例如,通过旋转)且应用本身未处理此变化时,系统不会恢复之前的 IME 可见性。

如果您的应用发生其无法处理的配置更改,并且应用需要在更改后显示键盘,您必须明确请求显示键盘。您可以通过以下任一方式提出此请求:

  • 将 android:windowSoftInputMode 属性设置为 stateAlwaysVisible。
  • 在 activity 的 onCreate() 方法中以编程方式请求软键盘,或添加 onConfigurationChanged() 方法。

Действия специалистов

В Android 17 внесены следующие изменения, которые влияют на то, как приложения взаимодействуют с устройствами ввода, такими как клавиатуры и сенсорные панели.

Сенсорные панели по умолчанию передают относительные события во время захвата указателя

Начиная с Android 17, если приложение запрашивает захват указателя с помощью View.requestPointerCapture(), а пользователь использует сенсорную панель, система распознает жесты перемещения указателя и прокрутки по касаниям пользователя и сообщает о них приложению так же, как о перемещениях указателя и колеса прокрутки от захваченной мыши. В большинстве случаев это избавляет от необходимости добавлять в приложения, поддерживающие захват мыши, специальную логику обработки для сенсорных панелей. Подробную информацию вы найдете в документации по View.POINTER_CAPTURE_MODE_RELATIVE.

Ранее система не пыталась распознавать жесты на сенсорной панели, а передавала приложению необработанные абсолютные координаты пальцев в формате, аналогичном касаниям сенсорного экрана. Если приложению по-прежнему нужны абсолютные данные, оно должно вызвать новый метод View.requestPointerCapture(int) с View.POINTER_CAPTURE_MODE_ABSOLUTE.

Мультимедиа

В Android 17 внесены следующие изменения в работу с медиаконтентом.

Усиление защиты аудио в фоновом режиме

Начиная с Android 17, аудиофреймворк накладывает ограничения на фоновые аудиовзаимодействия, включая воспроизведение аудио, запросы на фокусировку звука и API изменения громкости, чтобы гарантировать, что эти изменения запускаются пользователем намеренно.

Если приложение пытается вызвать API аудио, когда оно находится в недопустимом жизненном цикле, API воспроизведения аудио и изменения громкости не срабатывают без выдачи исключения или сообщения об ошибке. API аудиофокуса возвращает код ошибки AUDIOFOCUS_REQUEST_FAILED.

Дополнительную информацию, в том числе о стратегиях устранения уязвимостей, можно найти в статье Усиление защиты фонового аудио.

Функции связи

В Android 17 внесены следующие изменения, улучшающие подключение устройств.

Автоматическое повторное подключение при потере связи по Bluetooth.

Android 17 引入了自主重新配对功能,这是一项系统级增强功能,旨在自动解决蓝牙绑定丢失问题。

以前,如果绑定丢失,用户必须手动前往“设置”取消配对外围设备,然后重新配对。此功能以 Android 16 的安全改进为基础,允许系统在后台重新建立绑定,而无需用户手动前往“设置”取消配对外围设备并重新配对。

虽然大多数应用不需要更改代码,但开发者应注意蓝牙堆栈中的以下行为变更:

  • 新的配对上下文:ACTION_PAIRING_REQUEST 现在包含 EXTRA_PAIRING_CONTEXT extra,使应用能够区分标准配对请求和系统发起的自主重新配对尝试。
  • 有条件地更新密钥:只有在重新配对成功且新连接的安全级别达到或超过之前绑定的安全级别时,系统才会替换现有安全密钥。
  • 修改了 intent 时间:现在,仅当自主重新配对尝试失败时,系统才会广播 ACTION_KEY_MISSING intent。如果系统在后台成功恢复绑定,这会减少应用中不必要的错误处理。
  • 用户通知:系统通过新的界面通知和对话框管理重新配对。系统会提示用户确认重新配对尝试,以确保他们知道重新连接。

外围设备制造商和配套应用开发者应验证硬件和应用是否能妥善处理绑定转换。如需测试此行为,请使用以下任一方法模拟远程绑定丢失:

  • 手动从外围设备中移除绑定信息
  • 在“设置”>“已连接的设备”中手动取消配对设备