Глава 1.4: Android WebView: Особенности и версионность

Фрагментация, обновления через Google Play и специфичные баги Android

Глава 1.4 • Часть 1 из 8

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 недели, получая новые фичи и исправления безопасности.
2013
Android 4.4
Chromium-based WebView, но часть AOSP
2014
Android 5.0
WebView становится отдельным приложением в Google Play
2020+
Современность
Обновления каждые 2-4 недели через Google Play

Что это значит для QA:

  • Разные версии WebView на разных устройствах: Даже если у двух пользователей одинаковая версия Android, у них могут быть разные версии WebView.
  • Проблема с обновлениями: Пользователи могут не обновлять WebView, оставаясь на старых версиях с багами.
  • Необходимость тестирования на разных версиях: Нельзя тестировать только на одной версии Android — нужно проверять разные версии WebView.
🎯 Почему это важно

Если баг воспроизводится на Android 12 с WebView 120, но не на Android 12 с WebView 115 — это баг конкретной версии WebView. Такие баги часто исправляются в следующих обновлениях, но нужно знать, на каких версиях они есть.

2 Как узнать версию WebView на устройстве

Знание версии WebView критически важно для локализации багов. Вот все способы узнать версию:

Способ 1: Через настройки устройства (самый простой)

  1. Откройте Настройки устройства.
  2. Перейдите в Приложения (или «Приложения и уведомления»).
  3. Найдите Android System WebView (может называться «Системный WebView Android»).
  4. Нажмите на него и посмотрите версию (например, 120.0.6099.144).
💡 Лайфхак

Если не можете найти WebView в списке приложений, включите отображение системных приложений:

  • В настройках приложений нажмите на три точки (меню).
  • Выберите «Показать системные» или «Показать все приложения».

Способ 2: Через ADB (для разработчиков и QA)

Команда ADB для получения версии WebView
# Подключите устройство через USB и выполните:
adb shell dumpsys package com.google.android.webview | grep versionName

# Вывод будет примерно таким:
# versionName=120.0.6099.144

Способ 3: Через JavaScript (программно)

Получение версии WebView через 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: Через код приложения (для разработчиков)

Получение версии WebView в Kotlin
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 ситуация намного сложнее.

Факторы фрагментации:

  1. Версия Android: От Android 5.0 (API 21) до Android 14 (API 34).
  2. Версия WebView: От 37 (Android 5.0) до 120+ (современные версии).
  3. Производитель устройства: Samsung, Xiaomi, Huawei, Google Pixel и т.д.
  4. Наличие Google Play: На устройствах без Google Play (Huawei, китайские устройства) WebView может не обновляться.
  5. Пользовательские настройки: Некоторые пользователи отключают автообновления.
Пример распределения версий WebView (условные данные)
WebView 120+
45%
WebView 110-119
25%
WebView 100-109
15%
WebView 90-99
10%
WebView < 90
5%

Что это значит для тестирования:

  • Нельзя тестировать только на одной версии: Нужно проверять минимум 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.
Пример: Открытие Chrome Custom Tabs (Kotlin)
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 vs Chrome Custom Tabs
Критерий WebView Chrome Custom Tabs
Контроль над UI ✅ Полный ⚠️ Ограниченный
JS Bridge ✅ Поддерживается ❌ Не поддерживается
Cookies пользователя ❌ Изолированы ✅ Общие с Chrome
Скорость загрузки ⚠️ Средняя ✅ Быстрая (предзагрузка)
Поддержка фич ⚠️ Зависит от версии ✅ Все фичи Chrome
Работа без Chrome ✅ Работает ❌ Не работает
⚠️ Важно для QA

Если ваше приложение использует Chrome Custom Tabs, тестируйте:

  • Что происходит, если Chrome не установлен на устройстве.
  • Что происходит, если Chrome отключён в настройках.
  • Корректность возврата в приложение после закрытия Custom Tabs.
  • Сохранение состояния (если пользователь авторизовался через OAuth).

5 User-Agent Android WebView

User-Agent — это строка, которую WebView отправляет на сервер при каждом запросе. Сервер использует её для определения типа устройства, версии ОС и версии WebView.

Стандартный User-Agent Android WebView:

Пример User-Agent
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 (для разработчиков):

Изменение User-Agent в Android WebView
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

Для проверки User-Agent:

  1. Откройте в WebView страницу whatsmyua.info.
  2. Посмотрите, какой User-Agent отправляется.
  3. Сравните с User-Agent в обычном Chrome на том же устройстве.
  4. Проверьте, как сервер реагирует на разные 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:

  1. Проверьте версию WebView (может, это баг конкретной версии).
  2. Проверьте версию Android (может, это баг конкретной версии ОС).
  3. Проверьте производителя устройства (Samsung, Xiaomi могут иметь модифицированный WebView).
  4. Поищите баг на Chromium Bug Tracker — возможно, он уже известен.
💡 Чек-лист для тестирования Android WebView
  • ✅ Проверьте баг на минимум 3 разных версиях WebView.
  • ✅ Проверьте баг на разных производителях (Samsung, Xiaomi, Pixel).
  • ✅ Проверьте баг на разных версиях Android (если возможно).
  • ✅ Укажите в баг-репорте версию WebView и версию Android.
  • ✅ Приложите скриншоты и логи (Logcat).
  • ✅ Проверьте, воспроизводится ли баг в обычном Chrome на том же устройстве.