Android WebView: Особенности и версионность
Android WebView — это отдельное приложение, которое обновляется через Google Play. Это создаёт уникальные challenges для тестирования: фрагментацию версий, проблемы с обновлениями и специфичные баги.
1 Android WebView как системный компонент
Android WebView — это не просто часть операционной системы, а отдельное приложение, которое устанавливается и обновляется через Google Play. Это фундаментальное отличие от iOS, где WKWebView обновляется только с обновлением iOS.
Исторический контекст:
- До Android 4.4 (KitKat): WebView был частью AOSP (Android Open Source Project) и обновлялся только с OTA-обновлениями Android. Это приводило к ужасной фрагментации — на устройствах могли годами работать устаревшие версии WebView.
- Android 4.4 (2013): Google начала использовать Chromium-based WebView, но он всё ещё был частью AOSP.
- Android 5.0 (Lollipop, 2014): WebView стал отдельным приложением в Google Play. Теперь Google может обновлять его независимо от версии Android.
- Современность: Android WebView обновляется каждые 2-4 недели, получая новые фичи и исправления безопасности.
Что это значит для QA:
- Разные версии WebView на разных устройствах: Даже если у двух пользователей одинаковая версия Android, у них могут быть разные версии WebView.
- Проблема с обновлениями: Пользователи могут не обновлять WebView, оставаясь на старых версиях с багами.
- Необходимость тестирования на разных версиях: Нельзя тестировать только на одной версии Android — нужно проверять разные версии WebView.
Если баг воспроизводится на Android 12 с WebView 120, но не на Android 12 с WebView 115 — это баг конкретной версии WebView. Такие баги часто исправляются в следующих обновлениях, но нужно знать, на каких версиях они есть.
2 Как узнать версию WebView на устройстве
Знание версии WebView критически важно для локализации багов. Вот все способы узнать версию:
Способ 1: Через настройки устройства (самый простой)
- Откройте Настройки устройства.
- Перейдите в Приложения (или «Приложения и уведомления»).
- Найдите Android System WebView (может называться «Системный WebView Android»).
- Нажмите на него и посмотрите версию (например, 120.0.6099.144).
Если не можете найти WebView в списке приложений, включите отображение системных приложений:
- В настройках приложений нажмите на три точки (меню).
- Выберите «Показать системные» или «Показать все приложения».
Способ 2: Через ADB (для разработчиков и QA)
# Подключите устройство через USB и выполните:
adb shell dumpsys package com.google.android.webview | grep versionName
# Вывод будет примерно таким:
# versionName=120.0.6099.144
Способ 3: Через JavaScript (программно)
// В консоли DevTools выполните:
console.log(navigator.userAgent);
// Вывод будет примерно таким:
// Mozilla/5.0 (Linux; Android 13; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko)
// Chrome/120.0.6099.144 Mobile Safari/537.36
// Версия WebView — это версия Chrome в User-Agent (120.0.6099.144)
Способ 4: Через код приложения (для разработчиков)
val webView = findViewById<WebView>(R.id.webview)
val webViewVersion = WebView.getCurrentWebViewPackage()?.versionName
Log.d("WebView", "Version: $webViewVersion")
На некоторых устройствах WebView может называться по-другому:
- Стандартное название: Android System WebView
- На Samsung: Samsung Internet (может использоваться вместо стандартного WebView)
- На Xiaomi: Mi WebView (на некоторых устройствах)
- На Huawei: Huawei WebView (на старых устройствах без Google Play)
Всегда проверяйте, какой именно WebView используется на устройстве!
3 Фрагментация версий Android WebView
Фрагментация — это главная боль Android-тестировщика. В отличие от iOS, где все пользователи на одной версии iOS имеют одинаковый WebKit, на Android ситуация намного сложнее.
Факторы фрагментации:
- Версия Android: От Android 5.0 (API 21) до Android 14 (API 34).
- Версия WebView: От 37 (Android 5.0) до 120+ (современные версии).
- Производитель устройства: Samsung, Xiaomi, Huawei, Google Pixel и т.д.
- Наличие Google Play: На устройствах без Google Play (Huawei, китайские устройства) WebView может не обновляться.
- Пользовательские настройки: Некоторые пользователи отключают автообновления.
Что это значит для тестирования:
- Нельзя тестировать только на одной версии: Нужно проверять минимум 3-5 разных версий WebView.
- Приоритет версий: 80% пользователей имеют WebView последних 6 месяцев. Фокусируйтесь на них.
- Старые версии: Если баг есть только на WebView < 90, но таких пользователей < 5%, можно не исправлять (решение бизнеса).
- Минимальная поддерживаемая версия: Определите с бизнесом, какие версии WebView вы поддерживаете (обычно последние 2 года).
| Версия Android | Мин. версия WebView | Макс. версия WebView | Особенности |
|---|---|---|---|
| Android 5.0 (Lollipop) | 37 | 105 | Первая версия с WebView в Google Play |
| Android 6.0 (Marshmallow) | 44 | 105 | Добавлены runtime permissions |
| Android 7.0 (Nougat) | 51 | 105 | Мультиоконный режим |
| Android 8.0 (Oreo) | 60 | 120+ | Background execution limits |
| Android 9.0 (Pie) | 68 | 120+ | Safe Area support, Dark Theme |
| Android 10 | 76 | 120+ | Scoped storage |
| Android 11 | 86 | 120+ | Package visibility |
| Android 12 | 95 | 120+ | Material You, Privacy Dashboard |
| Android 13 | 104 | 120+ | Photo picker, Notification permissions |
| Android 14 | 113 | 120+ | Predictive back gesture |
Рекомендуемая матрица тестирования для Android WebView:
- Обязательно: Последние 3 версии WebView (120, 119, 118).
- Желательно: Последние 6 месяцев (WebView 115+).
- Опционально: Старые версии (WebView 90-110), если есть пользователи.
- Не нужно: WebView < 90 (если только это не критично для бизнеса).
4 Chrome Custom Tabs: Альтернатива WebView
Chrome Custom Tabs — это альтернатива WebView для открытия веб-контента. Это «облегчённая» версия Chrome, которая интегрируется в ваше приложение, но использует полноценный движок Chrome.
Когда использовать Chrome Custom Tabs вместо WebView:
- Открытие внешних ссылок: Когда нужно открыть сайт, не связанный с вашим приложением.
- Авторизация через OAuth: Google, Facebook, VK — все рекомендуют использовать Custom Tabs.
- Платёжные шлюзы: 3-D Secure, страницы банков.
- Контент с cookies: Custom Tabs сохраняет cookies пользователя из Chrome.
Преимущества Chrome Custom Tabs:
- Быстрая загрузка: Использует тот же движок, что и Chrome (предварительная инициализация).
- Общие cookies: Пользователь уже авторизован в Google/Facebook.
- Безопасность: Автоматические обновления через Google Play.
- Знакомый UX: Пользователь видит привычный интерфейс Chrome.
- Поддержка всех фич: Все современные CSS/JS-фичи из Chrome.
Недостатки Chrome Custom Tabs:
- Ограниченный контроль: Нельзя полностью кастомизировать UI (только цвет тулбара).
- Нет JS Bridge: Нельзя вызывать нативные методы из JavaScript.
- Зависимость от Chrome: Если Chrome не установлен, Custom Tabs не работает.
- Нет доступа к нативным API: Камера, геолокация — всё через стандартные веб-API.
val uri = Uri.parse("https://example.com")
val intentBuilder = CustomTabsIntent.Builder()
// Настройка цвета тулбара
intentBuilder.setToolbarColor(ContextCompat.getColor(this, R.color.primary))
// Показывать заголовок страницы
intentBuilder.setShowTitle(true)
// Включить кнопку "Назад"
intentBuilder.setCloseButtonIcon(
BitmapFactory.decodeResource(resources, R.drawable.ic_arrow_back)
)
val customTabsIntent = intentBuilder.build()
customTabsIntent.launchUrl(this, uri)
| Критерий | WebView | Chrome Custom Tabs |
|---|---|---|
| Контроль над UI | ✅ Полный | ⚠️ Ограниченный |
| JS Bridge | ✅ Поддерживается | ❌ Не поддерживается |
| Cookies пользователя | ❌ Изолированы | ✅ Общие с Chrome |
| Скорость загрузки | ⚠️ Средняя | ✅ Быстрая (предзагрузка) |
| Поддержка фич | ⚠️ Зависит от версии | ✅ Все фичи Chrome |
| Работа без Chrome | ✅ Работает | ❌ Не работает |
Если ваше приложение использует Chrome Custom Tabs, тестируйте:
- Что происходит, если Chrome не установлен на устройстве.
- Что происходит, если Chrome отключён в настройках.
- Корректность возврата в приложение после закрытия Custom Tabs.
- Сохранение состояния (если пользователь авторизовался через OAuth).
5 User-Agent Android WebView
User-Agent — это строка, которую WebView отправляет на сервер при каждом запросе. Сервер использует её для определения типа устройства, версии ОС и версии WebView.
Стандартный User-Agent Android WebView:
Mozilla/5.0 (Linux; Android 13; Pixel 6 Build/TQ3A.230705.001)
AppleWebKit/537.36 (KHTML, like Gecko)
Version/4.0 Chrome/120.0.6099.144 Mobile Safari/537.36
Разбор User-Agent:
Mozilla/5.0— историческое наследие, есть у всех браузеров.Linux; Android 13— операционная система и версия.Pixel 6 Build/TQ3A.230705.001— модель устройства и сборка Android.AppleWebKit/537.36— версия движка (WebKit/Blink).Chrome/120.0.6099.144— версия WebView (это и есть версия Blink).Mobile Safari/537.36— историческое наследие от Safari.
Зачем серверу нужен User-Agent:
- Адаптивная вёрстка: Сервер может отдавать разный HTML/CSS для мобильных и десктопных устройств.
- Определение возможностей: Сервер может проверять, поддерживает ли WebView определённые фичи.
- Аналитика: Сбор статистики по устройствам и версиям.
- Безопасность: Блокировка устаревших версий WebView с известными уязвимостями.
Как изменить User-Agent (для разработчиков):
val webView = findViewById<WebView>(R.id.webview)
// Получить текущий User-Agent
val defaultUserAgent = webView.settings.userAgentString
Log.d("WebView", "Default UA: $defaultUserAgent")
// Изменить User-Agent
webView.settings.userAgentString = "MyApp/1.0 $defaultUserAgent"
// Или добавить приложение к стандартному User-Agent
val customUA = webView.settings.userAgentString + " MyApp/1.0"
webView.settings.userAgentString = customUA
Типичные проблемы с User-Agent:
- Сервер не распознаёт WebView: Некоторые серверы проверяют наличие
Chromeв User-Agent. Если его нет, сервер может отдавать упрощённую версию сайта. - Блокировка устаревших версий: Если сервер блокирует WebView < 100, а у пользователя WebView 95, сайт не загрузится.
- Проблемы с адаптивной вёрсткой: Если User-Agent изменён, сервер может не распознать мобильное устройство.
Для проверки User-Agent:
- Откройте в WebView страницу whatsmyua.info.
- Посмотрите, какой User-Agent отправляется.
- Сравните с User-Agent в обычном Chrome на том же устройстве.
- Проверьте, как сервер реагирует на разные User-Agent (используйте Charles/Proxyman для подмены).
6 Специфичные баги Android WebView
Android WebView имеет ряд специфических багов, которые не встречаются в iOS WKWebView. Знание этих багов поможет вам быстрее локализовать проблемы.
Баг 1: Проблема с position: fixed при скролле
Фиксированные элементы (хедер, футер, кнопки) "прыгают" или "уезжают" при скролле.
Особенно заметно на старых версиях Android (5.0-7.0).
/* Используйте transform для "приклеивания" элементов */
.fixed-header {
position: fixed;
top: 0;
width: 100%;
transform: translateZ(0); /* Создаёт отдельный слой */
will-change: transform;
}
/* Или используйте sticky position (работает лучше) */
.sticky-header {
position: -webkit-sticky;
position: sticky;
top: 0;
}
Баг 2: input type="date" выглядит по-разному
Нативный date picker на Android выглядит по-разному на разных версиях:
- Android 5.0-6.0: Старый диалог с колёсиками
- Android 7.0-9.0: Календарь в стиле Material Design
- Android 10+: Современный Material You дизайн
/* Используйте кастомный date picker на JavaScript */
<input type="text" id="date-picker" placeholder="Выберите дату">
<script>
// Подключите библиотеку типа flatpickr или pikaday
flatpickr("#date-picker", {
dateFormat: "Y-m-d",
locale: "ru"
});
</script>
Баг 3: Проблема с overflow: auto на старых версиях
На Android 5.0-7.0 скролл внутри контейнера с overflow: auto может не работать.
Контент обрезается, но прокрутить его нельзя.
/* Добавьте -webkit-overflow-scrolling */
.scrollable {
overflow-y: auto;
-webkit-overflow-scrolling: touch; /* Для iOS */
/* Для старых Android */
overflow-scrolling: touch;
}
/* Или используйте JavaScript-библиотеку для скролла (iScroll, Swiper) */
Баг 4: Утечки памяти при длительной работе
При длительном использовании WebView (30+ минут) приложение начинает тормозить,
потреблять много памяти и может крашиться.
Особенно заметно на устройствах с малым объёмом RAM (1-2 ГБ).
// В нативном коде (Kotlin)
override fun onPause() {
super.onPause()
webView?.onPause() // Приостанавливает JavaScript, анимации
webView?.pauseTimers() // Приостанавливает таймеры
}
override fun onResume() {
super.onResume()
webView?.onResume()
webView?.resumeTimers()
}
override fun onDestroy() {
webView?.destroy() // Освобождает ресурсы
super.onDestroy()
}
Баг 5: Проблема с will-change и потреблением памяти
Чрезмерное использование will-change приводит к потреблению большого объёма памяти.
Приложение может крашиться с ошибкой "Out of memory".
/* ❌ Плохо: will-change на всех элементах */
* {
will-change: transform;
}
/* ✅ Хорошо: will-change только для анимируемых элементов */
.animated-button {
will-change: transform;
transition: transform 0.3s ease;
}
/* Убирайте will-change после анимации */
.animated-button:hover {
will-change: transform;
}
.animated-button:not(:hover) {
will-change: auto;
}
Баг 6: Проблема с input type="file" и загрузкой файлов
На некоторых версиях Android WebView не открывает диалог выбора файла при клике на input type="file".
Или диалог открывается, но файл не загружается.
// В нативном коде (Kotlin) нужно обработать onShowFileChooser
webView.webChromeClient = object : WebChromeClient() {
override fun onShowFileChooser(
webView: WebView?,
filePathCallback: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams?
): Boolean {
// Сохраняем callback для später использования
this.filePathCallback = filePathCallback
// Открываем intent для выбора файла
val intent = fileChooserParams?.createIntent()
startActivityForResult(intent, FILE_CHOOSER_REQUEST_CODE)
return true
}
}
// В onActivityResult обрабатываем результат
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == FILE_CHOOSER_REQUEST_CODE) {
if (resultCode == RESULT_OK && data != null) {
val result = FileChooserParams.parseResult(resultCode, data)
filePathCallback?.onReceiveValue(result)
} else {
filePathCallback?.onReceiveValue(null)
}
}
}
Если вы нашли баг, который воспроизводится только на Android, но не на iOS:
- Проверьте версию WebView (может, это баг конкретной версии).
- Проверьте версию Android (может, это баг конкретной версии ОС).
- Проверьте производителя устройства (Samsung, Xiaomi могут иметь модифицированный WebView).
- Поищите баг на Chromium Bug Tracker — возможно, он уже известен.
- ✅ Проверьте баг на минимум 3 разных версиях WebView.
- ✅ Проверьте баг на разных производителях (Samsung, Xiaomi, Pixel).
- ✅ Проверьте баг на разных версиях Android (если возможно).
- ✅ Укажите в баг-репорте версию WebView и версию Android.
- ✅ Приложите скриншоты и логи (Logcat).
- ✅ Проверьте, воспроизводится ли баг в обычном Chrome на том же устройстве.