Изменения поведения: приложения для 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 continues the work of refreshing Android's core libraries to align with the features in the latest OpenJDK LTS releases, including both library updates and Java 17 language support for app and platform developers.

A few of these changes can affect app compatibility:

  • Changes to regular expressions: Invalid group references are now disallowed to more closely follow the semantics of OpenJDK. You might see new cases where an IllegalArgumentException is thrown by the java.util.regex.Matcher class, so make sure to test your app for areas that use regular expressions. To enable or disable this change while testing, toggle the DISALLOW_INVALID_GROUP_REFERENCE flag using the compatibility framework tools.
  • UUID handling: The java.util.UUID.fromString() method now does more strict checks when validating the input argument, so you might see an IllegalArgumentException during deserialization. To enable or disable this change while testing, toggle the ENABLE_STRICT_VALIDATION flag using the compatibility framework tools.
  • ProGuard issues: In some cases, the addition of the java.lang.ClassValue class causes an issue if you try to shrink, obfuscate, and optimize your app using ProGuard. The problem originates with a Kotlin library that changes runtime behaviour based on whether Class.forName("java.lang.ClassValue") returns a class or not. If your app was developed against an older version of the runtime without the java.lang.ClassValue class available, then these optimizations might remove the computeValue method from classes derived from java.lang.ClassValue.

JobScheduler усиливает обратный вызов и сетевое поведение

С момента своего появления JobScheduler ожидает, что ваше приложение вернется из onStartJob или onStopJob в течение нескольких секунд. До версии Android 14, если задание выполнялось слишком долго, оно останавливалось и завершалось автоматически. Если ваше приложение предназначено для Android 14 (уровень API 34) или выше и превышает разрешенное время в основном потоке, приложение запускает ANR с сообщением об ошибке «Нет ответа на onStartJob » или «Нет ответа на onStopJob ».

Этот ANR может быть результатом двух сценариев: 1. Выполняется работа, блокирующая основной поток, что препятствует выполнению и завершению обратных вызовов onStartJob или onStopJob в течение ожидаемого срока. 2. Разработчик запускает блокировку в обратном вызове JobScheduler onStartJob или onStopJob , не позволяя обратному вызову завершиться в течение ожидаемого срока.

Для решения № 1 вам потребуется дополнительная отладка того, что блокирует основной поток при возникновении ошибки ANR. Это можно сделать с помощью ApplicationExitInfo#getTraceInputStream() чтобы получить трассировку захоронения при возникновении ошибки ANR. Если вы можете вручную воспроизвести ANR, вы можете записать системную трассировку и проверить ее с помощью Android Studio или Perfetto, чтобы лучше понять, что происходит в основном потоке при возникновении ошибки ANR. Обратите внимание, что это может произойти при непосредственном использовании API JobScheduler или при использовании библиотеки WorkManager для Android.

Для решения № 2 рассмотрите возможность перехода на WorkManager , который обеспечивает поддержку переноса любой обработки в onStartJob или onStopJob в асинхронный поток.

JobScheduler также вводит требование объявлять разрешение ACCESS_NETWORK_STATE при использовании ограничения setRequiredNetworkType или setRequiredNetwork . Если ваше приложение не декларирует разрешение ACCESS_NETWORK_STATE при планировании задания и предназначено для Android 14 или более поздней версии, это приведет к возникновению SecurityException .

,

С момента своего появления JobScheduler ожидает, что ваше приложение вернется из onStartJob или onStopJob в течение нескольких секунд. До версии Android 14, если задание выполнялось слишком долго, оно останавливалось и завершалось автоматически. Если ваше приложение предназначено для Android 14 (уровень API 34) или выше и превышает разрешенное время в основном потоке, приложение запускает ANR с сообщением об ошибке «Нет ответа на onStartJob » или «Нет ответа на onStopJob ».

Этот ANR может быть результатом двух сценариев: 1. Выполняется работа, блокирующая основной поток, что препятствует выполнению и завершению обратных вызовов onStartJob или onStopJob в течение ожидаемого срока. 2. Разработчик запускает блокировку в обратном вызове JobScheduler onStartJob или onStopJob , не позволяя обратному вызову завершиться в течение ожидаемого срока.

