Как и в предыдущих версиях, Android 14 включает изменения в поведении, которые могут повлиять на ваше приложение. Следующие изменения в поведении применяются исключительно к приложениям, ориентированным на Android 14 (уровень API 34) или выше. Если ваше приложение ориентировано на Android 14 или выше, вам следует внести в него изменения для корректной поддержки этих изменений, где это применимо.
Обязательно ознакомьтесь также со списком изменений в поведении, которые затрагивают все приложения, работающие на Android 14, независимо от targetSdkVersion приложения.
Основная функциональность
Требуются типы служб переднего плана.
If your app targets Android 14 (API level 34) or higher, it must specify at least one foreground service type for each foreground service within your app. You should choose a foreground service type that represents your app's use case. The system expects foreground services that have a particular type to satisfy a particular use case.
If a use case in your app isn't associated with any of these types, it's strongly recommended that you migrate your logic to use WorkManager or user-initiated data transfer jobs.
Применение разрешения BLUETOOTH_CONNECT в BluetoothAdapter
Android 14 enforces the BLUETOOTH_CONNECT permission when calling the
BluetoothAdapter getProfileConnectionState() method for apps targeting
Android 14 (API level 34) or higher.
This method already required the BLUETOOTH_CONNECT permission, but it was not
enforced. Make sure your app declares BLUETOOTH_CONNECT in your app's
AndroidManifest.xml file as shown in the following snippet and check that
a user has granted the permission before calling
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 обеспечивает корректное отображение поведения при обратных вызовах и в сети.
С момента своего появления 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 запуска плиток
For apps targeting 14 and higher,
TileService#startActivityAndCollapse(Intent) is deprecated and now throws
an exception when called. If your app launches activities from tiles, use
TileService#startActivityAndCollapse(PendingIntent) instead.
Конфиденциальность
Частичный доступ к фотографиям и видео.
Android 14 introduces Selected Photos Access, which allows users to grant apps access to specific images and videos in their library, rather than granting access to all media of a given type.
This change is only enabled if your app targets Android 14 (API level 34) or higher. If you don't use the photo picker yet, we recommend implementing it in your app to provide a consistent experience for selecting images and videos that also enhances user privacy without having to request any storage permissions.
If you maintain your own gallery picker using storage permissions and need to
maintain full control over your implementation, adapt your implementation
to use the new READ_MEDIA_VISUAL_USER_SELECTED permission. If your app
doesn't use the new permission, the system runs your app in a compatibility
mode.
пользовательский опыт
Безопасные полноэкранные уведомления Intent
With Android 11 (API level 30), it was possible for any app to use
Notification.Builder.setFullScreenIntent to send full-screen
intents while the phone is locked. You could auto-grant this on app install by
declaring USE_FULL_SCREEN_INTENT permission in the
AndroidManifest.
Full-screen intent notifications are designed for extremely high-priority
notifications demanding the user's immediate attention, such as an incoming
phone call or alarm clock settings configured by the user. For apps targeting
Android 14 (API level 34) or higher, apps that are allowed to use this
permission are limited to those that provide calling and alarms only. The Google
Play Store revokes default USE_FULL_SCREEN_INTENT permissions for any apps
that don't fit this profile. The deadline for these policy changes is May 31,
2024.
This permission remains enabled for apps installed on the phone before the user updates to Android 14. Users can turn this permission on and off.
You can use the new API
NotificationManager.canUseFullScreenIntent to check if your app
has the permission; if not, your app can use the new intent
ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT to launch the settings
page where users can grant the permission.
Безопасность
Ограничения, касающиеся неявных и ожидающих намерений.
Для приложений, предназначенных для 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 и запускать разрушительные действия в фоновом режиме.
Обход по зип-пути
For apps targeting Android 14 (API level 34) or higher, Android prevents the Zip
Path Traversal Vulnerability in the following way:
ZipFile(String) and
ZipInputStream.getNextEntry() throws a
ZipException if zip file entry names contain ".." or start
with "/".
Apps can opt-out from this validation by calling
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.
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.