I have a webview which loads an offline HTML . My offline HTML contains
Text
Local Images
Embedded videos
All works fine but when user doesn't have the internet connection the 'text' and 'images' load fine but 'embedded videos' part shows an ugly NO INTERNET CONNECTION error.
My question is how do I handle this error and replace it with my own custom error.
I want to keep showing all the other contents in my html even if there is no internet connection but replace embedded video error message with custom error message.
Anyone knows how to achieve this?
Cheers
My webview code
webView.ClearCache(true);
webView.ClearHistory();
string HTML_DATA = "";
if (File.Exists(localPath))
{
string HTML_LOCAL = File.ReadAllText(localPath);
HTML_DATA = HTML_LOCAL;
}
webView.Settings.JavaScriptEnabled = true;
webView.Settings.LoadWithOverviewMode = true;
webView.Settings.UseWideViewPort = true;
webView.SetWebViewClient(new WebViewClientClass());
webView.LoadDataWithBaseURL("file:///android_asset/", HTML_DATA, "text/html", "UTF-8", null);
Now the results are the following
With internet
Without internet
My question is how do I handle this error and replace it with my own custom error.
You can handle it in WebViewClient like codes below, but it will replace the whole page of WebView with your error page:
public class MyClient:WebViewClient
{
public Context _context;
public MyClient(Context c)
{
_context = c;
}
public override void OnReceivedError(WebView view, IWebResourceRequest request, WebResourceError error)
{
base.OnReceivedError(view, request, error);
var errMsg = error.DescriptionFormatted;
Toast.MakeText(_context, errMsg, ToastLength.Long).Show();
string htmlData = $"<html><body><div align='center'>This is the description for the load fail : {errMsg}</div></body>";
view.LoadUrl("about:blank");
view.LoadDataWithBaseURL(null, htmlData, "text/html", "UTF-8", null);
view.Invalidate();
}
...
Alternatively, you can handle the error in Html, you can define an error window with the same size of your webview, and hide/show it according to the internet states:
<DOCTYPE>
<html>
<head></head>
<body>
<iframe id="mFrame" width="854" height="480" src="https://www.youtube.com/embed/a5GMRrEJaVo" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<div id="errorWindow" width="854" height="480">
This is the div for your custom error view
</div>
<script>
(function(){
"use strict"
var mIframe=document.getElementById("mFrame");
var errorWindow=document.getElementById("errorWindow");
if(navigator.onLine)
{
//internet available
mIframe.hidden=false;
errorWindow.hidden=true;
}else
{
//internet not available
mIframe.hidden=true;
errorWindow.hidden=false;
}
})()
</script>
</body>
Notes: you will have to define following permission to have navigator.onLine work:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Related
I use volley to fetch content from a wordpress blog via its api.
The content I receive looks like this:
<p>Blog content blabla</p>\n
<div id=\ "pressrelease-link-345\" class=\ "sh-link pressrelease-link sh-hide\">
<a href=\ "#\" onclick=\ "showhide_toggle('pressrelease', 345, 'Show full article', 'Hide article'); return false;\" aria-expanded=\ "false\">
<span id=\"pressrelease-toggle-345\">Show full article</span>
</a>
</div>
<div id=\ "pressrelease-content-345\" class=\ "sh-content pressrelease-content sh-hide\" style=\ "display: none;\">
</p>\n
<p>more content which is displayed after expanding the text in the browser</p>
I'd like to show the full text in my app, so the whole -part should be removed. Is there a nicer way to do this than just building the string for each article (id, here 345)? I though maybe I could just 'filter' out the div using volley, but didn't figure out how yet.
If i have understand, you want remove a div from a HTML page with a WebView ?
private void yourwebv (){
String url = "mysite.com";
final WebView webview = (WebView) findViewById(R.id.WEBVIEW_ID);
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebChromeClient(new WebChromeClient());
webview.setVisibility(View.INVISIBLE);
final ProgressBar ProgressBar = (ProgressBar) findViewById(R.id.ProgressBar);
ProgressBar.setVisibility(View.VISIBLE);
webview.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url){
String javaScript ="javascript:document.getElementsByClassName('YOURDIVCLASSNAME_REMOVE')[0]" +
".style.display='none';void(0);";
webview.loadUrl(javaScript);
Log.d("[WV]", " JS OK");
final ProgressBar ProgressBar = (ProgressBar) findViewById(R.id.ProgressBar);
ProgressBar.setVisibility(View.INVISIBLE);
webview.setVisibility(View.VISIBLE);
}
});
webview.loadUrl(url);
Log.d("[WV]", " WEBSITE + JS SCRIPT OK");
}
I'm developing an Android application in which I have used an HTML file for help contents. I have used a WebView to display the content and every thing is fine.
The problem is that user can change the theme and font size of the application. How can I propagate these properties to the content of WebView? Exactly how can I change the font size and text color in WebView? Is there a simple way to do that or I should create different HTMLfiles or CSSes? How to handle the size units (dp, sp, ...)?
I will appreciate your help with this situation.
loadUrl("javascript:(document.body.style.backgroundColor ='red');");
loadUrl("javascript:(document.body.style.fontSize ='20pt');");loadUrl("javascript:(document.body.style.color ='yellow');");
On your android application, use following code to load a web page with user chosen font size and color:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebChromeClient(new InredisChromeClient(this));
myWebView.setWebViewClient(new InredisWebViewClient(this));
myWebView.clearCache(true);
myWebView.clearHistory();
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
myWebView.loadUrl("http://demo.com/content.html?font-size=12&fontcolor=blue");
On the content.html page, enable JavaScript and use jQuery and its function as below:
function getCssValue(sCSS)
{
var sPageURL = window.location.search.substring(1);
var sValues = sPageURL.split('&');
for (var i = 0; i < sValues.length; i++)
{
var sPair = sValues[i].split('=');
if (sPair[0] == sCSS)
{
return sPair[1];
}
}
}
$(document).ready(function(){
// Set the Font Size from URL
$('html').css('font-size', getCssValue('font-size'));
});
It is best to do theme activities using CSS and Javascript. However if we want to pass on some settings from Android to the WebView dynamically, it is possible and a solution is to use the JavascriptInterface. Here is one way of doing it:
Firstly, we define a class which will be used as a bridge between the Android app and the WebView for JS interactions.
Here WebInterface is an inner class in the Activity and hence it has direct access to myWebView, which is a WebView instance variable.
public class WebInterface {
private Activity activity;
public WebInterface(Activity activiy) {
this.activity = activiy;
}
#JavascriptInterface
public void changeTheme() {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
// All of the theme settings could go here, the settings passed on by Android
myWebView.loadUrl("javascript:document.body.style.backgroundColor ='red';");
myWebView.loadUrl("javascript:document.body.style.fontSize ='20pt'");
myWebView.loadUrl("javascript:document.body.style.color ='yellow';");
//OR load your data as shown here http://stackoverflow.com/a/7736654/891092
htmlData = "<link rel=\"stylesheet\" type=\"text/css\" href=\"theme.css\" />" + htmlData;
// lets assume we have /assets/theme.css file
myWebView.loadDataWithBaseURL("file:///android_asset/", htmlData, "text/html", "UTF-8", null);
}
});
}
}
Note that it is very important to run your code in UI Thread otherwise it will not work.
Here is how the Activity registers the WebView with the JavascriptInterface:
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.addJavascriptInterface(jsInterface, "JSInterface");
In the HTML file, which the user is viewing, a button or widget could be made to change theme by calling code in Android through the bridge:
<input type="button" value="Say hello" onClick="doChangeTest()" />
<script type="text/javascript">
function doChangeTest(){
JSInterface.changeTheme(); // this calls the changeTheme in WebInterface
}
</script>
First you need to define a webView and after that use below method.
lightFont is your font that you should store in asset folder.
color is your text color.
font size : you can change font size.(for example 20px or medium and etc).
at the end you need to use seconde method to show html on webView
First Method:
public static String getStyledFont(String html) {
boolean addBodyStart = !html.toLowerCase().contains("<body>");
boolean addBodyEnd = !html.toLowerCase().contains("</body");
return "<style type=\"text/css\">" +
"#font-face {font-family: CustomFont;" +
"src: url(\"file:///android_asset/lightFont.ttf\")}" +
"body {color: #787878;}"+
"body {font-family: CustomFont;font-size: x-small;}</style>" +
(addBodyStart ? "<body>" : "") + html +(addBodyEnd ? "</body>" : "");
}
Second method:
String htmlText = getStyledFont(yourText);
webView.loadDataWithBaseURL("file:///android_asset/",
htmlText ,
"text/html; charset=UTF-8", null, null);
I wanted to put variable from my activity and display it in html. Below is how I insert the variable into webview but I'm not sure how am I suppose to get the data from html and display it in "textview" form?
EDIT
Java
webView = (WebView)findViewById(R.id.webView);
webView.setWebViewClient(new WebViewClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webView.getSettings().setDatabaseEnabled(true);
webView.getSettings().setDatabasePath("/data/data/com.example.hybrid/hybrid_user");
webView.loadUrl("file:///android_asset/www/index.html");
webView.loadUrl("javascript:callFromActivity(\""+userid+"\")");
html
<body>
<form>
<fieldset>
<legend>Hybrid Application</legend>
<p>
<label>UserName: </label>
</p>
<p id="mytext">Hello!</p>
<p>
<label>Mobile Number :</label>
<input type = "text"
id = "mobileNum" />
</p>
<button type="button"
onclick="updateRecord()">Submit</button>
<div id="output"></div>
</fieldset>
</form>
<script>
function errorHandler(transaction, error){
alert('Error:'+error.message+' (Code '+error.code+')');
return true;
}
window.onerror = errorHandler;
var shortName = 'hybrid_user';
var version = '1.0';
var displayName = 'Hybrid Database';
var maxSize = 65536;
var db = openDatabase(shortName, version, displayName, maxSize);
function updateRecord(id, textE1){
database.transaction(function(tx){
tx.executeSql("UPDATE hybrid_user SET mobile = ? WHERE userid = ?", [textE1.innerHTML, id], null, onError);
})
}
function callFromActivity(msg){
document.getElementById("mytext").innerHTML = msg;
}
</script>
I'm new to html and I don't know what's wrong with my code, it did not display out the userid in the html page. Any comments and answers will be appreciated!
Edit update
webView.loadUrl("javascript:callFromActivity(\""+userid+"\")");
Apparently is the system didn't go through this line of code. Is there anyway go through this code?
try change innerHTML for value like this:
function callFromActivity(msg) {
document.getElementById("mytext").value = msg;
}
webView.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url){
webView.loadUrl("javascript:callFromActivity(\""+userid+"\")");
}
});
I solved my problem with this. When the page loads finished it will execute the above code and get the userid from the activity.
I'm loading below html in my webView
https://mail-attachment.googleusercontent.com/attachment/?ui=2&ik=25c0c425c6&view=att&th=138db54ff27ad34b&attid=0.1&disp=inline&realattid=f_h5ahtmbe0&safe=1&zw&saduie=AG9B_P9YNooGjsk_jLefLptQ9q15&sadet=1343790299575&sads=-yBVsLKP_2mh7zMfYLCF7sL1u-w
Now what I want to do is to fill the textbox in the html that came from my java class variable and then automatically hit submit.
But I don't have any idea how to do this.
Any thougths will be appreciated.
First, your URL seems not available.
If you want to do data exchange between android app and your web app/web page you can achieve this via javascript.
Here is an example from Android official site:
Create a class like this:
public class JavaScriptInterface {
Context mContext;
/** Instantiate the interface and set the context */
JavaScriptInterface(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 your WebView:
WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new JavaScriptInterface(this), "Android");
In your web page:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
If you wanna pass something to your webpage, just calling corresponding javascript function:
String str = "xxx";
myWebView.loadUrl("javascript:xxx('"+str+"')");
Here is the Reference:
http://developer.android.com/guide/webapps/webview.html
I would add that the load of the javascript function should be done when the html is loaded. To control that, you can use the following:
webview.getSettings().setJavaScriptEnabled(true);
webview.loadUrl("file:///android_asset/test.html");
webview.setWebViewClient(new WebViewClient(){
public void onPageFinished(WebView view, String url){
webview.loadUrl("javascript:init('" + theArgumentYouWantToPass + "')");
}
});
test.html
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
hola
adios
</body>
<script type="text/javascript">
function init(val){
// Do whatever you want with your parameter val
}
</script>
</html>
Taken from Uncaught ReferenceError: myFunction is not defined at null:1 Android exception in webview
Just enable DOM Storage and write var x= to string:
webview.getSettings().setJavaScriptEnabled(true);
web.getSettings().setDomStorageEnabled(true);
webview.loadUrl(urlString);
webview.setWebViewClient(new WebViewClient(){
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
String js = "javascript:var x =document.getElementById('username').value = '"+user+"';var y=document.getElementById('password').value='"+pass+"';";
if (Build.VERSION.SDK_INT >= 19) {
view.evaluateJavascript(js, new ValueCallback<String>() {
#Override
public void onReceiveValue(String s) {
}
});
}
else {
view.loadUrl(js);
}
}
Be careful to call javascript function like this, the str may include single quote or other special characters.
String str = "xxx";
myWebView.loadUrl("javascript:xxx('"+str+"')");
I suggest to encode the str in base64, and decode it on javascript side.
Android
String str = "xxx";
//encode in base64
String base64Str = Base64.encodeToString(str.getBytes(), Base64.NO_WRAP);
myWebView.loadUrl("javascript:xxx('"+ base64Str +"')");
Javascript
function xxx(val) {
//decode from base64
var str = atob(data)
}
Pass the paramter directly in the url
webView.loadUrl("file:///android_asset/animation.html?message=testing");
Get the paramter in html file
var url_string = window.location.href
var url = new URL(url_string);
var message= url.searchParams.get("message");
Solutions by Hungr would work, but using the same document they point out, I do the following:
in my Android code WebAppInterface class:
#JavascriptInterface
fun provideData(val input: String): String{
val output = ""
//some operation with input
return output
}
then in host activity for webview:
webView.addJavascriptInterface(WebAppInterface(this), "Provider")
Inside your JS or HTML:
document.getElementbyId("Text").innerhtml = Provider.provideData(input);
I have a simple html5 test page which uses LocalStorage to display / save / redisplay a piece of data.
This code works perfectly in Android 2.3.x but logs an exception in 4.0.1 on line 18 of the html which is the frist localStorage.getItem() call and at this point the JS stops.
Exception: Uncaught Error: SECURITY_ERR: DOM Exception 18 at /data/data/my.app.name/app_htmlData:18
I've also tried setting the database path to getCacheDir() with the same result.
String htmlContent = "HTML content listed below";
File sharedDir = getActivity().getDir("htmlData", Context.MODE_PRIVATE);
WebView browser = (WebView)v.findViewById(R.id.wvBrowser);
browser.setWebChromeClient(new WebChromeClient(){
public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
quotaUpdater.updateQuota(estimatedSize * 2);
}
});
browser.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url){
view.loadUrl("javascript:doTest()");
});
browser.getSettings().setDatabaseEnabled(true);
browser.getSettings().setDatabasePath(sharedDir.getPath());
browser.getSettings().setDomStorageEnabled(true);
browser.loadDataWithBaseURL(mSharedDir.getPath(),
htmlContent,
"text/html",
"utf-8",
null);
The HTML that the page is rendering is as follows:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Simple localStorage test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
function doTest() {
$('#stuff').append('<p>reading</p>');
var item = read();
$('#stuff').append('<p>writing</p>');
localStorage['bar'] = new Date().toUTCString();
$('#stuff').append('<p> </p><p>reading again</p>');
read();
}
function read() {
var item = localStorage.getItem('bar');
if (item == null || (item == undefined)) {
item = '';
}
$('#stuff').append('<p> item: ' + item + '</p>');
return item;
}
</script>
</head>
<body>
<p>-Simple localStorage test-</p>
<div id="stuff"></div>
</body>
</html>
Source available here
Via some discussion with a Google engineer it seems that they've made the decision that the file:// scheme is insecure.
A work around for this is to do the following
browser.loadDataWithBaseURL("http://www.example.com",
htmlContent,
"text/html",
"utf-8",
null);
For android versions less than 4.4, loading data into a webview with a file scheme as a directory:
browser.loadDataWithBaseUrl("file:///android_asset/", html, "text/html", "UTF-8", null);
wont work with localStorage. If I add a filename it does work on older OS versions
browser.loadDataWithBaseUrl("file:///android_asset/test.html", html, "text/html", "UTF-8", null);