Как и в предыдущих версиях, в 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 可能是由以下 2 种情况造成的:
1.有工作阻塞主线程,阻止回调 onStartJob
或者onStopJob在预期时间内执行并完成。
2. 开发者在 JobScheduler 中运行阻塞工作
回调 onStartJob 或 onStopJob,阻止从
在预期的时限内完成
要解决第 1 个问题,您需要进一步调试阻塞主线程的因素
您可以使用以下代码
ApplicationExitInfo#getTraceInputStream(),用于获取 Tombstone
ANR 发生时的跟踪信息如果您能够手动重现 ANR 问题
您可以录制系统轨迹,并使用
Android Studio 或 Perfetto,以便更好地了解应用上运行的
在发生 ANR 时调用主线程
请注意,直接使用 JobScheduler API 或使用 androidx 库 WorkManager 时可能会发生这种情况。
如需解决问题 2,请考虑迁移到 WorkManager,它支持将 onStartJob 或 onStopJob 中的任何处理封装在异步线程中。
JobScheduler 还引入了一项要求,即如果使用 setRequiredNetworkType 或 setRequiredNetwork 约束条件,则必须声明 ACCESS_NETWORK_STATE 权限。如果您的应用未声明
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 для запуска страницы настроек, на которой пользователи могут предоставить разрешение.
Безопасность
Ограничения на неявные и ожидаемые намерения
Для приложений, предназначенных для 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) или выше, система дополнительно ограничивает, когда приложениям разрешено запускать действия в фоновом режиме:
- Когда приложение отправляет
PendingIntentс помощьюPendingIntent#send()или аналогичных методов, приложение должно согласиться, если оно хочет предоставить свои собственные привилегии запуска фоновой активности для запуска ожидающего намерения. Чтобы принять участие, приложение должно передать пакетActivityOptionsс помощьюsetPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED). - Когда видимое приложение привязывает службу другого приложения, находящегося в фоновом режиме, с помощью
bindService(), видимое приложение теперь должно согласиться, если оно хочет предоставить свои собственные привилегии запуска фоновой активности связанному сервису. Чтобы принять участие, приложение должно включить флагBIND_ALLOW_ACTIVITY_STARTSпри вызове методаbindService().
Эти изменения расширяют существующий набор ограничений для защиты пользователей, не позволяя вредоносным приложениям злоупотреблять API и запускать разрушительные действия в фоновом режиме.
Обход почтового индекса
对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,Android 会通过以下方式防止 Zip 路径遍历漏洞:如果 Zip 文件条目名称包含“..”或以“/”开头,ZipFile(String) 和 ZipInputStream.getNextEntry() 会抛出 ZipException。
应用可以通过调用 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 .