Изменения поведения: приложения для Android 14 или более поздней версии. Изменения поведения: приложения для Android 14 или более поздней версии. Изменения поведения: приложения для Android 14 или более поздней версии. Изменения поведения: приложения для Android 14 или более поздней версии.

Как и предыдущие выпуски, Android 14 включает изменения поведения, которые могут повлиять на ваше приложение. Следующие изменения поведения применяются исключительно к приложениям, нацеленным на Android 14 (API уровня 34) или выше. Если ваше приложение нацелено на Android 14 или выше, вам следует изменить свое приложение для поддержки этих поведений должным образом, где это применимо.

Обязательно ознакомьтесь со списком изменений поведения, которые влияют на все приложения, работающие на Android 14, независимо от targetSdkVersion приложения.

Основная функциональность

Требуются типы служб переднего плана

Если ваше приложение предназначено для Android 14 (уровень API 34) или более поздней версии, оно должно указать хотя бы один тип службы переднего плана для каждой службы переднего плана в вашем приложении. Вам следует выбрать тип службы приоритетного плана, который соответствует варианту использования вашего приложения. Система ожидает, что службы приоритетного плана, имеющие определенный тип, удовлетворят конкретному сценарию использования.

Если вариант использования в вашем приложении не связан ни с одним из этих типов, настоятельно рекомендуется перенести вашу логику на использование WorkManager или заданий передачи данных, инициируемых пользователем .

Обеспечение разрешения 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 продолжается работа по обновлению основных библиотек 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 . Если ваше приложение не использует новое разрешение, система запускает его в режиме совместимости .

Пользовательский опыт

Безопасные полноэкранные уведомления о намерениях

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);

Приемники широковещательных сообщений, зарегистрированные во время выполнения, должны указывать поведение экспорта

以 Android 14(API 级别 34)或更高版本为目标平台并使用上下文注册的接收器的应用和服务必须指定以下标志,以指明接收器是否应导出到设备上的所有其他应用:RECEIVER_EXPORTEDRECEIVER_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 следующим образом: ZipFile(String) и ZipInputStream.getNextEntry() выдают исключение ZipException , если имена записей zip-файла содержат «..» или start. с "/".

Приложения могут отказаться от этой проверки, вызвав dalvik.system.ZipPathValidator.clearCallback() .

Для приложений, предназначенных для Android 14 (уровень API 34) или выше, MediaProjection#createVirtualDisplay создает исключение SecurityException в любом из следующих сценариев:

Ваше приложение должно запрашивать у пользователя согласие перед каждым сеансом захвата. Один сеанс захвата — это один вызов MediaProjection#createVirtualDisplay , и каждый экземпляр MediaProjection должен использоваться только один раз.

Обработка изменений конфигурации

Если вашему приложению необходимо вызвать MediaProjection#createVirtualDisplay для обработки изменений конфигурации (например, изменения ориентации или размера экрана), вы можете выполнить следующие действия, чтобы обновить VirtualDisplay для существующего экземпляра MediaProjection :

  1. Вызовите VirtualDisplay#resize с новой шириной и высотой.
  2. Предоставьте новую 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 .