Как и предыдущие выпуски, 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 . В некоторых случаях добавление класса
java.lang.ClassValue
вызывает проблемы, если вы пытаетесь сжать, запутать и оптимизировать свое приложение с помощью ProGuard. Проблема возникает из-за библиотеки Kotlin, которая меняет поведение во время выполнения в зависимости от того, возвращает лиClass.forName("java.lang.ClassValue")
класс или нет. Если ваше приложение было разработано для более старой версии среды выполнения без доступного классаjava.lang.ClassValue
, то эти оптимизации могут удалить методcomputeValue
из классов, производных от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
发送全屏 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_EXPORTED
, либо RECEIVER_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 的时间:
- 现在,当应用使用
PendingIntent#send()
或类似方法发送PendingIntent
时,如果它想要授予自己的后台 activity 启动待处理 intent 的启动特权,则必须选择启用。如需选择启用,应用应通过setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
传递ActivityOptions
软件包。 - 当可见应用绑定了另一个后台应用的服务时
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 требуется согласие пользователя.
Для приложений, предназначенных для Android 14 (уровень API 34) или выше, MediaProjection#createVirtualDisplay
создает исключение SecurityException
в любом из следующих сценариев:
- Ваше приложение кэширует
Intent
, возвращаемое изMediaProjectionManager#createScreenCaptureIntent
, и передает его несколько раз вMediaProjectionManager#getMediaProjection
. - Ваше приложение вызывает
MediaProjection#createVirtualDisplay
несколько раз в одном и том же экземпляреMediaProjection
.
Ваше приложение должно запрашивать у пользователя согласие перед каждым сеансом захвата. Один сеанс захвата — это один вызов MediaProjection#createVirtualDisplay
, и каждый экземпляр MediaProjection
должен использоваться только один раз.
Обработка изменений конфигурации
Если вашему приложению необходимо вызвать MediaProjection#createVirtualDisplay
для обработки изменений конфигурации (например, изменения ориентации или размера экрана), вы можете выполнить следующие действия, чтобы обновить VirtualDisplay
для существующего экземпляра MediaProjection
:
- Вызовите
VirtualDisplay#resize
с новой шириной и высотой. - Предоставьте новую
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 .