Используйте WebView для отображения веб-приложения или веб-страницы в составе клиентского приложения. Класс WebView является расширением класса View из Android и позволяет отображать веб-страницы в составе макета вашей активности. Он не включает в себя функции полноценного веб-браузера, такие как элементы управления навигацией или адресная строка. По умолчанию WebView просто отображает веб-страницу.
WebView может помочь вам добавить в приложение информацию, которую, возможно, потребуется обновить, например, пользовательское соглашение или руководство пользователя. В вашем Android-приложении вы можете создать Activity , содержащую WebView , а затем использовать её для отображения документа, размещенного в интернете.
WebView также может помочь, когда ваше приложение предоставляет пользователю данные, для получения которых требуется подключение к интернету, например, электронная почта. В этом случае вам может показаться проще создать WebView в вашем Android-приложении, который отображает веб-страницу со всеми данными пользователя, чем выполнять сетевой запрос, затем анализировать данные и отображать их в макете Android. Вместо этого вы можете разработать веб-страницу, адаптированную для устройств на базе Android, а затем реализовать WebView в вашем Android-приложении, который будет загружать эту веб-страницу.
В этом документе описывается, как начать работу с WebView , как привязать JavaScript с вашей веб-страницы к клиентскому коду в вашем Android-приложении, как обрабатывать навигацию по страницам и как управлять окнами при использовании WebView .
Работа с WebView на более ранних версиях Android
Для безопасного использования более новых возможностей WebView на устройстве, на котором работает ваше приложение, добавьте библиотеку Jetpack 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")
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadUrl("http://www.example.com");
Добавьте WebView в метод onCreate().
Чтобы добавить WebView в ваше приложение в методе onCreate() активности, используйте логику, аналогичную следующей:
Котлин
val myWebView = WebView(activityContext) setContentView(myWebView)
Java
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
Затем загрузите страницу:
Котлин
myWebView.loadUrl("http://www.example.com")
Java
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")
Java
// 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
В WebView по умолчанию JavaScript отключен. Вы можете включить его через WebSettings прикрепленные к вашему WebView . Получите WebSettings с помощью getSettings() , а затем включите JavaScript с помощью setJavaScriptEnabled() .
См. следующий пример:
Котлин
val myWebView: WebView = findViewById(R.id.webview) myWebView.settings.javaScriptEnabled = true
Java
WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true);
WebSettings предоставляет доступ к множеству других настроек, которые могут оказаться полезными. Например, если вы разрабатываете веб-приложение, специально предназначенное для WebView в вашем Android-приложении, вы можете определить пользовательскую строку User Agent с помощью setUserAgentString() , а затем запросить этот пользовательский агент на вашей веб-странице, чтобы убедиться, что клиент, запрашивающий вашу веб-страницу, является вашим Android-приложением.
Привязка кода JavaScript к коду Android
При разработке веб-приложения, специально предназначенного для использования WebView в вашем Android-приложении, вы можете создавать интерфейсы между вашим JavaScript-кодом и клиентским Android-кодом. Например, ваш JavaScript-код может вызывать метод в вашем Android-коде для отображения Dialog , вместо использования функции alert() в JavaScript.
Чтобы связать новый интерфейс между вашим JavaScript-кодом и кодом Android, вызовите addJavascriptInterface() , передав ему экземпляр класса для привязки к вашему JavaScript-коду и имя интерфейса, к которому ваш JavaScript сможет обращаться для доступа к классу.
Чтобы узнать больше о взаимодействии между JavaScript и нативным кодом, включая более современные и безопасные API, см. раздел «Доступ к нативным API с помощью JSBridge» .
Например, вы можете включить следующий класс в свое 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() } }
Java
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")
Java
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 } }
Java
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()
Java
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-адрес. Вы можете использовать пользовательскую схему или URL-адрес HTTPS для домена, контролируемого вашей организацией.
Вместо использования простой строки в ссылке, как в предыдущем примере, вы можете использовать пользовательскую схему, например, следующую:
<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 } }
Java
// 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-адресов. При его реализации убедитесь, что для обрабатываемых WebView URL-адресов возвращается false . Однако вы не ограничены запуском интентов. Вы можете заменить запуск интентов любым пользовательским поведением, описанным в приведенных выше примерах кода.
Перейти к истории веб-страниц
Когда ваш 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) }
Java
@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); }
Если ваше приложение использует Jetpack AppCompat 1.6.0+, вы можете еще больше упростить предыдущий фрагмент кода:
Котлин
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack() } }
Java
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack(); } }
Метод canGoBack() возвращает true, если у пользователя есть история посещений веб-страниц. Аналогично, вы можете использовать canGoForward() для проверки наличия истории перемотки вперед. Если вы не выполняете эту проверку, то после того, как пользователь достигнет конца истории, goBack() и goForward() ничего не делают.
Чтобы сохранить историю навигации при повторном создании активности или освобождении ресурсов фонового процесса, используйте saveState() для сериализации истории навигации WebView в Bundle и restoreState() для ее восстановления. Рекомендации по безопасному управлению ограничениями размера сохраненного состояния и предотвращению TransactionTooLargeException см. в разделе «Эффективное управление состоянием WebView» .
Обработка изменений конфигурации устройства
Во время выполнения программы изменения состояния активности происходят при изменении конфигурации устройства, например, когда пользователь поворачивает устройство или закрывает редактор методов ввода (IME). Эти изменения приводят к уничтожению активности объекта WebView и созданию новой активности, которая также создает новый объект WebView , загружающий URL-адрес уничтоженного объекта. Вы можете использовать saveState() внутри onSaveInstanceState() и restoreState() при повторном создании объекта, чтобы восстановить контекст навигации пользователя. Для безопасного управления размером состояния см. раздел «Эффективное управление состоянием WebView» .
Чтобы изменить поведение вашего действия по умолчанию, вы можете изменить способ обработки изменений orientation в вашем манифесте. Подробнее об обработке изменений конфигурации во время выполнения см. в разделе «Обработка изменений конфигурации» .
Управление окнами
По умолчанию запросы на открытие новых окон игнорируются. Это справедливо как для окон, открываемых с помощью JavaScript, так и для окон, открываемых атрибутом target в ссылке. Вы можете настроить WebChromeClient , чтобы задать собственное поведение при открытии нескольких окон одновременно.
Для повышения безопасности вашего приложения лучше всего предотвратить открытие всплывающих окон и новых окон. Самый безопасный способ реализовать это поведение — передать значение "true" в метод setSupportMultipleWindows() , но не переопределять метод onCreateWindow() , от которого зависит setSupportMultipleWindows() . Эта логика предотвращает загрузку любой страницы, в ссылках которой используется target="_blank" .