Load HTML file into WebView - android

I have a local html page along with several other resources pointed by it (css files and Javascript libraries) that I would like to load into a WebView . How could this be achieved ?
Perhaps not the best way to procede but I'm still experimenting.

The easiest way would probably be to put your web resources into the assets folder then call:
webView.loadUrl("file:///android_asset/filename.html");
For Complete Communication between Java and Webview See This
Update: The assets folder is usually the following folder:
<project>/src/main/assets
This can be changed in the asset folder configuration setting in your <app>.iml file as:
<option name=”ASSETS_FOLDER_RELATIVE_PATH” value=”/src/main/assets” />
See Article Where to place the assets folder in Android Studio

probably this sample could help:
WebView lWebView = (WebView)findViewById(R.id.webView);
File lFile = new File(Environment.getExternalStorageDirectory() + "<FOLDER_PATH_TO_FILE>/<FILE_NAME>");
lWebView.loadUrl("file:///" + lFile.getAbsolutePath());

In this case, using WebView#loadDataWithBaseUrl() is better than WebView#loadUrl()!
webView.loadDataWithBaseURL(url,
data,
"text/html",
"utf-8",
null);
url: url/path String pointing to the directory all your JavaScript files and html links have their origin. If null, it's about:blank.
data: String containing your hmtl file, read with BufferedReader for example
More info: WebView.loadDataWithBaseURL(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)

The Accepted Answer is not working for me, This is what works for me
WebSettings webSetting = webView.getSettings();
webSetting.setBuiltInZoomControls(true);
webView1.setWebViewClient(new WebViewClient());
webView.loadUrl("file:///android_asset/index.html");

XML Layout File:
<WebView android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/webView"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".activities.Bani9">
</WebView>
Java Code:
public class Bani9 extends AppCompatActivity {
WebView webView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bani9);
webView = findViewById(R.id.webView);
WebSettings webSetting = webView.getSettings();
webSetting.setBuiltInZoomControls(true);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl("file:///android_asset/punjabi/bani9.html");
}
}
Make sure you set file path accurately.

From the official guide https://developer.android.com/develop/ui/views/layout/webapps/load-local-content :
Store the HTML as an asset in app/src/main/assets/
Use WebViewAssetLoader to load the asset. Construct it in your onCreate() as follows:
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
.addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this))
.addPathHandler("/res/", new WebViewAssetLoader.ResourcesPathHandler(this))
.build();
Subclass WebViewClient to wrap WebViewAssetLoader:
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));
}
}
This basically passes the request URL to WebViewAssetLoader to load web content from an asset.
Use assetLoader from (2) to construct WebViewClient from (3), and set it in your WebView. Your index.html can be loaded by using https and the default domain appassets.androidplatform.net:
mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
Note that loading local files using web-like URLs instead of file:// is desirable as it is compatible with the Same-Origin policy.

Related

Android WebViewClient / WebViewAssetLoader implementation error

I am trying to load a webpage in asset folder and app's local storage using the webasset loader using the code provided by google.
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
.addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this))
.build();
myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient() {
#Override
#RequiresApi(21)
public WebResourceResponse shouldInterceptRequest(WebView view,
WebResourceRequest request) {
return assetLoader.shouldInterceptRequest(request.getUrl());
}
//This gives the error: shouldInterceptRequest(WebView, WebResourceRequest)' is already
defined in 'Anonymous class derived from android.webkit.WebViewClient
#Override
#SuppressWarnings("deprecation") // for API < 21
public WebResourceResponse shouldInterceptRequest(WebView view,
WebResourceRequest request) {
return assetLoader.shouldInterceptRequest(Uri.parse(request));
//This gives an error for the request variable. It says : Required type: String and
Provided: WebResourceRequest. When I cast it as a string type, it
gives an error similar to first error.
}
});
Can someone please guide me here? What am i doing wrong here, i am using the exact code given by google. Any tutorial on using this class?
The snippet you found in the documentation is wrong, and I have already opened an issue for it.
The problem is that the second method's signature, which refers to a deprecated implementation, should instead be:
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
Use this and it'll compile (and work) as expected.

WebSetting allowFileAccessFromFileURLs is Deprecated in API Level 30

I wanted to use webSetting allowFileAccessFromFileURLs in WebView but the setter is deprecated. how should I set this parameter.
Apparently you should be using WebViewAssetLoader now. Reference here.
Add an implementation "androidx.webkit:webkit:x.x.x" to your build.gradle file replacing x.x.x with the current version (1.3.0 is the most recent one as of the date of this post).
And load it like this in wherever you're setting your WebView (Activity, Fragment, etc):
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
.addPathHandler("/assets/", new AssetsPathHandler(this))
.addPathHandler("/res/", new ResourcesPathHandler(this))
.build();
webView.setWebViewClient(new WebViewClient() {
#Override
public WebResourceResponse shouldInterceptRequest(WebView view,
WebResourceRequest request) {
return assetLoader.shouldInterceptRequest(request.getUrl());
}
});
// Assets are hosted under http(s)://appassets.androidplatform.net/assets/... .
// If the application's assets are in the "main/assets" folder this will read the file
// from "main/assets/www/index.html" and load it as if it were hosted on:
// https://appassets.androidplatform.net/assets/www/index.html
webview.loadUrl("https://appassets.androidplatform.net/assets/www/index.html");

Get a value from webview Android