Для решения № 1 вам потребуется дополнительная отладка того, что блокирует основной поток при возникновении ошибки ANR. Это можно сделать с помощью ApplicationExitInfo#getTraceInputStream() чтобы получить трассировку захоронения при возникновении ошибки ANR. Если вы можете вручную воспроизвести ANR, вы можете записать системную трассировку и проверить ее с помощью Android Studio или Perfetto, чтобы лучше понять, что происходит в основном потоке при возникновении ошибки ANR. Обратите внимание, что это может произойти при непосредственном использовании API JobScheduler или при использовании библиотеки WorkManager для Android.

Для решения № 2 рассмотрите возможность перехода на WorkManager , который обеспечивает поддержку переноса любой обработки в onStartJob или onStopJob в асинхронный поток.

JobScheduler также вводит требование объявлять разрешение ACCESS_NETWORK_STATE при использовании ограничения setRequiredNetworkType или setRequiredNetwork . Если ваше приложение не декларирует разрешение ACCESS_NETWORK_STATE при планировании задания и предназначено для Android 14 или более поздней версии, это приведет к возникновению SecurityException .

,

С момента своего появления JobScheduler ожидает, что ваше приложение вернется из onStartJob или onStopJob в течение нескольких секунд. До версии Android 14, если задание выполнялось слишком долго, оно останавливалось и завершалось автоматически. Если ваше приложение предназначено для Android 14 (уровень API 34) или выше и превышает разрешенное время в основном потоке, приложение запускает ANR с сообщением об ошибке «Нет ответа на onStartJob » или «Нет ответа на onStopJob ».

Этот ANR может быть результатом двух сценариев: 1. Выполняется работа, блокирующая основной поток, что препятствует выполнению и завершению обратных вызовов onStartJob или onStopJob в течение ожидаемого срока. 2. Разработчик запускает блокировку в обратном вызове JobScheduler onStartJob или onStopJob , не позволяя обратному вызову завершиться в течение ожидаемого срока.

Для решения № 1 вам потребуется дополнительная отладка того, что блокирует основной поток при возникновении ошибки ANR. Это можно сделать с помощью ApplicationExitInfo#getTraceInputStream() чтобы получить трассировку захоронения при возникновении ошибки ANR. Если вы можете вручную воспроизвести ANR, вы можете записать системную трассировку и проверить ее с помощью Android Studio или Perfetto, чтобы лучше понять, что происходит в основном потоке при возникновении ошибки ANR. Обратите внимание, что это может произойти при непосредственном использовании API JobScheduler или при использовании библиотеки WorkManager для Android.

Для решения № 2 рассмотрите возможность перехода на WorkManager , который обеспечивает поддержку переноса любой обработки в onStartJob или onStopJob в асинхронный поток.

JobScheduler также вводит требование объявлять разрешение ACCESS_NETWORK_STATE при использовании ограничения setRequiredNetworkType или setRequiredNetwork . Если ваше приложение не декларирует разрешение ACCESS_NETWORK_STATE при планировании задания и предназначено для Android 14 или более поздней версии, это приведет к возникновению SecurityException .

,

С момента своего появления JobScheduler ожидает, что ваше приложение вернется из onStartJob или onStopJob в течение нескольких секунд. До версии Android 14, если задание выполнялось слишком долго, оно останавливалось и завершалось автоматически. Если ваше приложение предназначено для Android 14 (уровень API 34) или выше и превышает разрешенное время в основном потоке, приложение запускает ANR с сообщением об ошибке «Нет ответа на onStartJob » или «Нет ответа на onStopJob ».

Этот ANR может быть результатом двух сценариев: 1. Выполняется работа, блокирующая основной поток, что препятствует выполнению и завершению обратных вызовов onStartJob или onStopJob в течение ожидаемого срока. 2. Разработчик запускает блокировку в обратном вызове JobScheduler onStartJob или onStopJob , не позволяя обратному вызову завершиться в течение ожидаемого срока.

Для решения № 1 вам потребуется дополнительная отладка того, что блокирует основной поток при возникновении ошибки ANR. Это можно сделать с помощью ApplicationExitInfo#getTraceInputStream() чтобы получить трассировку захоронения при возникновении ошибки ANR. Если вы можете воспроизвести ANR вручную, вы можете записать трассировку системы и проверить ее с помощью Android Studio или Perfetto, чтобы лучше понять, что происходит в основном потоке при возникновении ошибки ANR. Обратите внимание, что это может произойти при непосредственном использовании API JobScheduler или при использовании библиотеки WorkManager для Android.

