Изменения поведения: приложения для Android 14 или более поздней версии. Изменения поведения: приложения для Android 14 или более поздней версии. Изменения поведения: приложения для Android 14 или более поздней версии. Изменения поведения: приложения для Android 14 или более поздней версии.

Как и в предыдущих версиях, Android 14 включает изменения в поведении, которые могут повлиять на ваше приложение. Следующие изменения в поведении применяются исключительно к приложениям, ориентированным на Android 14 (уровень API 34) или выше. Если ваше приложение ориентировано на Android 14 или выше, вам следует внести в него изменения для корректной поддержки этих изменений, где это применимо.

Обязательно ознакомьтесь также со списком изменений в поведении, которые затрагивают все приложения, работающие на Android 14, независимо от targetSdkVersion приложения.

Основная функциональность

Требуются типы служб переднего плана.

如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台,则必须为应用中的每个前台服务至少指定一项前台服务类型。您应选择一个能代表应用用例的前台服务类型。系统需要特定类型的前台服务满足特定用例。

如果应用中的用例与这些类型均不相关,强烈建议您迁移逻辑以使用 WorkManager用户发起的数据传输作业

Применение разрешения BLUETOOTH_CONNECT в BluetoothAdapter

Android 14 применяет разрешение BLUETOOTH_CONNECT при вызове метода BluetoothAdapter getProfileConnectionState() для приложений, предназначенных для Android 14 (уровень API 34) или выше.

Для этого метода уже требовалось разрешение BLUETOOTH_CONNECT , но оно не было применено. Убедитесь, что ваше приложение объявляет BLUETOOTH_CONNECT в файле AndroidManifest.xml вашего приложения, как показано в следующем фрагменте, и убедитесь, что пользователь предоставил разрешение перед вызовом getProfileConnectionState .

<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

Обновления OpenJDK 17

Android 14 将继续更新 Android 的核心库,以与最新 OpenJDK LTS 版本中的功能保持一致,包括适合应用和平台开发者的库更新和 Java 17 语言支持。

以下变更可能会影响应用兼容性:

  • 对正则表达式的更改:现在,为了更严格地遵循 OpenJDK 的语义,不允许无效的组引用。您可能会看到 java.util.regex.Matcher 类抛出 IllegalArgumentException 的新情况,因此请务必测试应用中使用正则表达式的情形。如需在测试期间启用或停用此变更,请使用兼容性框架工具切换 DISALLOW_INVALID_GROUP_REFERENCE 标志。
  • UUID 处理:现在,验证输入参数时,java.util.UUID.fromString() 方法会执行更严格的检查,因此您可能会在反序列化期间看到 IllegalArgumentException。如需在测试期间启用或停用此变更,请使用兼容性框架工具切换 ENABLE_STRICT_VALIDATION 标志。
  • ProGuard 问题:有时,在您尝试使用 ProGuard 缩减、混淆和优化应用时,添加 java.lang.ClassValue 类会导致问题。问题源自 Kotlin 库,该库会根据 Class.forName("java.lang.ClassValue") 是否会返回类更改运行时行为。如果您的应用是根据没有 java.lang.ClassValue 类的旧版运行时开发的,则这些优化可能会将 computeValue 方法从派生自 java.lang.ClassValue 的类中移除。

JobScheduler обеспечивает корректное отображение поведения при обратных вызовах и в сети.

自从引入后,JobScheduler 期望您的应用从 onStartJobonStopJob。在 Android 14 之前,如果作业运行时间过长,系统会停止作业并静默失败。如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台, 超过在主线程上授予的时间,应用会触发 ANR 显示“没有响应 onStartJob”错误消息或 “onStopJob没有回复”。

此 ANR 可能是由以下 2 种情况造成的: 1.有工作阻塞主线程,阻止回调 onStartJob 或者onStopJob在预期时间内执行并完成。 2. 开发者在 JobScheduler 中运行阻塞工作 回调 onStartJobonStopJob,阻止从 在预期的时限内完成

要解决第 1 个问题,您需要进一步调试阻塞主线程的因素 您可以使用以下代码 ApplicationExitInfo#getTraceInputStream(),用于获取 Tombstone ANR 发生时的跟踪信息如果您能够手动重现 ANR 问题 您可以录制系统轨迹,并使用 Android StudioPerfetto,以便更好地了解应用上运行的 在发生 ANR 时调用主线程 请注意,直接使用 JobScheduler API 或使用 androidx 库 WorkManager 时可能会发生这种情况。

如需解决问题 2,请考虑迁移到 WorkManager,它支持将 onStartJobonStopJob 中的任何处理封装在异步线程中。

JobScheduler 还引入了一项要求,即如果使用 setRequiredNetworkTypesetRequiredNetwork 约束条件,则必须声明 ACCESS_NETWORK_STATE 权限。如果您的应用未声明 ACCESS_NETWORK_STATE 权限 Android 14 或更高版本,则会导致 SecurityException