My application has a webview calling an url and basically all the stuff will be done by the website, but after the user finishes the proccess, it will send an information for the app, like success or invalid.
I want to know how to catch this return value through the webview. Is there a way to do this?
thanks.
You should use a JavascriptInterface to expose one of your Java methods to Javascript on your website.
First, create a class to act as your interface. Any methods you want to expose to Javascript need the #JavascriptInterface annotation:
class MyJavaScriptInterface{
#JavascriptInterface
public void myMethod(boolean success){
//Do something with value
}
}
Then initialize the interface on your WebView:
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new MyJavaScriptInterface(), "JSInterface");
Finally, create the Javascript function to call the Java method from your website:
<script>
//Communicate with Javascript Interface
var processComplete = function(success){
//Only call if the interface exists
if(window.JSInterface){
window.JSInterface.myMethod(success);
}
};
</script>

accessing a file from folder within assets

I have an application which displays html file from assets folder.Now the issue is if there is only one html, all works fine but in case I have more than 1 html, how do I refer it?
Folder structure when only 1 html is present is like
and I refer to html file as follows:
InputStream input = this.getAssets().open("index.html");
but in case of multiple html's, it should/will be like
So, in this scenario , how do I refer different html's?i.e. how do I refer a file from a folder placed within assets folder?
As I have no idea how to proceed, any help appreciated...
You can access it as a URL like so:
"file:///android_asset/myfile.html"
So in a WebView you can use the method:
loadUrl("file:///android_asset/myfile.html")
You can refer like this
WebView webview;
webview=(WebView)findViewById(R.id.webView1);
webview.getSettings().setJavaScriptEnabled(true);
webview.loadUrl("file:///android_asset/HTML 1/index.html");
webview.addJavascriptInterface(new MyJavaScriptInterface(), "Android");
final class MyJavaScriptInterface
{
public void ProcessJavaScript(final String scriptname, final String args)
{
mHandler.post(new Runnable()
{
public void run()
{
//ToDo Something here...
}
});
}
}

Issue with loading local javascript files inside a webview

I had with an issue that has plagued me for days. It turned out that it was an Android glitch and has been submitted, confirmed, and hopefully will be fixed in a future release. Now I have found a solution that works for me, and will provide it below, however the solution is not perfect as it involves editing the phone gap source. Mainly my question is if someone can find a better solution to this issue.
The Bug:
There is a glitch when you attempt to load a page inside of a WebView on Android 3.0+. The glitch is that if that page references any local javascript files, you cannot append query data to the url. Basically
This works:
<script type="text/javascript" src="StaticJS.js"></script>
This does not work:
<script type="text/javascript" src="StaticJS.js?var=val"></script>
Why the hell would anyone want to do this since the file obviously can't do anything with the query vals? Well for me I have a phonegap application that loads a settings file via JSONP, however if a settings file is not specified it defaults to a local file. So yeah, the file can't process the query data but it would be nice to use the same file format and loading structure.
Solution 1 (Non-PhoneGap)
So there is an easy solution to this if the target android platform is 11(Honeycomb) or higher. (As long as you are careful and do not use any method that do not exists in any lower API levels this code will run on <11 apis, but you will still have to set 11 as your target)
Basically you add a WebViewClient to the WebView that utilizes the shouldInterceptRequest method to intercept the loading of local js files with query data attached.
import java.io.IOException;
import java.io.InputStream;
import android.content.res.AssetManager;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class PatchingWebViewClient extends WebViewClient{
AssetManager am;
public PatchingWebViewClient(AssetManager am){
this.am = am;
}
#Override
public WebResourceResponse shouldInterceptRequest (WebView view, String url){
if(url.indexOf("file:///android_asset") == 0 && url.contains("?")){
String filePath = url.substring(22, url.length());
filePath = filePath.substring(0, filePath.indexOf("?"));
try {
InputStream is = am.open(filePath);
WebResourceResponse wr = new WebResourceResponse("text/javascript", "UTF-8", is);
return wr;
} catch (IOException e) {
return null;
}
}else{
return null;
}
}
}
To set the WebViewClient, your code would look something like this:
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
public class CanWeBreakAWebViewActivity extends Activity {
WebView mWebView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new PatchingWebViewClient(this.getAssets()));
mWebView.loadUrl("file:///android_asset/index.html");
}
}
Solution 2 (PhoneGap)
Now for Phonegap I don't have a clean solution. My solution is to go and download the Phonegap source and edit the CordovaWebViewClient by adding the following method:
#Override
public WebResourceResponse shouldInterceptRequest (WebView view, String url){
if(url.indexOf("file:///android_asset") == 0 && url.contains("?")){
String filePath = url.substring(22, url.length());
filePath = filePath.substring(0, filePath.indexOf("?"));
try {
InputStream is = ctx.getAssets().open(filePath);
WebResourceResponse wr = new WebResourceResponse("text/javascript", "Cp1252", is);
return wr;
} catch (IOException e) {
return null;
}
}else{
return null;
}
}
Solution 3 (Non-Existent)
This solution would hopefully be some easy to include class or tweak to the main activity so that you can use phone gap but could just use a .jar file of the code, making upgrades easier.
Thanks for this post, you clued me in to the latest solution which is simply to use IceCreamCordovaWebViewClient.
#Override
public void init() {
super.init(webView, new IceCreamCordovaWebViewClient(this, webView), new CordovaChromeClient(this, webView));
}
Query data is appended to javascript files (and other file types like css) to prevent browser caching. The query data is useless to the file but the browser treats it as new because the location is changed (in the eyes of the browser) and it loads a fresh copy.
I'm glad you found an answer to your problem, just thought I'd give my input as to why people use this method.

Categories

Resources