Для решения № 2 рассмотрите возможность перехода на WorkManager , который обеспечивает поддержку переноса любой обработки в onStartJob или onStopJob в асинхронный поток.

JobScheduler также вводит требование объявлять разрешение ACCESS_NETWORK_STATE при использовании ограничения setRequiredNetworkType или setRequiredNetwork . Если ваше приложение не декларирует разрешение ACCESS_NETWORK_STATE при планировании задания и предназначено для Android 14 или более поздней версии, это приведет к возникновению SecurityException .

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

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

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

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

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

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

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

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

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

В 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 для запуска страницы настроек, на которой пользователи могут предоставить разрешение.

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

Ограничения на неявные и ожидаемые намерения

For apps targeting Android 14 (API level 34) or higher, Android restricts apps from sending implicit intents to internal app components in the following ways:

  • Implicit intents are only delivered to exported components. Apps must either use an explicit intent to deliver to unexported components, or mark the component as exported.
  • If an app creates a mutable pending intent with an intent that doesn't specify a component or package, the system throws an exception.

These changes prevent malicious apps from intercepting implicit intents that are intended for use by an app's internal components.

For example, here is an intent filter that could be declared in your app's manifest file:

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

If your app tried to launch this activity using an implicit intent, an ActivityNotFoundException exception would be thrown:

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"));

To launch the non-exported activity, your app should use an explicit intent instead:

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

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

Apps and services that target Android 14 (API level 34) or higher and use context-registered receivers are required to specify a flag to indicate whether or not the receiver should be exported to all other apps on the device: either RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED, respectively. This requirement helps protect apps from security vulnerabilities by leveraging the features for these receivers introduced in Android 13.

Exception for receivers that receive only system broadcasts

If your app is registering a receiver only for system broadcasts through Context#registerReceiver methods, such as Context#registerReceiver(), then it shouldn't specify a flag when registering the receiver.

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

If your app targets Android 14 (API level 34) or higher and uses Dynamic Code Loading (DCL), all dynamically-loaded files must be marked as read-only. Otherwise, the system throws an exception. We recommend that apps avoid dynamically loading code whenever possible, as doing so greatly increases the risk that an app can be compromised by code injection or code tampering.

If you must dynamically load code, use the following approach to set the dynamically-loaded file (such as a DEX, JAR, or APK file) as read-only as soon as the file is opened and before any content is written:

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

Handle dynamically-loaded files that already exist

To prevent exceptions from being thrown for existing dynamically-loaded files, we recommend deleting and recreating the files before you try to dynamically load them again in your app. As you recreate the files, follow the preceding guidance for marking the files read-only at write time. Alternatively, you can re-label the existing files as read-only, but in this case, we strongly recommend that you verify the integrity of the files first (for example, by checking the file's signature against a trusted value), to help protect your app from malicious actions.

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

Для приложений, ориентированных на 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() .

For apps targeting Android 14 (API level 34) or higher, a SecurityException is thrown by MediaProjection#createVirtualDisplay in either of the following scenarios:

Your app must ask the user to give consent before each capture session. A single capture session is a single invocation on MediaProjection#createVirtualDisplay, and each MediaProjection instance must be used only once.

Handle configuration changes

If your app needs to invoke MediaProjection#createVirtualDisplay to handle configuration changes (such as the screen orientation or screen size changing), you can follow these steps to update the VirtualDisplay for the existing MediaProjection instance:

  1. Invoke VirtualDisplay#resize with the new width and height.
  2. Provide a new Surface with the new width and height to VirtualDisplay#setSurface.

Register a callback

Your app should register a callback to handle cases where the user doesn't grant consent to continue a capture session. To do this, implement Callback#onStop and have your app release any related resources (such as the VirtualDisplay and Surface).

If your app doesn't register this callback, MediaProjection#createVirtualDisplay throws an IllegalStateException when your app invokes it.

Обновлены ограничения, не связанные с SDK

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

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

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

To learn more about the changes in this release of Android, see Updates to non-SDK interface restrictions in Android 14. To learn more about non-SDK interfaces generally, see Restrictions on non-SDK interfaces.