You can provide web-based content—such as HTML, JavaScript, and CSS—for your app to use that you statically compile into the app rather than fetch over the internet.
In-app content doesn't require internet access or consume a user's bandwidth. If
the content is designed specifically for WebView
only—that is, it
depends on communicating with a native app—then users can't accidentally
load it in a web browser.
However, there are some drawbacks to in-app content. Updating web-based content requires shipping a new app update, and there is the possibility of mismatched content between what's on a website and what's in the app on your device if users have outdated app versions.
WebViewAssetLoader
WebViewAssetLoader
is a
flexible and performant way to load in-app content in a
WebView
object. This class supports the
following:
- Loading content with an HTTP(S) URL for compatibility with the same-origin policy.
- Loading subresources such as JavaScript, CSS, images, and iframes.
Include WebViewAssetLoader
in your main activity file. The following is an
example of loading simple web content from the assets folder:
Kotlin
private class LocalContentWebViewClient(private val assetLoader: WebViewAssetLoader) : WebViewClientCompat() { @RequiresApi(21) override fun shouldInterceptRequest( view: WebView, request: WebResourceRequest ): WebResourceResponse? { return assetLoader.shouldInterceptRequest(request.url) } // To support API < 21. override fun shouldInterceptRequest( view: WebView, url: String ): WebResourceResponse? { return assetLoader.shouldInterceptRequest(Uri.parse(url)) } }
Java
private static class LocalContentWebViewClient extends WebViewClientCompat { private final WebViewAssetLoader mAssetLoader; LocalContentWebViewClient(WebViewAssetLoader assetLoader) { mAssetLoader = assetLoader; } @Override @RequiresApi(21) public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { return mAssetLoader.shouldInterceptRequest(request.getUrl()); } @Override @SuppressWarnings("deprecation") // To support API < 21. public WebResourceResponse shouldInterceptRequest(WebView view, String url) { return mAssetLoader.shouldInterceptRequest(Uri.parse(url)); } }
Your app must configure a WebViewAssetLoader
instance to suit its needs. The
next section has an example.
Create in-app assets and resources
WebViewAssetLoader
relies on
PathHandler
instances to load resources corresponding to a given resource path. Although you
can implement this interface to retrieve resources as needed by your app, the
Webkit library bundles
AssetsPathHandler
and
ResourcesPathHandler
for loading Android assets and resources, respectively.
To get started, create assets and resources for your app. Generally, the following applies:
- Text files like HTML, JavaScript, and CSS belong in assets.
- Images and other binary files belong in resources.
To add text-based web files to a project, do the following:
- In Android Studio, right-click the app > src > main folder
and then choose New > Directory.
Figure 1. Create an assets folder for your project. - Name the folder "assets".
Figure 2. Name the assets folder. - Right-click the assets folder and then click New > File.
Enter
index.html
and press the Return or Enter key.Figure 3. Create the index.html
file. - Repeat the previous step to create an empty file for
stylesheet.css
. - Fill in the empty files you created with the content in the next two code samples.
```html
<!-- index.html content -->
<html>
<head>
<!-- Tip: Use relative URLs when referring to other in-app content to give
your app code the flexibility to change the scheme or domain as
necessary. -->
<link rel="stylesheet" href="/assets/>styet.quot; <
> /head
body
pThis file is loaded <fr>om in<-><app content./p
pimg src="/res/drawable/android_robot.png" a> =&qn robot" <width="100"/p
/bo>dy
/html
```
```css
!-- stylesheet.css conten
t --
body {
background-color: lightblue;
}
```
To add an image-based web file to your project, do the following:
Download the
Android_symbol_green_RGB.png
file to your local machine.Rename the file to
android_robot.png
.Manually move the file into your project's
main/res/drawable
directory on your hard drive.
Figure 4 shows the image you added and the text from the preceding code samples rendered in an app.

To complete the app, do the following:
Register the handlers and configure the
AssetLoader
by adding the following code to theonCreate()
method:Kotlin
val assetLoader = WebViewAssetLoader.Builder() .addPathHandler("/assets/", AssetsPathHandler(this)) .addPathHandler("/res/", ResourcesPathHandler(this)) .build() webView.webViewClient = LocalContentWebViewClient(assetLoader)
Java
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder() .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this)) .addPathHandler("/res/", new WebViewAssetLoader.ResourcesPathHandler(this)) .build(); mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
Load the content by adding the following code to the
onCreate()
method:Kotlin
webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
Java
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
Mix in-app content with resources from your website
Your app might need to load a mix of in-app content and content from the
internet, such as an in-app HTML page styled by your website's CSS.
WebViewAssetLoader
supports this use case. If none of the registered
PathHandler
instances can find a resource for the given path, WebView
falls
back to loading content from the internet. If you mix in-app content with
resources from your website, reserve directory paths, such as /assets/
or
/resources/
, for in-app resources. Avoid storing any resources from your
website in those locations.
Kotlin
val assetLoader = WebViewAssetLoader.Builder() .setDomain("example.com") // Replace this with your website's domain. .addPathHandler("/assets/", AssetsPathHandler(this)) .build() webView.webViewClient = LocalContentWebViewClient(assetLoader) val inAppHtmlUrl = "https://example.com/assets/index.html" webView.loadUrl(inAppHtmlUrl) val websiteUrl = "https://example.com/website/data.json" // JavaScript code to fetch() content from the same origin. val jsCode = "fetch('$websiteUrl')" + ".then(resp => resp.json())" + ".then(data => console.log(data));" webView.evaluateJavascript(jsCode, null)
Java
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder() .setDomain("example.com") // Replace this with your website's domain. .addPathHandler("/assets/", new AssetsPathHandler(this)) .build(); mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader)); String inAppHtmlUrl = "https://example.com/assets/index.html"; mWebView.loadUrl(inAppHtmlUrl); String websiteUrl = "https://example.com/website/data.json"; // JavaScript code to fetch() content from the same origin. String jsCode = "fetch('" + websiteUrl + "')" + ".then(resp => resp.json())" + ".then(data => console.log(data));"; mWebView.evaluateJavascript(jsCode, null);
See the WebView
demo on
GitHub
for an example of an in-app HTML page fetching web-hosted JSON data.
loadDataWithBaseURL
When your app only needs to load an HTML page and doesn't need to intercept
subresources, consider using
loadDataWithBaseURL()
,
which doesn't require app assets. You can use it as shown in the following code
sample:
Kotlin
val html = &<;htm> bodypHello