API запуска плиток

对于以 Android 14 及更高版本为目标平台的应用, TileService#startActivityAndCollapse(Intent) 已弃用,现在会抛出 调用时抛出异常。如果您的应用从功能块启动 activity,请使用 TileService#startActivityAndCollapse(PendingIntent)

Конфиденциальность

Частичный доступ к фотографиям и видео.

В Android 14 представлен доступ к выбранным фотографиям, который позволяет пользователям предоставлять приложениям доступ к определенным изображениям и видео в их библиотеке, а не предоставлять доступ ко всем медиафайлам определенного типа.

Это изменение доступно только в том случае, если ваше приложение предназначено для Android 14 (уровень API 34) или более поздней версии. Если вы еще не используете средство выбора фотографий, мы рекомендуем внедрить его в свое приложение , чтобы обеспечить единообразный выбор изображений и видео, а также повысить конфиденциальность пользователей без необходимости запрашивать какие-либо разрешения на хранение.

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

пользовательский опыт

Безопасные полноэкранные уведомления Intent

В Android 11 (уровень API 30) любое приложение могло использовать Notification.Builder.setFullScreenIntent для отправки полноэкранных намерений, когда телефон заблокирован. Вы можете автоматически предоставить это разрешение при установке приложения, объявив разрешение USE_FULL_SCREEN_INTENT в AndroidManifest.

Полноэкранные уведомления о намерениях предназначены для уведомлений с чрезвычайно высоким приоритетом, требующих немедленного внимания пользователя, таких как входящий телефонный звонок или настройки будильника, настроенные пользователем. Для приложений, предназначенных для Android 14 (уровень API 34) или выше, приложения, которым разрешено использовать это разрешение, ограничены теми, которые обеспечивают только вызовы и сигналы тревоги. Магазин Google Play отзывает разрешения USE_FULL_SCREEN_INTENT по умолчанию для всех приложений, которые не соответствуют этому профилю. Крайний срок внесения этих изменений в политику — 31 мая 2024 года .

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

Вы можете использовать новый API NotificationManager.canUseFullScreenIntent чтобы проверить, имеет ли ваше приложение разрешение; в противном случае ваше приложение может использовать новое намерение ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT для запуска страницы настроек, на которой пользователи могут предоставить разрешение.

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

Ограничения, касающиеся неявных и ожидающих намерений.

对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,Android 会通过以下方式限制应用向内部应用组件发送隐式 intent:

  • 隐式 intent 只能传送到导出的组件。应用必须使用显式 intent 传送到未导出的组件,或将该组件标记为已导出。
  • 如果应用通过未指定组件或软件包的 intent 创建可变待处理 intent,系统会抛出异常。

这些变更可防止恶意应用拦截意在供应用内部组件使用的隐式 intent。

例如,下面是可以在应用的清单文件中声明的 intent 过滤器

<activity
    android:name=".AppActivity"
    android:exported="false">
    <intent-filter>
        <action android:name="com.example.action.APP_ACTION" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

如果应用尝试使用隐式 intent 启动此 activity,则系统会抛出 ActivityNotFoundException 异常:

Kotlin

// Throws an ActivityNotFoundException exception when targeting Android 14.
context.startActivity(Intent("com.example.action.APP_ACTION"))

Java

// Throws an ActivityNotFoundException exception when targeting Android 14.
context.startActivity(new Intent("com.example.action.APP_ACTION"));

如需启动非导出的 activity,应用应改用显式 intent:

Kotlin

// This makes the intent explicit.
val explicitIntent =
        Intent("com.example.action.APP_ACTION")
explicitIntent.apply {
    package = context.packageName
}
context.startActivity(explicitIntent)

Java

// This makes the intent explicit.
Intent explicitIntent =
        new Intent("com.example.action.APP_ACTION")
explicitIntent.setPackage(context.getPackageName());
context.startActivity(explicitIntent);

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

Приложения и службы, ориентированные на Android 14 (уровень API 34) или выше и использующие приемники, зарегистрированные в контексте, должны указать флаг, указывающий, следует ли экспортировать приемник во все другие приложения на устройстве: либо RECEIVER_EXPORTED , либо RECEIVER_NOT_EXPORTED соответственно. . Это требование помогает защитить приложения от уязвимостей безопасности за счет использования функций этих приемников, представленных в Android 13 .

Исключение для приемников, которые принимают только системные трансляции.

Если ваше приложение регистрирует получателя только для системных широковещательных рассылок с помощью методов Context#registerReceiver , таких как Context#registerReceiver() , то ему не следует указывать флаг при регистрации получателя.

Более безопасная динамическая загрузка кода

如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台并使用动态代码 正在加载 (DCL),所有动态加载的文件都必须标记为只读。 否则,系统会抛出异常。我们建议应用尽可能避免动态加载代码,因为这样做会大大增加应用因代码注入或代码篡改而遭到入侵的风险。

