How to Save Webview Content and Load Again in Android
You lot can provide spider web-based content—such as HTML, JavaScript, and CSS—for your app to use that you lot statically compile into the awarding rather than fetch over the internet.
In-app content doesn't require cyberspace access or consume a user's bandwidth, and if the content is designed specifically for WebView-merely—that is, information technology depends on communicating with a native app—then users can't accidentally load information technology in a web browser.
Still, there are some drawbacks to in-app content. Updating web-based content requires shipping a new app update, and at that place is the possibility of mismatched content betwixt what'due south on a spider web site and what'south in the app on your device if users accept outdated app versions.
WebViewAssetLoader
WebViewAssetLoader is a flexible and performant way to load in-app content in a WebView object. This class supports:
- 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 post-obit is an example of loading simple web content from the assets folder:
Kotlin
private course LocalContentWebViewClient(individual val assetLoader: WebViewAssetLoader) : WebViewClientCompat() { @RequiresApi(21) override fun shouldInterceptRequest( view: WebView, request: WebResourceRequest ): WebResourceResponse? { return assetLoader.shouldInterceptRequest(request.url) } // to back up API < 21 override fun shouldInterceptRequest( view: WebView, url: Cord ): WebResourceResponse? { return assetLoader.shouldInterceptRequest(Uri.parse(url)) } } Coffee
private static class LocalContentWebViewClient extends WebViewClientCompat { individual final WebViewAssetLoader mAssetLoader; LocalContentWebViewClient(WebViewAssetLoader assetLoader) { mAssetLoader = assetLoader; } @Override @RequiresApi(21) public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { return mAssetLoader.shouldInterceptRequest(asking.getUrl()); } @Override @SuppressWarnings("deprecation") // to support API < 21 public WebResourceResponse shouldInterceptRequest(WebView view, String url) { render mAssetLoader.shouldInterceptRequest(Uri.parse(url)); } } Your app should configure a WebViewAssetLoader instance to suit its needs. The adjacent 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 tin implement this interface to retrieve resources as needed by your app, the Webkit library bundles AssetsPathHandler and ResourcesPathHandler for loading Android avails and resources, respectively.
To get started, create some assets and resources for your app. Generally speaking:
- Text files similar HTML, JavaScript, and CSS vest in assets.
- Images and other binary files belong in resource.
To add together text-based web files to a project, do the following:
-
In Android Studio, right-click the app > src > main folder and so cull New > Directory.
Figure one. Create an assets folder for your projection. -
Name the folder "avails."
Effigy 2. Proper name the assets folder. -
Right-click the assets folder and and then click New > File. Enter
index.htmland press Return or Enter.
Figure 3. Create files with the name of the following code samples. -
Echo the previous step to create an empty file for
stylesheet.css. -
Fill in the empty files you created with the content in the next ii code samples.
index.html:
<html> <caput> <!-- Tip: Utilise 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/stylesheet.css"> </head> <body> <p>This file was loaded from in-app content</p> <p><img src="/res/drawable/android_robot.png" alt="Android robot" width="100"></p> </body> </html> stylesheet.css:
body { background-color: lightblue; } To add an image-based web file to your project, do the post-obit:
-
Download the
Android_symbol_green_RGB.pngfile to your local car. -
Rename the file to
android_robot.png. -
Manually move the file into your project's
main/res/drawabledirectory on your hard drive.
Effigy 4 shows the image y'all added and the text from the preceding lawmaking samples rendered in an app.
Figure 4. In-app HTML file and image file rendered in an app.
To complete the app, exercise the following:
-
Register the handlers and configure the
AssetLoaderby calculation the following code to theonCreate()method:Kotlin
val assetLoader = WebViewAssetLoader.Builder() .addPathHandler("/assets/", AssetsPathHandler(this)) .addPathHandler("/res/", ResourcesPathHandler(this)) .build() webView.webViewClient = LocalContentWebViewClient(assetLoader)Coffee
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Architect() .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this)) .addPathHandler("/res/", new WebViewAssetLoader.ResourcesPathHandler(this)) .build(); mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader)); -
Load the content past calculation the post-obit lawmaking to the
onCreate()method:Kotlin
webView.loadUrl("https://appassets.androidplatform.internet/assets/index.html")Java
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
Mix in-app content with resources from your website
Your app may need to load a mix of in-app content and content from the internet, such as an in-app HTML page styled past your website'due south CSS. WebViewAssetLoader supports this use case. If none of the registered PathHandlers can observe a resource for the given path, WebView falls back to loading content from the internet. If you're mixing in-app content with resource from your website, make certain to reserve directory paths, such as /assets/ or /resources/, for in-app resources. Avoid storing whatever resources from your website in those locations.
Kotlin
val assetLoader = WebViewAssetLoader.Builder() .setDomain("case.com") // replace this with your website'southward domain .addPathHandler("/assets/", AssetsPathHandler(this)) .build() webView.webViewClient = LocalContentWebViewClient(assetLoader) val inAppHtmlUrl = "https://case.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())" + ".and then(data => console.log(information));" webView.evaluateJavascript(jsCode, null) Coffee
last WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder() .setDomain("example.com") // supervene upon this with your website's domain .addPathHandler("/avails/", 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/information.json"; // JavaScript code to fetch() content from the aforementioned origin String jsCode = "fetch('" + websiteUrl + "')" + ".then(resp => resp.json())" + ".so(data => console.log(information));"; mWebView.evaluateJavascript(jsCode, zero); Run across the WebView demo on GitHub for an example of an in-app HTML page fetching spider web-hosted JSON information.
loadDataWithBaseURL
When your app only needs to load an HTML page and doesn't need to intercept subresources, consider using loadDataWithBaseURL(), which doesn't crave application assets. You can use it as shown in the following lawmaking sample:
Kotlin
val html = "<html><body><p>Hello world</p></torso></html>" val baseUrl = "https://example.com/" webView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl)
Java
String html = "<html><body><p>Hello world</p></torso></html>"; Cord baseUrl = "https://instance.com/"; mWebView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl);
Choose statement values carefully:
-
baseUrl: This is the URL your HTML content will be loaded as. This must be an HTTP(S) URL. -
data: This is the HTML content you desire to display, as a string. -
mimeType: This should normally exist set totext/html. -
encoding: This is unused whenbaseUrlis an HTTP(S) URL, so tin can be set togoose egg. -
historyUrl: This is set to the same value asbaseUrl.
We strongly recommend using an HTTP(Due south) URL as the baseUrl, as this ensures your app complies with the same-origin policy.
If you can't find a suitable baseUrl for your content and prefer to employ loadData(), y'all must encode the content with either percent-encoding or Base64 encoding. We strongly recommend choosing Base64 encoding and using Android APIs to encode this programmatically, as shown in the following code sample:
Kotlin
val encodedHtml: Cord = Base64.encodeToString(html.toByteArray(), Base64.NO_PADDING) webView.loadData(encodedHtml, mimeType, "base64")
Java
String encodedHtml = Base64.encodeToString(html.getBytes(), Base64.NO_PADDING); mWebView.loadData(encodedHtml, mimeType, "base64");
Antipatterns
There are several other ways to load in-app content, but we strongly recommend against them:
-
file://URLs anddata:URLs are considered to be opaque origins, pregnant that they can't accept reward of powerful spider web APIs such every bitfetch()orXMLHttpRequest.loadData()internally usesinformation:URLs, so we encourage usingWebViewAssetLoaderorloadDataWithBaseURL()instead. - Although
WebSettings.setAllowFileAccessFromFileURLs()andWebSettings.setAllowUniversalAccessFromFileURLs()can work around the issues withfile://URLs, we recommend confronting setting these totruebecause information technology leaves your app vulnerable to file-based exploits. We recommend explicitly setting these toimitationon all API levels for the strongest security. - For the same reasons, nosotros recommend confronting
file://android_assets/andfile://android_res/URLs. TheAssetsHandlerandResourcesHandlerclasses are meant to be drop-in replacements. - Avoid using
MIXED_CONTENT_ALWAYS_ALLOW. This setting generally is not necessary and weakens the security of your app. We recommend loading your in-app content over the aforementioned scheme (HTTP or HTTPS) equally your website'south resources and using eitherMIXED_CONTENT_COMPATIBILITY_MODEorMIXED_CONTENT_NEVER_ALLOW, every bit appropriate.
Source: https://developer.android.google.cn/guide/webapps/load-local-content
0 Response to "How to Save Webview Content and Load Again in Android"
Mag-post ng isang Komento