Как отличия между 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 — в основном расширения и оптимизации, а не новые ломающие ограничения.
Реальные проблемы совместимости и готовые решения
- Уведомления не видны
- Причина: отсутствует или неверен 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)
Создавайте каналы один раз при запуске и сохраняйте логику, если пользователь отключил канал — показывайте экран настроек канала.
-
Краш при вызове startService() из фона
- Причина: ограничения фоновой работы.
- Решение: если задача длительная — использовать startForegroundService() + startForeground() в течение 5 секунд; для отложенных задач — WorkManager/JobScheduler/JobIntentService.
-
Фоновые обновления геолокации слишком редкие
- Причина: ограничения для фоновых location‑запросов.
- Решение: если необходим реальный трекинг — оформить foreground service с уведомлением; минимизировать частоту запросов и использовать Fused Location Provider.
-
Падения из-за нативных библиотек
- Причина: сегменты .so с writable+executable флагами.
- Решение: пересобрать с правильными флагами линковщика/NDK, проверить упаковку APK/so, обновить инструменты сборки.
-
Неявные broadcast‑Receiver в манифесте не срабатывают
- Причина: запрет на большинство implicit broadcasts.
- Решение: регистрировать динамически через Context.registerReceiver() или переосмыслить архитектуру событий.
Чек‑лист для быстрой проверки совместимости (практически применимо)
- targetSdkVersion >= 26? Если да — обязательно пройти все пункты.
- Уведомления: созданы все NotificationChannel(ы), channelId совпадает.
- Сервисы: заменить фоновые startService() на WorkManager/JobIntentService или startForegroundService() + startForeground().
- Location: для фонового трекинга — foreground service.
- Native: проверить на linker errors, убрать W^X нарушения.
- Broadcasts: избежать reliance на implicit manifest broadcasts.
- Тесты: прогнать ручные/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‑кода)? Напишите эти параметры — и я сгенерирую готовые изменения.