Что важно знать разработчику при адаптации под Android 12

Кратко: Android 12 (API 31) вводит новые runtime‑разрешения (новые Bluetooth‑права, approximate location), строгие требования к PendingIntent и android:exported, ограничивает запуск foreground‑служб из фона и добавляет поведение авто‑сброса прав — всё это требует правок манифеста, кода и тестов перед релизом.

Ключевые изменения, влияющие на совместимость

  • PendingIntent: теперь обязательно указывать FLAG_IMMUTABLE или FLAG_MUTABLE. По умолчанию используйте FLAG_IMMUTABLE и ставьте FLAG_MUTABLE только когда действительно изменяете intent (например, inline reply).

    • Пример: PendingIntent.getActivity(ctx, id, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT)
  • android:exported: для Activity/Service/BroadcastReceiver с intent‑filter нужно явно указать android:exported="true" или "false". Иначе сборка/установка при targetSdk 31 провалится.

  • Foreground‑сервисы: запрещён запуск startForegroundService из фона для приложений, таргетирующих S+. Для срочных задач используйте WorkManager (expedited work) или exact alarm + запуск сервиса в момент выполнения.

  • Разрешения локации: появилась опция approximate location — UX должен предугадывать, что пользователь может дать только ACCESS_COARSE_LOCATION. Запрашивайте и обрабатывайте оба варианта.

  • Bluetooth: старые BLUETOOTH/BLUETOOTH_ADMIN заменены на BLUETOOTH_SCAN, BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE с новыми ограничениями для фонового сканирования.

  • App hibernation и auto‑reset permissions: система может сбрасывать runtime‑permissions и останавливать фоновые процессы для неиспользуемых приложений — добавьте сценарии повторного получения прав и восстановления состояния.

  • Нотификации и trampoline: ограничено использование "трамплинов" для запуска Activity из фоновых компонентов; проверьте ваши уведомления и deeplink‑обработку.

  • Мультимедиа и WebView: платформа добавляет AVIF и транс‑кодирование, WebView ужесточил SameSite cookies — проверьте сценарии авторизации через встроенные вебы.

Большинство изменений применяются именно к приложениям с targetSdkVersion = 31. Если пока не обновляете target, всё равно тестируйте на Android 12-устройствах.

Практический чек‑лист перед релизом

  1. Обновить compileSdkVersion = 31 и targetSdkVersion = 31 в Gradle, собрать проект и исправить ошибки сборки.
  2. Найти и исправить все PendingIntent — добавить FLAG_IMMUTABLE/FLAG_MUTABLE.
  3. Пройти mergedManifest и явно указать android:exported для всех компонентов с intent‑filter.
  4. Переработать фоновые задачи: заменить неразрешённый startForegroundService на WorkManager/expedited work или exact alarm.
  5. Заменить старые Bluetooth‑perm на новые и реализовать runtime‑запросы для BLUETOOTH_SCAN/CONNECT/ADVERTISE.
  6. Обработать approximate location в логике и запросах разрешений.
  7. Перейти на SplashScreen API, если используете кастомные сплэш‑решения.
  8. Добавить UX для восстановления прав после app hibernation (информирование и повторный запрос).
  9. Обновить сторонние SDK (push, аналitika, платежи) до версий, совместимых с API 31.
  10. Прогнать smoke‑tests: permissions flows, BLE сценарии, уведомления, foreground‑work, WebView auth, воспроизведение/загрузка медиа.

Тестируйте сначала с targetSdk 31 в debug‑сборке и включайте режимы совместимости в Developer options — это помогает локализовать причины сбоев быстрее.

Тестирование и распространённые проблемы (и как их решать)

  • Ошибка "requires FLAG_IMMUTABLE" → найти все вызовы PendingIntent и указать флаг. Используйте статический анализатор или grep по проекту.
  • Manifest merger: "android:exported needs to be explicitly specified" → проверьте зависимости и плагины, обновите/патчьте манифесты библиотек.
  • Crash при Bluetooth‑сканировании → убедитесь в наличии BLUETOOTH_SCAN + runtime‑запросах, обработайте отказ пользователя и ограничения фонового сканирования.
  • ForegroundServiceStartNotAllowedException → замените логику запуска на WorkManager/expedited work или поднимайте foreground‑сервис только из пользовательского контекста (взаимодействие UI).
  • WebView SameSite/авторизация ломает флоу → тестируйте входы через встроенный браузер, при необходимости реализуйте fallback на внешние браузеры или web auth flows.

Обновление только compileSdk без проработки поведенческих изменений часто вызывает runtime‑краши на устройствах с Android 12. Проверяйте не только сборку, но и реальные сценарии.

Частые ошибки

  • Забыт FLAG_IMMUTABLE в PendingIntent.
  • Не указано android:exported в компонентах из библиотек.
  • Ожидание, что BLE‑поведение осталось прежним — фоновые сканы теперь строже.
  • Нет UX для восстановления прав после hibernation — потеря функциональности без объяснения пользователю.

FAQ

  • Нужно ли срочно менять targetSdk на 31?

    • Менять стоит планово: сначала в debug‑ветку, исправить все ошибки сборки и поведенческие регрессии, затем выпускать обновление. Play Console может требовать обновлённый target для новых публикаций.
  • Как быстро найти все PendingIntent в коде?

    • Поиск по getActivity/getService/getBroadcast + ревью библиотек; статический анализ и CI‑шаблоны помогут предотвратить пропуски.
  • Что делать, если уведомления перестали запускать Activity?

    • Убедитесь, что вы не используете trampoline (запуск Activity через короткий intermediate receiver/service). В Intent, который передаёте в PendingIntent, укажите явную Activity и правильные флаги, и соблюдайте требования FLAG_IMMUTABLE.

Короткий план на неделю: обновить target/compile → исправить сборку (exported, PendingIntent) → обновить SDK依赖 → ручное тестирование на Android 12 (permissions, BLE, notifications, foreground‑work) → выпуск. Если нужно, подготовлю diff и набор adb/espresso тестов под ваш стек.