Как отличия между Android 8.0 и 8.1 влияют на совместимость приложений

Коротко: Android 8.0 (API 26) ввёл ключевые ограничения — фоновые сервисы, обязательные Notification Channels, изоляцию идентификаторов и ужесточение загрузки нативного кода (W^X). Android 8.1 (API 27) добавил API‑улучшения (Autofill, SharedMemory, оптимизации для Android Go) и не вводит новых фундаментальных ограничений — большинство «сломанных» сценариев связаны именно с 8.0. Ниже — что проверить и как быстро исправить проблемы.

Если приложение «сломалось» на Oreo — сначала проверьте notification channels, поведение фоновых сервисов и ошибки загрузки native libs в logcat.

Ключевые отличия Android 8.0 vs 8.1

Оглавление {{TOC_AUTOMATIC}}

Что важнее всего для совместимости

  • Background execution limits (8.0): startService() из фона может привести к IllegalStateException — нужно использовать startForegroundService() или планировщики задач.
  • Notification Channels (8.0): уведомления от приложений, таргетирующих API≥26, должны иметь channelId; без канала уведомления не показываются.
  • ANDROID_ID и приватность (8.0): идентификаторы стали скопированными по ключу подписи приложения — нельзя использовать их как глобальные кросс‑приложенческие ID.
  • W^X и native libs (8.0): запрещены сегменты, одновременно writable и executable — некорректные .so могут вызывать падения.
  • Android 8.1: доработки Autofill, SharedMemory, улучшения для Android Go — в основном расширения и оптимизации, а не новые ломающие ограничения.

Реальные проблемы совместимости и готовые решения

  1. Уведомления не видны
    • Причина: отсутствует или неверен NotificationChannel.
    • Решение: при старте приложения создать каналы для всех типов уведомлений; проверять, что channelId совпадает. Пример на Kotlin:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val ch = NotificationChannel("default_channel", "Основные", NotificationManager.IMPORTANCE_DEFAULT)
    (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(ch)
}
val notif = NotificationCompat.Builder(this, "default_channel")
    .setContentTitle("Заголовок")
    .setContentText("Текст")
    .setSmallIcon(R.drawable.ic_notification)
    .build()
NotificationManagerCompat.from(this).notify(1, notif)

Создавайте каналы один раз при запуске и сохраняйте логику, если пользователь отключил канал — показывайте экран настроек канала.

  1. Краш при вызове startService() из фона

    • Причина: ограничения фоновой работы.
    • Решение: если задача длительная — использовать startForegroundService() + startForeground() в течение 5 секунд; для отложенных задач — WorkManager/JobScheduler/JobIntentService.
  2. Фоновые обновления геолокации слишком редкие

    • Причина: ограничения для фоновых location‑запросов.
    • Решение: если необходим реальный трекинг — оформить foreground service с уведомлением; минимизировать частоту запросов и использовать Fused Location Provider.
  3. Падения из-за нативных библиотек

    • Причина: сегменты .so с writable+executable флагами.
    • Решение: пересобрать с правильными флагами линковщика/NDK, проверить упаковку APK/so, обновить инструменты сборки.
  4. Неявные broadcast‑Receiver в манифесте не срабатывают

    • Причина: запрет на большинство implicit broadcasts.
    • Решение: регистрировать динамически через Context.registerReceiver() или переосмыслить архитектуру событий.

Чек‑лист для быстрой проверки совместимости (практически применимо)

  1. targetSdkVersion >= 26? Если да — обязательно пройти все пункты.
  2. Уведомления: созданы все NotificationChannel(ы), channelId совпадает.
  3. Сервисы: заменить фоновые startService() на WorkManager/JobIntentService или startForegroundService() + startForeground().
  4. Location: для фонового трекинга — foreground service.
  5. Native: проверить на linker errors, убрать W^X нарушения.
  6. Broadcasts: избежать reliance на implicit manifest broadcasts.
  7. Тесты: прогнать ручные/CI тесты на Android 8.0 и 8.1 в состояниях foreground/background/doze.

OEM‑оптимизации батареи (Xiaomi, Huawei и др.) могут усиливать проявления проблем с фоновыми задачами — проверяйте на реальных устройствах.

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

  • Не создали канал уведомлений или изменили channelId — уведомления не отображаются.
  • Использование startService() из background вместо стартового/foreground решения — приложение падает.
  • Полагание на ANDROID_ID как на глобальный идентификатор между приложениями.
  • Неправильная упаковка native libs — недоступность/краши на запуске.
  • Ожидание implicit broadcast‑ов, которые больше не доставляются через манифест.

FAQ

  • Нужна ли поддержка Android Go (8.1)?
    Да, если вы целитесь на устройства ≤1GB RAM — тестируйте и оптимизируйте память; Play‑фильтрация помечает «оптимизированные» приложения.
  • Обязательно ли менять все startService на WorkManager?
    Нет: для задач, требующих немедленного длительного выполнения в фоне, используйте foreground service; для периодических/отложенных задач — WorkManager.
  • Как быстро найти причину «тихого» не получения уведомлений?
    Проверьте в настройках приложения каналы уведомлений и logcat на предупреждения о channelId; также используйте отладочные опции разработчика для уведомлений.

Рекомендации для поддержки проекта

  • В CI включите тесты на образах/эмуляторах Android 8.0 и 8.1 и прогоняйте сценарии background→foreground, doze, восстановление после перезапуска.
  • Выделите в баг‑трекинге отдельную метку «Oreo» и собирайте stacktrace/логкат для каждого инцидента на этих версиях.
  • При наличии нативного кода — обновите NDK/инструменты сборки и прогоните smoke‑tests на реальных устройствах.

Вы хотите, чтобы я подготовил конкретный чек‑лист/патч под ваш проект (по targetSdkVersion, используемым сервисам и наличию native‑кода)? Напишите эти параметры — и я сгенерирую готовые изменения.