Используйте 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"
в своих ссылках.