Using Android WebView to load external HTML with local resources (images, javascript)? - android

I want to create a simple web based application on Android that loads certain large files, like Javascript and user interface elements locally, from 'assets' directory. However I am unable to use local assets directory when loading external HTML. So the external server would give something like this:
<script type="text/javascript" src="file:///android_asset/javascript.js"/>
And WebView would use that, even if the website itself came from external website. I know there are security risks involved, but is there a way to perhaps do that by only allowing specific URL's on applications end?
Is there any way I can do that?

First of all you have to copy all the assets somewhere (external storage, for instance).
Then, to filter URL's you should override method
public boolean shouldOverrideUrlLoading(WebView view, String url);
in WebViewClient class.
added:
When your application starts, put the assets to /sdcard/somefolder/ see getExternalFilesDir()
in shouldOverrideUrlLoading override url to something like this
file:///sdcard/somefolder/<your filename here>
it should be as easy as
public boolean shouldOverrideUrlLoading(WebView view, String url) {
url = "file://" + context.getExternalFilesDir().getAbsolutePath() + "/" + url;
super.shouldOverrideUrlLoading(view, url);
}

Related

Load CSS file from assets to a WebView with custom HTML and predefined Base URL

I need to load some HTML that I construct at runtime into a WebView and apply a CSS file to it placed in the assets directory. And I already have a base URL that I need to provide to the webview's loadDataWithBaseURL function.
Code Snippet (not applying CSS file):
StringBuffer buff = new StringBuffer();
buff.append("<head>");
buff.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"file:///android_asset/my_css_file.css\"/>");
buff.append("</head>");
buff.append("<div class=\"announcement-header\">");
buff.append("HEADER");
buff.append("</div>");
buff.append("<div class=\"announcement-separator\"></div>");
buff.append("<div class=\"announcement\">");
buff.append("CONTENT");
buff.append("</div>")
WebView.loadDataWithBaseURL(MY_BASE_URL, buff.toString(), "text/html", HTTP.UTF_8, null);
I've looked at these 2 similar issues Issue 1 & Issue 2, but my case is slightly different as I cant give file:///android_asset/ as the base url to the loadDataWithBaseURL function.
Any ideas how I can apply the CSS file in this case ?
If you want to intercept some of the requests from WebView you can do so by overriding shouldInterceptRequest() in WebViewClient like this:
public WebResourceResponse shouldInterceptRequest (final WebView view, String url) {
if (URLUtil.isFileUrl(url) && url.contains(".css")) {
return getCssWebResourceResponseFromAsset();
} else {
return super.shouldInterceptRequest(view, url);
}
}
There is already an excellent detailed answer here https://stackoverflow.com/a/8274881/1112882
HOWEVER
You can not access local file if your base url is not local because of security reasons. So give relative path to your css and then intercept the request.
I would suggest using a pattern to differentiate b/w actual relative and custom relative paths. e.g. use android_asset/my_css_file.css instead of my_css_file.css and modify shouldInterceptRequest() accordingly to always intercept requests starting from android_asset.

How to get the HTML code from a webview?

I have read several topics here on SO about this, at first all of them seem related but than when i read the "solution" code i cannot understand where the String that keeps the code is.
What i want to do is load a local HTML file, than modify it with some javascript. And after i have modified it i would like to either replace the unmodified HTML file with the modified HTML file, or create a new HTML file from the modified HTML. So after this process i would have the modified HTML file saved on the users SD card.
I would have loved it if there where a functions like this:
String htmlContent = myWebView.getSouce();
Than i could just create an HTML file from that String and save it to the sd card.
This is my code so far.
final WebView webview = (WebView)rootView.findViewById(R.id.webView);
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url)
{
/* This loads a javascript to the Html file and changes its design*/
view.loadUrl("javascript:(function() { "+
"Some Modifications to the test.html file"+
"})()");
//Now when i have modified the above test.html i would like
//to get the modified HTML (The HTML now displaying in my webview).
//So i was hoping i could write something like this:
// String htmlContent = view.getSouce();
}
});
webview.loadUrl("file:///android_asset/test.html");
If you don't understand javascript interfaces:
http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)
http://developer.android.com/guide/webapps/webview.html#BindingJavaScript

How to check if WebView needs to load remote network resource?

