Белый экран вместо сайта после вызова loadUrl() — самый частый симптом, с которым сталкиваются при первом подключении WebView в Android Studio: в большинстве случаев причина в отсутствии разрешения INTERNET в манифесте или отключённом JavaScript. Компонент WebView позволяет отображать веб-страницы прямо внутри Android-приложения, не открывая внешний браузер, и построен на движке Chromium.
В этом руководстве разберём полный цикл работы с WebView: от добавления элемента в разметку до обработки ошибок загрузки и настройки взаимодействия между JavaScript и нативным кодом. Примеры приведены на Kotlin, но логика идентична для Java — отличается только синтаксис.
Добавление WebView в проект
Начните с разметки. Откройте файл activity_main.xml и добавьте элемент WebView, растянув его на весь экран или ограничив нужной областью:
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Далее обязательный шаг, который часто пропускают: объявите разрешение на доступ в интернет в файле AndroidManifest.xml внутри тега <manifest>, но за пределами <application>:
<uses-permission android:name="android.permission.INTERNET" />
Без этого разрешения вызов loadUrl() не выдаст исключение — страница просто не загрузится, и вы увидите ошибку net::ERR_CACHE_MISS или пустой экран. Это разрешение относится к «нормальным», поэтому запрашивать его у пользователя во время выполнения не требуется.
☑️ Минимальная настройка WebView
Базовая загрузка страницы
Минимальный код в MainActivity.kt выглядит так: получаем ссылку на компонент, включаем JavaScript и загружаем адрес.
val webView = findViewById<WebView>(R.id.webView)
webView.settings.javaScriptEnabled = true
webView.webViewClient = WebViewClient()
webView.loadUrl("https://example.com")
Обратите внимание на строку с WebViewClient. Без неё клики по ссылкам внутри страницы будут открываться во внешнем браузере устройства, а не в вашем приложении. Назначение клиента заставляет WebView обрабатывать навигацию самостоятельно.
Если нужно отобразить не удалённый сайт, а локальный HTML, поместите файл в папку app/src/main/assets и загрузите его по схеме file:///android_asset/page.html. Это удобно для офлайн-справки, лицензионных соглашений и экранов «О приложении».
Ключевые настройки WebSettings
Объект WebSettings управляет поведением движка. Вот параметры, которые чаще всего требуются на практике:
- 🔧
javaScriptEnabled— включает выполнение JavaScript; без него большинство современных сайтов работать не будет. - 📱
domStorageEnabled— разрешает DOM Storage (localStorage), необходим для многих веб-приложений и авторизации. - 🔍
setSupportZoom(true)иbuiltInZoomControls— включают масштабирование страницы жестами. - 🖼️
loadWithOverviewModeиuseWideViewPort— подгоняют страницу под ширину экрана, полезно для неадаптивных сайтов. - 💾
cacheMode— управляет кэшированием, напримерLOAD_CACHE_ELSE_NETWORKдля офлайн-режима.
Включайте только те функции, которые реально нужны. Каждый активированный механизм — это потенциальная поверхность для уязвимостей и лишний расход памяти.
⚠️ Внимание: включение JavaScript вместе с загрузкой стороннего или непроверенного контента создаёт риск XSS-атак. Никогда не включайте
javaScriptEnabledдля страниц, источнику которых вы не доверяете, и не передавайте в WebView URL из недоверенных данных без валидации.
Обработка навигации и ошибок
Чтобы контролировать переходы и реагировать на сбои, переопределите методы WebViewClient. Метод shouldOverrideUrlLoading() позволяет перехватывать ссылки: например, внутренние адреса открывать в WebView, а внешние — в браузере или другом экране приложения.
webView.webViewClient = object : WebViewClient() {
override fun onReceivedError(
view: WebView?,
request: WebResourceRequest?,
error: WebResourceError?
) {
// Показать экран ошибки или заглушку
}
}
Для отслеживания прогресса загрузки используется WebChromeClient с методом onProgressChanged() — его значения удобно привязать к ProgressBar. Также именно WebChromeClient обрабатывает диалоги JavaScript (alert, confirm) и запросы геолокации со страниц.
Типичные проблемы и их решения
Разберём ситуации, которые чаще всего встречаются при работе с WebView. Симптомы могут различаться в зависимости от версии Android и оболочки устройства, поэтому проверяйте поведение на нескольких аппаратах.
| Проблема | Вероятная причина | Решение |
|---|---|---|
| Пустой белый экран | Нет разрешения INTERNET или выключен JavaScript | Проверить манифест и javaScriptEnabled |
| Ошибка cleartext HTTP | Блокировка незашифрованного трафика на новых версиях Android | Использовать HTTPS или настроить networkSecurityConfig |
| Ссылки открываются в браузере | Не назначен WebViewClient | Установить webViewClient = WebViewClient() |
| Кнопка «Назад» закрывает приложение | Не переопределён onBackPressed | Проверять webView.canGoBack() и вызывать goBack() |
| Сайт не сохраняет авторизацию | Отключён DOM Storage | Включить domStorageEnabled |
Отдельно стоит сказать про HTTP-адреса. Начиная с Android 9 (API 28), открытый HTTP-трафик по умолчанию заблокирован, и попытка загрузить http://-страницу приведёт к ошибке net::ERR_CLEARTEXT_NOT_PERMITTED. Правильное решение — перейти на HTTPS. Если это невозможно, разрешение cleartext-трафика настраивается через файл network_security_config.xml, но делать это глобально для всего приложения небезопасно.
⚠️ Внимание: параметр
android:usesCleartextTraffic="true"в манифесте открывает HTTP для всего приложения сразу. Если без него не обойтись, ограничьте разрешение конкретными доменами через networkSecurityConfig, чтобы не ослаблять защиту остального трафика.
Взаимодействие JavaScript и Kotlin
Для гибридных приложений WebView поддерживает двусторонний мост. Из нативного кода в страницу данные передаются методом evaluateJavascript(), который выполняет JS-выражение и возвращает результат в колбэк.
Обратный канал организуется через addJavascriptInterface(): вы помечаете методы Kotlin-класса аннотацией @JavascriptInterface, и они становятся доступными из JavaScript под заданным именем. Это позволяет, например, вызывать нативные функции устройства по клику на веб-странице.
⚠️ Внимание: интерфейс
addJavascriptInterface()на устройствах со старыми версиями Android имеет известные уязвимости, позволяющие выполнить произвольный код. Используйте его только с доверенным контентом и ограничивайте загружаемые страницы белым списком доменов.
Как обработать кнопку «Назад» для WebView
Переопределите onBackPressed() в Activity: если webView.canGoBack() возвращает true, вызовите webView.goBack(), иначе выполните стандартное поведение через super.onBackPressed(). В новых версиях Android рекомендуется использовать OnBackPressedDispatcher с аналогичной логикой.
Производительность и память
WebView — ресурсоёмкий компонент. Страницы с тяжёлым JavaScript и медиа могут заметно нагружать устройство, особенно бюджетное. Несколько практических мер помогут снизить нагрузку:
- 🧹 Вызывайте
webView.destroy()вonDestroy()активности, предварительно удалив компонент из родительского контейнера, — это предотвращает утечки памяти. - ⏸️ Используйте
onPause()иonResume()у WebView при сворачивании экрана, чтобы остановить таймеры и воспроизведение. - 🚫 Не размещайте WebView внутри
ScrollView— это ломает прокрутку и вызывает проблемы с отрисовкой; для вложенной прокрутки применяйтеNestedScrollViewс осторожностью. - 🗜️ Включайте аппаратное ускорение для активности с WebView — на некоторых устройствах без него возможны артефакты отрисовки.
FAQ: частые вопросы о WebView
Почему WebView показывает ошибку ERR_CLEARTEXT_NOT_PERMITTED?
Начиная с Android 9, незашифрованный HTTP-трафик заблокирован по умолчанию. Переведите сайт на HTTPS или настройте исключение для конкретного домена через network_security_config.xml.
Чем WebView отличается от Chrome Custom Tabs?
WebView встраивается в вашу разметку и полностью контролируется приложением, но требует самостоятельной обработки навигации и безопасности. Custom Tabs открывает страницу в движке установленного браузера с готовым интерфейсом и общими cookie — это проще и безопаснее для простого показа веб-контента.
Как включить отладку WebView?
Вызовите WebView.setWebContentsDebuggingEnabled(true) в коде приложения (только для debug-сборок), затем подключите устройство к компьютеру и откройте chrome://inspect в Chrome — появится доступ к консоли и инспектору элементов страницы.
Почему не работает загрузка файлов через input type="file"?
Выбор файлов не обрабатывается автоматически. Нужно переопределить onShowFileChooser() в WebChromeClient, запустить системный выбор файла через ActivityResultLauncher и вернуть результат через ValueCallback.
Можно ли использовать WebView для авторизации в Google и других сервисах?
Некоторые сервисы блокируют вход через WebView из соображений безопасности. Для OAuth-авторизации рекомендуется использовать Custom Tabs или официальные SDK соответствующих сервисов — проверяйте требования конкретного провайдера.