Используйте WebView, чтобы показывать веб-приложение или веб-страницу в клиентском приложении. Класс WebView – это расширение класса View в Android, которое позволяет показывать веб-страницы в макете действия. В нем нет функций полноценного браузера, таких как элементы управления навигацией или адресная строка. По умолчанию WebView просто показывает веб-страницу.
WebView позволяет размещать в приложении информацию, которую может потребоваться обновить, например пользовательское соглашение или руководство пользователя. В приложении для Android можно создать объект Activity, содержащий WebView, и использовать его для показа документа, размещенного в интернете.
WebView также может помочь, если ваше приложение предоставляет пользователю данные, для получения которых требуется подключение к интернету, например электронную почту. В этом случае вам может быть проще создать в приложении Android объект WebView, который будет показывать веб-страницу со всеми пользовательскими данными, а не выполнять сетевой запрос, а затем анализировать данные и отображать их в макете Android. Вместо этого вы можете создать веб-страницу, адаптированную для устройств Android, а затем реализовать в своем приложении Android WebView, который загружает эту веб-страницу.
В этом документе рассказывается, как начать работу с WebView, как связать JavaScript на веб-странице с клиентским кодом в приложении Android, как обрабатывать навигацию по страницам и как управлять окнами при использовании WebView.
Как работать с WebView в более ранних версиях Android
Чтобы безопасно использовать более новые возможности WebView на устройстве, на котором запущено ваше приложение, добавьте библиотеку Jetpack Webkit. Это статическая библиотека, которую можно добавить в приложение, чтобы использовать API android.webkit, недоступные в более ранних версиях платформы.
Добавьте его в файл build.gradle следующим образом:
Kotlin
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, как показано в примере ниже.
Kotlin
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(), используйте логику, аналогичную следующей:
Kotlin
val myWebView = WebView(activityContext) setContentView(myWebView)
Java
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
Затем загрузите страницу:
Kotlin
myWebView.loadUrl("http://www.example.com")
Java
myWebView.loadUrl("https://www.example.com");
Или загрузите URL из строки HTML:
Kotlin
// 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
По умолчанию JavaScript в WebView отключен. Вы можете включить его в WebSettings, связанном с вашим WebView. Получите WebSettings с помощью getSettings, а затем включите JavaScript с помощью setJavaScriptEnabled.
Вот пример:
Kotlin
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, вы можете определить специальную строку агента пользователя с помощью setUserAgentString, а затем запросить специальный агент пользователя на своей веб-странице, чтобы убедиться, что клиент, запрашивающий вашу веб-страницу, является вашим приложением Android.
Как связать код JavaScript с кодом Android
При разработке веб-приложения, предназначенного специально для WebView в приложении Android, вы можете создать интерфейсы между кодом JavaScript и клиентским кодом Android. Например, код JavaScript может вызывать метод в коде Android для отображения Dialog вместо использования функции alert() в JavaScript.
Чтобы связать новый интерфейс между кодом JavaScript и Android, вызовите addJavascriptInterface, передав ему экземпляр класса для привязки к JavaScript и имя интерфейса, которое JavaScript может вызвать для доступа к классу.
Чтобы узнать больше о взаимодействии между JavaScript и нативным кодом, в том числе о более современных и безопасных API, прочитайте статью Доступ к нативным API с помощью JSBridge.
Например, в приложение для Android можно добавить следующий класс:
Kotlin
/** 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(), как показано в примере ниже.
Kotlin
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.
Kotlin
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:
Kotlin
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 следующим образом:
Kotlin
// 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. При его реализации убедитесь, что для URL, которые обрабатывает WebView, возвращается значение false. Однако вы не ограничены запуском намерений. В примерах кода выше вы можете заменить запуск объектов intent на любое другое действие.
Как перемещаться по истории веб-страниц
Когда WebView переопределяет загрузку URL, он автоматически накапливает историю посещенных веб-страниц. Для перемещения по истории назад и вперед используйте сочетания клавиш goBack и goForward.
Например, в следующем примере показано, как Activity может использовать кнопку "Назад" на устройстве для перехода назад:
Kotlin
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 или более поздней версии, вы можете упростить предыдущий фрагмент кода:
Kotlin
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".
Как управлять памятью и производительностью
Поскольку WebView работает на движке Chromium с отдельными процессами и нативным кодом, базовое использование памяти выше, чем у стандартных представлений Android.
Чтобы приложение работало стабильно, важно повторно использовать экземпляры WebView и правильно их удалять.
Подробнее о том, как диагностировать и оптимизировать объем потребляемой памяти при использовании веб-контента…