I am using WebView to render local HTML pages loaded from a string, and for security reasons need to block loading any external resources, but need to notify the user if anything was actually blocked and give the user an option to fully load the page with remote images/scripts.
I'm initially blocking network resources with webView.getSettings().setBlockNetworkLoads(true). This works well. Next I need to determine if the loaded HTML content actually contained any references to external networked resources that were blocked. Can anyone please tell me how to do that?
I would like this to work with API 8
You need to do the following:
class MyWebViewClient extends WebViewClient {
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
// This method will get called when resources are to be loaded
return new WebResourceResponse(null, null, new ByteArrayInputStream(new byte[0]));
}
}
Then assign this client to your webview and handle resource loading in the above method.
This way you should be able to disable loading external resources without using the setBlockNetworkLoads(true) method and get the callback at the same time.

WebView loadDataWithBaseURL method cannot load images

I have a html string containing seveal img tags which I am passing to webview's loadDataWithBaseURL method like
String data = "some html with <img> and <link>.....";
wview.loadDataWithBaseURL("http://dummy.baseurl/", data, "text/html", "UTF-8", null);
if I dont pass the first parameter html can be displayed but subsequent requests for or css files are not triggered thats why I am passing a dummy baseUrl.
Running the code when I try to look what requests were made under shouldInterceptRequest() like below
wview.setWebViewClient(new WebViewClient() {
#Override
public WebResourceResponse shouldInterceptRequest(WebView view,
String url) {
Log.d("url="+url, "resources");
....
}
});
the I can see outputs like
http://dummy.host.name/images/face.jpg
etc
but my original html contains ".." in img src like <img src="../images/face.jpg"> trouble is parent directory (..) part is ignored by webview
this ".." is important for me I cannot figure out why it is skipping that part
EDIT
I am loading images from a zip file so inside shouldInterceptRequest() I can put necessary logic but first I should have correct src.
I also noticed that if path is appended to baseUrl, they are also ignored for example
http://dummy.baseUrl/one/two/
becomes (looking from request logs)
http://dummy.baseurl/
I suspect if these two are related !
Where do you want to load the images from? If you're trying to load them from the phone you need to use the assets folder.
https://stackoverflow.com/a/7268695/642161
I resolved my problem using a hack, not sure a better solution exist!
It looks like baseUrl and src are merged to create final request urls so if any ".." present in src it will be used to recalculate final url and they disappear no matter if top level directory exist.
I changed baseUrl to
file:///android_asset/x123_/x123_/x123_/x123_/
Here "x123_" is any random character sequence one can take but should be least likely to appear in "src"
Now count the mumber of "x123_" in request url inside shouldInterceptRequest() if it is 4 (as in this example) there were no ".." in src otherwise number of ".." = 4 - count

Access local file in a WebView

My native app includes a WebView, and the WebView loads a web page off web. For example, the html is loaded from
http://dongshengcn.com/test.html
It seems any page loaded from web (instead of local) can not load any file from local device.
My question is:
Is it possible for a http://dongsheng.com/test.html loaded to a webview (as part of native app) to access file on local device?
Here are a couple of things to try:
To use local files you need to place them in your project's assets folder and invoke them using URLs such as file:///android_asset/. For example, if you add mypage.html in your assets folder, then you can invoke it in the webview with file:///android_asset/mypage.html.
Check to make sure that you have the appropriate webview permissions in your Manifest. For the webview to work correctly, you need:
<uses-permission android:name="android.permission.INTERNET" />
Take a look at the following app on Github, which as a bonus also fixes a couple of bugs with the webview in Honeycomb and ICS. It is a full example on how to use the webview with local files:
https://github.com/bricolsoftconsulting/WebViewIssue17535FixDemo
EDIT: Addendum after question clarification:
Yes, it is possible to load a local page from the web, but you must use a trick to bypass the browser's security measures.
Replace the file://android_asset/ portion of the URLs with a custom scheme (e.g. file///android_asset/mypage.html becomes myscheme:///mypage.html), and place these custom scheme URLs in your page. Implement WebViewClient's shouldOverrideUrlLoading, check if the URL begins with the custom scheme and if so redirect to the local page using webview.loadUrl.
mWebView.setWebViewClient(new WebViewClient()
{
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
if (url != null && url.startsWith("myscheme://"))
{
String newUrl = url.replace("myscheme://", "file://android_asset/");
mWebView.loadUrl(newUrl);
return true;
}
return false;
}
}

Categories

Resources