如果必须动态加载代码,请使用以下方法,在动态文件(例如 DEX、JAR 或 APK 文件)打开并写入任何内容之前立即将其设为只读:

Kotlin

val jar = File("DYNAMICALLY_LOADED_FILE.jar")
val os = FileOutputStream(jar)
os.use {
    // Set the file to read-only first to prevent race conditions
    jar.setReadOnly()
    // Then write the actual file content
}
val cl = PathClassLoader(jar, parentClassLoader)

Java

File jar = new File("DYNAMICALLY_LOADED_FILE.jar");
try (FileOutputStream os = new FileOutputStream(jar)) {
    // Set the file to read-only first to prevent race conditions
    jar.setReadOnly();
    // Then write the actual file content
} catch (IOException e) { ... }
PathClassLoader cl = new PathClassLoader(jar, parentClassLoader);

处理已存在的动态加载文件

为防止系统对现有动态加载的文件抛出异常,我们建议您先删除并重新创建文件,然后再尝试在应用中重新动态加载这些文件。重新创建文件时,请按照上述指南在写入时将文件标记为只读。或者,您可以将现有文件重新标记为只读,但在这种情况下,我们强烈建议您先验证文件的完整性(例如,对照可信值检查文件的签名)以保护应用免遭恶意操作的影响。

Дополнительные ограничения на запуск деятельности из фонового режима.

Для приложений, ориентированных на Android 14 (уровень API 34) или выше, система дополнительно ограничивает, когда приложениям разрешено запускать действия в фоновом режиме:

  • Когда приложение отправляет PendingIntent с помощью PendingIntent#send() или аналогичных методов, приложение должно согласиться, если оно хочет предоставить свои собственные привилегии запуска фоновой активности для запуска ожидающего намерения. Чтобы принять участие, приложение должно передать пакет ActivityOptions с помощью setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED) .
  • Когда видимое приложение привязывает службу другого приложения, находящегося в фоновом режиме, с помощью bindService() , видимое приложение теперь должно согласиться, если оно хочет предоставить свои собственные привилегии запуска фоновой активности связанному сервису. Чтобы принять участие, приложение должно включить флаг BIND_ALLOW_ACTIVITY_STARTS при вызове метода bindService() .

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

Обход по зип-пути

Для приложений, предназначенных для Android 14 (уровень API 34) или выше, Android предотвращает уязвимость обхода пути Zip следующим образом: ZipFile(String) и ZipInputStream.getNextEntry() выдают исключение ZipException , если имена записей zip-файла содержат «..» или start. с "/".

Приложения могут отказаться от этой проверки, вызвав dalvik.system.ZipPathValidator.clearCallback() .

Для приложений, предназначенных для Android 14 (уровень API 34) или выше, MediaProjection#createVirtualDisplay создает исключение SecurityException в любом из следующих сценариев:

Ваше приложение должно запрашивать у пользователя согласие перед каждым сеансом захвата. Один сеанс захвата — это один вызов MediaProjection#createVirtualDisplay , и каждый экземпляр MediaProjection должен использоваться только один раз.

Обработка изменений конфигурации

Если вашему приложению необходимо вызвать MediaProjection#createVirtualDisplay для обработки изменений конфигурации (например, изменения ориентации или размера экрана), вы можете выполнить следующие действия, чтобы обновить VirtualDisplay для существующего экземпляра MediaProjection :

  1. Вызовите VirtualDisplay#resize с новой шириной и высотой.
  2. Предоставьте новую Surface с новой шириной и высотой для VirtualDisplay#setSurface .

Зарегистрируйте обратный звонок

Ваше приложение должно зарегистрировать обратный вызов для обработки случаев, когда пользователь не дает согласия на продолжение сеанса захвата. Для этого реализуйте Callback#onStop и освободите приложение все связанные ресурсы (например, VirtualDisplay и Surface ).

Если ваше приложение не регистрирует этот обратный вызов, MediaProjection#createVirtualDisplay выдает исключение IllegalStateException , когда ваше приложение его вызывает.

Обновлены ограничения, не относящиеся к SDK.

В Android 14 обновлены списки ограниченных интерфейсов, не использующих SDK, на основе сотрудничества с разработчиками Android и последних внутренних тестов. По возможности мы обеспечиваем наличие общедоступных альтернатив, прежде чем ограничивать использование интерфейсов, не использующих SDK.

Если ваше приложение не ориентировано на Android 14, некоторые из этих изменений могут не сразу повлиять на вас. Однако, хотя в настоящее время вы можете использовать некоторые интерфейсы, не связанные с SDK ( в зависимости от целевого уровня API вашего приложения ), использование любого метода или поля, не связанного с SDK, всегда сопряжено с высоким риском нарушения работы вашего приложения.

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

如需详细了解此 Android 版本中的变更,请参阅 Android 14 中有关限制非 SDK 接口的更新。如需全面了解有关非 SDK 接口的详细信息,请参阅对非 SDK 接口的限制