Use WebView
to deliver a web application
or a web page as a part of a client application. The WebView
class is an
extension of Android's View
class that lets
you display web pages as a part of your activity layout. It doesn't include the
features of a fully developed web browser, such as navigation controls or an
address bar. All WebView
does, by default, is show a web page.
WebView
can help you provide information in your app that you might need to
update, such as an end-user agreement or a user guide. Within your Android app,
you can create an Activity
that contains a
WebView
, then use it to display your document that's hosted online.
WebView
can also help when your app provides data to the user that requires an
internet connection to retrieve data, such as email. In this case, you might
find that it's easier to build a WebView
in your Android app that shows a web
page with all the user data, rather than performing a network request, then
parsing the data and rendering it in an Android layout. Instead, you can design
a web page that's tailored for Android-powered devices and then implement a
WebView
in your Android app that loads the web page.
This document describes how to get started with WebView
, how to bind
JavaScript from your web page to client-side code in your Android app, how to
handle page navigation, and how to manage windows when using WebView
.
Work with WebView on earlier versions of Android
To safely use more-recent WebView
capabilities on the device your app is
running on, add the AndroidX
Webkit library. This is a static
library you can add to your application to use android.webkit
APIs that aren't
available for earlier platform versions.
Add it to your build.gradle
file as follows:
Kotlin
dependencies { implementation("androidx.webkit:webkit:1.8.0") }
Groovy
dependencies { implementation ("androidx.webkit:webkit:1.8.0") }
Explore the WebView
example
on GitHub for more details.
Add a WebView to your app
To add a WebView
to your app, you can include the <WebView>
element in your
activity layout or set the entire Activity
window as a WebView
in
onCreate()
.
Add a WebView in the activity layout
To add a WebView
to your app in the layout, add the following code to your
activity's layout XML file:
<WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" />
To load a web page in the WebView
, use
loadUrl()
, as
shown in the following example:
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");
Add a WebView in onCreate()
To add a WebView
to your app in an activity's onCreate()
method instead, use
logic similar to the following:
Kotlin
val myWebView = WebView(activityContext) setContentView(myWebView)
Java
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
Then load the page:
Kotlin
myWebView.loadUrl("http://www.example.com")
Java
myWebView.loadUrl("https://www.example.com");
Or load the URL from an HTML string:
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");
Your app must have access to the internet. To get internet access, request the
INTERNET
permission in your
manifest file, as shown in the following example:
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
You can customize your WebView
by doing any of the following:
- Enabling fullscreen support using
WebChromeClient
. This class is also called when aWebView
needs permission to alter the host app's UI, such as creating or closing windows or sending JavaScript dialogs to the user. To learn more about debugging in this context, read Debug web apps. - Handling events that impact content rendering, such as errors on form
submissions or navigation using
WebViewClient
. You can also use this subclass to intercept URL loading. - Enabling JavaScript by modifying
WebSettings
. - Using JavaScript to access Android framework objects that you have injected
into a
WebView
.
Use JavaScript in WebView
If the web page you want to load in your WebView
uses JavaScript, you must
enable JavaScript for your WebView
. After you enable JavaScript, you can
create interfaces between your app code and your JavaScript code.
Enable JavaScript
JavaScript is disabled in a WebView
by default. You can enable it through the
WebSettings
attached to your WebView
. Retrieve WebSettings
with
getSettings()
, then enable
JavaScript with
setJavaScriptEnabled()
.
See the following example:
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
provides access to a variety of other settings that you might find
useful. For example, if you're developing a web application that's designed
specifically for the WebView
in your Android app, then you can define a custom
user agent string with
setUserAgentString()
,
then query the custom user agent in your web page to verify that the client
requesting your web page is your Android app.
Bind JavaScript code to Android code
When developing a web application that's designed specifically for the WebView
in your Android app, you can create interfaces between your JavaScript code and
client-side Android code. For example, your JavaScript code can call a method in
your Android code to display a Dialog
,
instead of using JavaScript's alert()
function.
To bind a new interface between your JavaScript and Android code, call
addJavascriptInterface()
,
passing it a class instance to bind to your JavaScript and an interface name
that your JavaScript can call to access the class.
For example, you can include the following class in your Android app:
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(); } }
In this example, the WebAppInterface
class lets the web page create a
Toast
message, using the showToast()
method.
You can bind this class to the JavaScript that runs in your WebView
with
addJavascriptInterface()
, as shown in the following example:
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");
This creates an interface called Android
for JavaScript running in the
WebView
. At this point, your web application has access to the
WebAppInterface
class. For example, here's some HTML and JavaScript that
creates a toast message using the new interface when the user taps a button:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" /> <script type="text/javascript"> function showAndroidToast(toast) { Android.showToast(toast); } </script>
There's no need to initialize the Android
interface from JavaScript. The
WebView
automatically makes it available to your web page. So, when a user
taps the button, the showAndroidToast()
function uses the Android
interface
to call the WebAppInterface.showToast()
method.
Handle page navigation
When the user taps a link from a web page in your WebView
, by default, Android
launches an app that handles URLs. Usually, the default web browser opens and
loads the destination URL. However, you can override this behavior for your
WebView
so links open within your WebView
. You can then let the user
navigate backward and forward through their web page history that's maintained
by your WebView
.
To open links tapped by the user, provide a WebViewClient
for your WebView
using
setWebViewClient()
.
All links the user taps load in your WebView
. If you want more control over
where a clicked link loads, create your own WebViewClient
that overrides the
shouldOverrideUrlLoading()
method. The following example assumes that MyWebViewClient
is an inner class
of 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; } }
Then create an instance of this new WebViewClient
for the WebView
:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.webViewClient = MyWebViewClient()
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new MyWebViewClient());
Now when the user taps a link, the system calls the
shouldOverrideUrlLoading()
method, which checks whether the URL host matches
a specific domain, as defined in the preceding example. If it does match, then
the method returns false and doesn't override the URL loading. It lets the
WebView
load the URL as usual. If the URL host doesn't match, then an
Intent
is created to launch the default
Activity
for handling URLs, which resolves to the user's default web browser.
Handle custom URLs
WebView
applies restrictions when requesting resources and resolving links
that use a custom URL scheme. For example, if you implement callbacks such as
shouldOverrideUrlLoading()
or
shouldInterceptRequest()
,
then WebView
invokes them only for valid URLs.
For example, WebView
might not call your shouldOverrideUrlLoading()
method
for links like this:
<a href="showProfile">Show Profile</a>
Invalid URLs, like the one shown in the preceding example, are handled
inconsistently in WebView
, so we recommend using a well-formed URL instead.
You can use a custom scheme or an HTTPS URL for a domain that your organization
controls.
Instead of using a simple string in a link, as in the previous example, you can use a custom scheme such as the following:
<a href="example-app:showProfile">Show Profile</a>
You can then handle this URL in your shouldOverrideUrlLoading()
method like
this:
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; }
The shouldOverrideUrlLoading()
API is primarily intended for launching intents
for specific URLs. When implementing it, make sure to return false
for URLs
the WebView
handles. You aren't limited to launching intents, though. You can
replace launching intents with any custom behavior in the preceding code
samples.
Navigate web page history
When your WebView
overrides URL loading, it automatically accumulates a
history of visited web pages. You can navigate backward and forward through the
history with goBack()
and
goForward()
.
For example, the following shows how your Activity
can use the device Back
button to navigate backward:
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); }
If you app uses AndroidX AppCompat
1.6.0+, you can simplify the previous
snippet even more:
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(); } }
The canGoBack()
method
returns true if there is web page history for the user to visit. Likewise, you
can use canGoForward()
to
check whether there is a forward history. If you don't perform this check, then
after the user reaches the end of the history, goBack()
and goForward()
do
nothing.
Handle device configuration changes
During runtime, activity state changes occur when a device's configuration
changes, such as when users rotate the device or dismiss an input method editor
(IME). These changes cause a WebView
object's activity to be destroyed and a
new activity to be created, which also creates a new WebView
object that loads
the destroyed object's URL. To modify your activity's default behavior, you can
change how it handles orientation
changes in your manifest. To learn more
about handling configuration changes during runtime, read Handle configuration
changes.
Manage windows
By default, requests to open new windows are ignored. This is true whether they
are opened by JavaScript or by the target attribute in a link. You can customize
your WebChromeClient
to provide your own behavior for opening multiple
windows.
To keep your app more secure, it's best to prevent popups and new windows from
opening. The safest way to implement this behavior is to pass "true"
into
setSupportMultipleWindows()
but not override the
onCreateWindow()
method, which setSupportMultipleWindows()
depends on. This logic prevents any
page that uses target="_blank"
in its links from loading.