Используйте WebView
для отображения веб-приложения или веб-страницы в составе клиентского приложения. Класс WebView
— это расширение класса View
в Android, позволяющее отображать веб-страницы в рамках макета вашей активности. Он не включает в себя функции полноценного веб-браузера, такие как элементы управления навигацией или адресная строка. По умолчанию WebView
отображает только веб-страницу.
WebView
поможет вам предоставить в вашем приложении информацию, которую может потребоваться обновить, например, соглашение с конечным пользователем или руководство пользователя. В вашем приложении для Android вы можете создать Activity
, содержащую WebView
, а затем использовать его для отображения документа, размещённого в сети.
WebView
также может быть полезен, когда ваше приложение предоставляет пользователю данные, для извлечения которых требуется подключение к Интернету, например, электронная почта. В этом случае может оказаться проще создать WebView
в вашем приложении для Android, который отображает веб-страницу со всеми пользовательскими данными, чем выполнять сетевой запрос, а затем анализировать данные и отображать их в макете Android. Вместо этого вы можете разработать веб-страницу, адаптированную для устройств на базе Android, а затем реализовать WebView
в вашем приложении для Android, который будет загружать эту веб-страницу.
В этом документе описывается, как начать работу с WebView
, как связать JavaScript с вашей веб-страницы с клиентским кодом в вашем приложении Android, как осуществлять навигацию по страницам и как управлять окнами при использовании WebView
.
Работа с WebView на более ранних версиях Android
Чтобы безопасно использовать новейшие возможности WebView
на устройстве, на котором работает ваше приложение, добавьте библиотеку AndroidX Webkit . Это статическая библиотека, которую вы можете добавить в своё приложение для использования API android.webkit
, недоступных в более ранних версиях платформы.
Добавьте его в файл build.gradle
следующим образом:
Котлин
dependencies { implementation("androidx.webkit:webkit:1.8.0") }
Круто
dependencies { implementation ("androidx.webkit:webkit:1.8.0") }
Для получения более подробной информации изучите пример WebView
на GitHub.
Добавьте WebView в свое приложение
Чтобы добавить WebView
в свое приложение, вы можете включить элемент <WebView>
в макет активности или настроить все окно Activity
как WebView
в onCreate()
.
Добавьте WebView в макет активности
Чтобы добавить WebView
в макет вашего приложения, добавьте следующий код в XML-файл макета вашей активности:
<WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" />
Чтобы загрузить веб-страницу в WebView
, используйте loadUrl()
, как показано в следующем примере:
Котлин
val myWebView: WebView = findViewById(R.id.webview) myWebView.loadUrl("http://www.example.com")
Ява
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadUrl("http://www.example.com");
Добавьте WebView в onCreate()
Чтобы добавить WebView
в свое приложение в методе onCreate()
действия, используйте логику, подобную следующей:
Котлин
val myWebView = WebView(activityContext) setContentView(myWebView)
Ява
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
Затем загрузите страницу:
Котлин
myWebView.loadUrl("http://www.example.com")
Ява
myWebView.loadUrl("https://www.example.com");
Или загрузите URL из HTML-строки:
Котлин
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. val unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; val encodedHtml = Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING) myWebView.loadData(encodedHtml, "text/html", "base64")
Ява
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. String unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(), Base64.NO_PADDING); myWebView.loadData(encodedHtml, "text/html", "base64");
Ваше приложение должно иметь доступ к Интернету. Чтобы получить доступ к Интернету, запросите разрешение INTERNET
в файле манифеста, как показано в следующем примере:
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
Вы можете настроить свой WebView
, выполнив любое из следующих действий:
- Включение поддержки полноэкранного режима с помощью
WebChromeClient
. Этот класс также вызывается, когдаWebView
требуется разрешение на изменение пользовательского интерфейса хост-приложения, например, на создание или закрытие окон или отправку пользователю диалоговых окон JavaScript. Подробнее об отладке в этом контексте см. в статье «Отладка веб-приложений» . - Обработка событий, влияющих на отрисовку контента, таких как ошибки при отправке форм или навигации с помощью
WebViewClient
. Этот подкласс также можно использовать для перехвата загрузки URL. - Включение JavaScript путем изменения
WebSettings
. - Использование JavaScript для доступа к объектам фреймворка Android, внедренным в
WebView
.
Использовать JavaScript в WebView
Если веб-страница, которую вы хотите загрузить в WebView
, использует JavaScript, необходимо включить JavaScript для WebView
. После включения JavaScript вы сможете создавать интерфейсы между кодом вашего приложения и кодом JavaScript.
Включить JavaScript
JavaScript по умолчанию отключен в WebView
. Вы можете включить его через WebSettings
, прикреплённый к вашему WebView
. Получите WebSettings
с помощью getSettings()
, а затем включите JavaScript с помощью setJavaScriptEnabled()
.
См. следующий пример:
Котлин
val myWebView: WebView = findViewById(R.id.webview) myWebView.settings.javaScriptEnabled = true
Ява
WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true);
WebSettings
предоставляет доступ к множеству других настроек, которые могут оказаться вам полезными. Например, если вы разрабатываете веб-приложение, предназначенное специально для WebView
в вашем приложении для Android, вы можете определить собственную строку пользовательского агента с помощью setUserAgentString()
, а затем запросить пользовательского агента на вашей веб-странице, чтобы убедиться, что клиент, запрашивающий вашу веб-страницу, является вашим приложением для Android.
Привязать код JavaScript к коду Android
При разработке веб-приложения, специально предназначенного для WebView
в вашем Android-приложении, вы можете создать интерфейсы между кодом JavaScript и клиентским кодом Android. Например, ваш код JavaScript может вызвать метод в коде Android для отображения Dialog
вместо использования функции alert()
JavaScript.
Чтобы связать новый интерфейс между вашим JavaScript и кодом Android, вызовите addJavascriptInterface()
, передав ему экземпляр класса для привязки к вашему JavaScript и имя интерфейса, который ваш JavaScript может вызвать для доступа к классу.
Например, вы можете включить следующий класс в свое приложение для Android:
Котлин
/** Instantiate the interface and set the context. */ class WebAppInterface(private val mContext: Context) { /** Show a toast from the web page. */ @JavascriptInterface fun showToast(toast: String) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show() } }
Ява
public class WebAppInterface { Context mContext; /** Instantiate the interface and set the context. */ WebAppInterface(Context c) { mContext = c; } /** Show a toast from the web page. */ @JavascriptInterface public void showToast(String toast) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show(); } }
В этом примере класс WebAppInterface
позволяет веб-странице создавать Toast
-сообщение с помощью метода showToast()
.
Вы можете привязать этот класс к JavaScript, который выполняется в вашем WebView
, с помощью addJavascriptInterface()
, как показано в следующем примере:
Котлин
val webView: WebView = findViewById(R.id.webview) webView.addJavascriptInterface(WebAppInterface(this), "Android")
Ява
WebView webView = (WebView) findViewById(R.id.webview); webView.addJavascriptInterface(new WebAppInterface(this), "Android");
Это создаёт интерфейс Android
для JavaScript, работающий в WebView
. На этом этапе ваше веб-приложение получает доступ к классу WebAppInterface
. Например, вот код HTML и JavaScript, который создаёт всплывающее сообщение с использованием нового интерфейса при нажатии пользователем кнопки:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" /> <script type="text/javascript"> function showAndroidToast(toast) { Android.showToast(toast); } </script>
Инициализировать интерфейс Android
из JavaScript не нужно. WebView
автоматически делает его доступным на вашей веб-странице. Поэтому, когда пользователь нажимает кнопку, функция showAndroidToast()
использует интерфейс Android
для вызова метода WebAppInterface.showToast()
.
Управление навигацией по страницам
Когда пользователь нажимает на ссылку на веб-странице в вашем WebView
, Android по умолчанию запускает приложение, обрабатывающее URL-адреса. Обычно открывается веб-браузер по умолчанию и загружает целевой URL-адрес. Однако вы можете переопределить это поведение для вашего WebView
, чтобы ссылки открывались в WebView
. После этого вы можете разрешить пользователю перемещаться вперёд и назад по истории веб-страниц, хранящейся в вашем WebView
.
Чтобы открывать ссылки, на которые нажимает пользователь, предоставьте WebViewClient
для вашего WebView
с помощью setWebViewClient()
. Все ссылки, на которые нажимает пользователь, загружаются в ваш WebView
. Если вам нужен больший контроль над тем, где загружается нажатая ссылка, создайте собственный WebViewClient
, который переопределяет метод shouldOverrideUrlLoading()
. В следующем примере предполагается, что MyWebViewClient
— это внутренний класс Activity
.
Котлин
private class MyWebViewClient : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { if (Uri.parse(url).host == "www.example.com") { // This is your website, so don't override. Let your WebView load // the page. return false } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply { startActivity(this) } return true } }
Ява
private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { if ("www.example.com".equals(request.getUrl().getHost())) { // This is your website, so don't override. Let your WebView load the // page. return false; } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl()); startActivity(intent); return true; } }
Затем создайте экземпляр этого нового WebViewClient
для WebView
:
Котлин
val myWebView: WebView = findViewById(R.id.webview) myWebView.webViewClient = MyWebViewClient()
Ява
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new MyWebViewClient());
Теперь, когда пользователь нажимает на ссылку, система вызывает метод shouldOverrideUrlLoading()
, который проверяет, соответствует ли хост URL-адреса определённому домену, как определено в предыдущем примере. Если соответствует, метод возвращает false и не переопределяет загрузку URL-адреса. Он позволяет WebView
загрузить URL-адрес как обычно. Если хост-адрес URL-адреса не совпадает, создаётся Intent
для запуска Activity
по умолчанию для обработки URL-адресов, который преобразуется в веб-браузер пользователя по умолчанию.
Обработка пользовательских URL-адресов
WebView
применяет ограничения при запросе ресурсов и разрешении ссылок, использующих пользовательскую схему URL. Например, если вы реализуете обратные вызовы, такие как shouldOverrideUrlLoading()
или shouldInterceptRequest()
, то WebView
будет вызывать их только для допустимых URL.
Например, WebView
может не вызывать ваш метод shouldOverrideUrlLoading()
для таких ссылок:
<a href="showProfile">Show Profile</a>
Недействительные URL-адреса, подобные показанному в предыдущем примере, обрабатываются в WebView
некорректно, поэтому мы рекомендуем использовать корректный URL. Вы можете использовать пользовательскую схему или HTTPS-URL для домена, контролируемого вашей организацией.
Вместо использования простой строки в ссылке, как в предыдущем примере, вы можете использовать пользовательскую схему, например следующую:
<a href="example-app:showProfile">Show Profile</a>
Затем вы можете обработать этот URL в методе shouldOverrideUrlLoading()
следующим образом:
Котлин
// The URL scheme must be non-hierarchical, meaning no trailing slashes. const val APP_SCHEME = "example-app:" override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { return if (url?.startsWith(APP_SCHEME) == true) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8") respondToData(urlData) true } else { false } }
Ява
// The URL scheme must be non-hierarchical, meaning no trailing slashes. private static final String APP_SCHEME = "example-app:"; @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith(APP_SCHEME)) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8"); respondToData(urlData); return true; } return false; }
API shouldOverrideUrlLoading()
в первую очередь предназначен для запуска намерений для определённых URL-адресов. При его реализации обязательно возвращайте false
для URL-адресов, обрабатываемых WebView
. Однако вы не ограничены только запуском намерений. Вы можете заменить запуск намерений любым другим пользовательским поведением из предыдущих примеров кода.
Навигация по истории веб-страницы
Когда ваш WebView
переопределяет загрузку URL, он автоматически накапливает историю посещённых веб-страниц. Вы можете перемещаться по истории вперёд и назад с помощью goBack()
и goForward()
.
Например, ниже показано, как ваша Activity
может использовать кнопку «Назад» устройства для перехода назад:
Котлин
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { // Check whether the key event is the Back button and if there's history. if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) { myWebView.goBack() return true } // If it isn't the Back button or there isn't web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event) }
Ява
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Check whether the key event is the Back button and if there's history. if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) { myWebView.goBack(); return true; } // If it isn't the Back button or there's no web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event); }
Если ваше приложение использует AndroidX AppCompat
1.6.0+, вы можете упростить предыдущий фрагмент еще больше:
Котлин
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack() } }
Ява
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack(); } }
Метод canGoBack()
возвращает true, если есть история посещений веб-страниц пользователем. Аналогично, метод canGoForward()
можно использовать для проверки наличия истории пересылок. Если эта проверка не выполняется, то после того, как пользователь достигнет конца истории, goBack()
и goForward()
не будут выполнять никаких действий.
Обработка изменений конфигурации устройства
Во время выполнения состояние активности изменяется при изменении конфигурации устройства, например, когда пользователь поворачивает устройство или закрывает редактор методов ввода (IME). Эти изменения приводят к уничтожению активности объекта WebView
и созданию новой активности, которая также создаёт новый объект WebView
, загружающий URL уничтоженного объекта. Чтобы изменить поведение активности по умолчанию, можно изменить способ обработки изменений orientation
в манифесте. Подробнее об обработке изменений конфигурации во время выполнения см. в статье Обработка изменений конфигурации .
Управление окнами
По умолчанию запросы на открытие новых окон игнорируются. Это справедливо как для JavaScript, так и для атрибута target в ссылке. Вы можете настроить WebChromeClient
, чтобы задать собственное поведение при открытии нескольких окон.
Чтобы повысить безопасность приложения, рекомендуется запретить открытие всплывающих окон и новых окон. Самый безопасный способ реализовать это поведение — передать значение "true"
в setSupportMultipleWindows()
, но не переопределять метод onCreateWindow()
, от которого зависит setSupportMultipleWindows()
. Эта логика предотвращает загрузку любой страницы, ссылки на которую содержат target="_blank"
.