Изменения поведения: приложения для 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(API 级别 34)或更高版本为目标平台的应用,在调用 BluetoothAdapter getProfileConnectionState() 方法时,Android 14 会强制执行 BLUETOOTH_CONNECT 权限。

此方法已需要 BLUETOOTH_CONNECT 权限,但未强制执行。确保您的应用在应用的 AndroidManifest.xml 文件中声明 BLUETOOTH_CONNECT,如以下代码段所示,并在调用 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 . В некоторых случаях добавление класса java.lang.ClassValue вызывает проблемы, если вы пытаетесь сжать, запутать и оптимизировать свое приложение с помощью ProGuard. Проблема возникает из-за библиотеки Kotlin, которая меняет поведение во время выполнения в зависимости от того, возвращает ли Class.forName("java.lang.ClassValue") класс или нет. Если ваше приложение было разработано для более старой версии среды выполнения без доступного класса java.lang.ClassValue , то эти оптимизации могут удалить метод computeValue из классов, производных от java.lang.ClassValue .

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

Since its introduction, JobScheduler expects your app to return from onStartJob or onStopJob within a few seconds. Prior to Android 14, if a job runs too long, the job is stopped and fails silently. If your app targets Android 14 (API level 34) or higher and exceeds the granted time on the main thread, the app triggers an ANR with the error message "No response to onStartJob" or "No response to onStopJob".

This ANR may be a result of 2 scenarios: 1. There is work blocking the main thread, preventing the callbacks onStartJob or onStopJob from executing and completing within the expected time limit. 2. The developer is running blocking work within the JobScheduler callback onStartJob or onStopJob, preventing the callback from completing within the expected time limit.

To address #1, you will need to further debug what is blocking the main thread when the ANR occurs, you can do this using ApplicationExitInfo#getTraceInputStream() to get the tombstone trace when the ANR occurs. If you're able to manually reproduce the ANR, you can record a system trace and inspect the trace using either Android Studio or Perfetto to better understand what is running on the main thread when the ANR occurs. Note that this can happen when using JobScheduler API directly or using the androidx library WorkManager.

To address #2, consider migrating to WorkManager, which provides support for wrapping any processing in onStartJob or onStopJob in an asynchronous thread.

JobScheduler also introduces a requirement to declare the ACCESS_NETWORK_STATE permission if using setRequiredNetworkType or setRequiredNetwork constraint. If your app does not declare the ACCESS_NETWORK_STATE permission when scheduling the job and is targeting Android 14 or higher, it will result in a SecurityException.

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

Для приложений, предназначенных для версии 14 и выше, TileService#startActivityAndCollapse(Intent) устарел и теперь выдает исключение при вызове. Если ваше приложение запускает действия из плиток, используйте вместо этого TileService#startActivityAndCollapse(PendingIntent) .

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

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

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

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

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

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

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

在 Android 11(API 级别 30)中,任何应用都可以在手机处于锁定状态时使用 Notification.Builder.setFullScreenIntent 发送全屏 intent。您可以通过在 AndroidManifest 中声明 USE_FULL_SCREEN_INTENT 权限,在应用安装时自动授予此权限。

全屏 intent 通知适用于需要用户立即注意的极高优先级通知,例如用户来电或用户配置的闹钟设置。对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,获准使用此权限的应用仅限于提供通话和闹钟的应用。对于不适合此情况的任何应用,Google Play 商店会撤消其默认的 USE_FULL_SCREEN_INTENT 权限。这些政策变更的截止日期为 2024 年 5 月 31 日

在用户更新到 Android 14 之前,在手机上安装的应用仍拥有此权限。用户可以开启和关闭此权限。

您可以使用新 API NotificationManager.canUseFullScreenIntent 检查应用是否具有该权限;如果没有,应用可以使用新 intent ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT 启动设置页面,在该页面中,用户可以授予权限。

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

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

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

  • Неявные намерения доставляются только экспортированным компонентам. Приложения должны либо использовать явное намерение доставить неэкспортированные компоненты, либо пометить компонент как экспортированный.
  • Если приложение создает изменяемое ожидающее намерение с намерением, в котором не указан компонент или пакет, система выдает исключение.

Эти изменения не позволяют вредоносным приложениям перехватывать неявные намерения, предназначенные для использования внутренними компонентами приложения.

Например, вот фильтр намерений , который можно объявить в файле манифеста вашего приложения:

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

Если ваше приложение попытается запустить это действие, используя неявное намерение, будет выдано исключение ActivityNotFoundException :

Котлин

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

Ява

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

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

Котлин

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

Ява

// 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_EXPORTEDRECEIVER_NOT_EXPORTED。此要求有助于利用 Android 13 中引入的这些接收器的功能,来保护应用免受安全漏洞的影响。

仅接收系统广播的接收器的例外情况

如果您的应用仅通过 Context#registerReceiver 方法(例如 Context#registerReceiver())针对系统广播注册接收器,那么它在注册接收器时不应指定标志。

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

Если ваше приложение предназначено для Android 14 (уровень API 34) или выше и использует динамическую загрузку кода (DCL), все динамически загружаемые файлы должны быть помечены как доступные только для чтения. В противном случае система выдает исключение. Мы рекомендуем приложениям избегать динамической загрузки кода , когда это возможно, поскольку это значительно увеличивает риск того, что приложение может быть скомпрометировано путем внедрения кода или подделки кода.

Если вам необходимо динамически загружать код, используйте следующий подход, чтобы установить динамически загружаемый файл (например, файл DEX, JAR или APK) только для чтения сразу после открытия файла и до записи какого-либо содержимого:

Котлин

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)

Ява

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)或更高版本为目标平台的应用,系统会进一步限制允许应用在后台启动 activity 的时间:

这些更改扩大了一组现有限制条件的范围,目的是防止恶意应用滥用 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 см . в разделе Обновления ограничений интерфейса, не связанных с SDK, в Android 14 . Дополнительные сведения об интерфейсах, отличных от SDK, см. в разделе Ограничения на интерфейсы, не относящиеся к SDK .