Как и в предыдущих версиях, в 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 усиливает обратный вызов и сетевое поведение
С момента своего появления 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 запуска плиток
对于以 Android 14 及更高版本为目标平台的应用,
TileService#startActivityAndCollapse(Intent) 已弃用,现在会抛出
调用时抛出异常。如果您的应用从功能块启动 activity,请使用
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 для запуска страницы настроек, на которой пользователи могут предоставить разрешение.
Безопасность
Ограничения на неявные и ожидаемые намерения
Для приложений, предназначенных для 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()方法绑定其他在后台应用的服务时,如果可见应用想要授予自己的后台 activity 对绑定服务的启动特权,则必须选择启用。如需选择启用,应用应在调用bindService()方法时包含BIND_ALLOW_ACTIVITY_STARTS标志。
这些更改扩大了一组现有限制条件的范围,目的是防止恶意应用滥用 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:
- 您的应用会缓存从
MediaProjectionManager#createScreenCaptureIntent返回的Intent,并多次将其传递给MediaProjectionManager#getMediaProjection。 - 您的应用在同一
MediaProjection实例上多次调用MediaProjection#createVirtualDisplay。
您的应用必须在每次捕获会话之前征求用户同意。单次捕获会话是对 MediaProjection#createVirtualDisplay 的单次调用,并且每个 MediaProjection 实例只能使用一次。
处理配置变更
如果您的应用需要调用 MediaProjection#createVirtualDisplay 来处理配置更改(例如屏幕方向或屏幕大小更改),您可以按照以下步骤更新现有 MediaProjection 实例的 VirtualDisplay:
- 使用新的宽度和高度调用
VirtualDisplay#resize。 - 向
VirtualDisplay#setSurface提供新的Surface,并为其指定新的宽度和高度。
注册回调
您的应用应注册回调,以处理用户不同意继续拍摄会话的情况。为此,请实现 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 .