Как и в предыдущих версиях, 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
IllegalArgumentExceptionis thrown by thejava.util.regex.Matcherclass, so make sure to test your app for areas that use regular expressions. To enable or disable this change while testing, toggle theDISALLOW_INVALID_GROUP_REFERENCEflag 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 anIllegalArgumentExceptionduring deserialization. To enable or disable this change while testing, toggle theENABLE_STRICT_VALIDATIONflag using the compatibility framework tools. - ProGuard issues: In some cases, the addition of the
java.lang.ClassValueclass 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 whetherClass.forName("java.lang.ClassValue")returns a class or not. If your app was developed against an older version of the runtime without thejava.lang.ClassValueclass available, then these optimizations might remove thecomputeValuemethod from classes derived fromjava.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 для отправки полноэкранных намерений, когда телефон заблокирован. Вы можете автоматически предоставить это разрешение при установке приложения, объявив разрешение 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 запрещает приложениям отправлять неявные намерения внутренним компонентам приложения следующими способами:
- Неявные намерения доставляются только экспортированным компонентам. Приложения должны либо использовать явное намерение доставить неэкспортированные компоненты, либо пометить компонент как экспортированный.
- Если приложение создает изменяемое ожидающее намерение с намерением, в котором не указан компонент или пакет, система выдает исключение.
Эти изменения не позволяют вредоносным приложениям перехватывать неявные намерения, предназначенные для использования внутренними компонентами приложения.
Например, вот фильтр намерений , который можно объявить в файле манифеста вашего приложения:
<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);
Приемники широковещательных сообщений, зарегистрированные во время выполнения, должны указать поведение экспорта.
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() .
Для каждой сессии захвата MediaProjection требуется согласие пользователя.
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 caches the
Intentthat is returned fromMediaProjectionManager#createScreenCaptureIntent, and passes it multiple times toMediaProjectionManager#getMediaProjection. - Your app invokes
MediaProjection#createVirtualDisplaymultiple times on the sameMediaProjectioninstance.
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:
- Invoke
VirtualDisplay#resizewith the new width and height. - Provide a new
Surfacewith the new width and height toVirtualDisplay#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 includes updated lists of restricted non-SDK interfaces based on collaboration with Android developers and the latest internal testing. Whenever possible, we make sure that public alternatives are available before we restrict non-SDK interfaces.
If your app does not target Android 14, some of these changes might not immediately affect you. However, while you can currently use some non-SDK interfaces (depending on your app's target API level), using any non-SDK method or field always carries a high risk of breaking your app.
If you are unsure if your app uses non-SDK interfaces, you can test your app to find out. If your app relies on non-SDK interfaces, you should begin planning a migration to SDK alternatives. Nevertheless, we understand that some apps have valid use cases for using non-SDK interfaces. If you cannot find an alternative to using a non-SDK interface for a feature in your app, you should request a new public API.
Дополнительные сведения об изменениях в этой версии Android см . в разделе Обновления ограничений интерфейса, не связанных с SDK, в Android 14 . Дополнительные сведения об интерфейсах, отличных от SDK, см. в разделе Ограничения на интерфейсы, не относящиеся к SDK .