Programming and Personal Development

Customizing Android WebView

In previous post we saw how to use the default Webview element to display html resources in your android application . Webview also offers the ability to override its default content loading behaviour, look and feel and its settings to suit your needs. Lets look at the various  customization points with examples.

WebViewClient

Allows you to customize and filter the content to be displayed in the WebView. Provides callback methods that receive control during various bowser events like,
  • when page has started loading and finished loading ( onPageStarted () && onPagefinished () ),
  • when the user clicked on a URL ( shouldOverrideUrlLoading () ),
  • error conditions such as onTooManyRedirects () etc.
You can extend the WebViewClient class to create and customize your own WebViewClient  and associate it with the WebView element using the setWebViewClient () method.

WebChromeClient

Allows customization of visual aspects of WebView such as
  • Alerts and Confirm Dialogs ( onJsAlert () or onJsConfirm ),
  • progress updates  ( onProgressChanged () ) etc.
You can customize by extending the WebChromeClient Class and  by calling the setWebChromeClient() method.

JavaScriptInterface

This essentially allows you to call your Java code from Javascript. You write a piece of logic in Java and use the addJavascriptInterface () method to bridge it with the Javascript environment along with a String identifier. You can then use this identifier in your Javascript code to call the Java code. As cool as this is, its also a security concern and it is a good idea to restrict this kind of access only for browser code ( HTML/Javascript) you trust.
In addition, WebView provides various settings that can be overridden such as enabling javascript ( its off by default), setting layout algorithm etc.android webview customization demo

Example

In the previous post we used a simple html file as a local resource and loaded it into the WebView element.  Lets now extend and customize it  raise an android toast message as well as  provide the ability to reload the page as follows :
  • Override the Javascript’s standard alert function to use Android’s Alert Dialog in our custom WebChromeClient.
  • Create a Java class to refresh the WebView and call it from javascript code to reload the page.
  • Finally,  we keep track of the number of times the page has refreshed and the time taken for the refresh with our own WebViewClient.
Lets look at each of them one by one.

Custom WebChromeClient

We extend the WebChromeClient and override the onJSAlert () method to use the Android’s Alert dialog.
private class CustomChromeclient extends WebChromeClient {
   @Override
   public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
      AlertDialog dialog = new AlertDialog.Builder(view.getContext()).
              setMessage(message).
              setPositiveButton("OK", new DialogInterface.OnClickListener() {
                 @Override
                 public void onClick(DialogInterface dialog, int which) {
                    //do nothing
                 }
              }).create();
      dialog.show();
      result.confirm();
      return true;
   }
}
Now this method gets called each  any time the  javascript alert () function is called within  the WebView. We also have to associate this to our WebView element using the setWebChromeClient() method as shown below.
wv.setWebChromeClient(new CustomChromeclient());

WebView Reload

Next we enapsulate the logic to reload the WebView in a separate Java class and associate it with string identifier ( in this case “JSI”). We can then use this string identifier to refer the Java class from the browser’s javascript environment. We’ll see this usage a bit later when we see the modifications to the HTML file. But first the WebView reload logic is as shown below. Nothing fancy here. We have a simple object that takes in a reference to the WebView element as a constructor argument and calls the reload() method on it.
private class JavaScriptInterface {
   private final WebView m_wv;
   public JavaScriptInterface(WebView wv) {
      m_wv = wv;
   }
   public void reload() {
      m_wv.reload();   }
}
we then bind this reload logic with the Javascript environment using the addJavascriptInterface () method. This method takes in the reference to the Java class and a string identifier as shown.
wv.addJavascriptInterface(new JavaScriptInterface(wv), "JSI");

Calculating the Page load  count and intervals

Here, we extend the WebViewClient class and override the onPageStarted () and OnPageFinished () methods. As the names imply, these are callback methods that get called when page has started and finished loading respectively. We use a static variable ( refreshCount) to keep track of the number of times the page has been refreshed and also note down the  start and end times for page load. We then subtract the two to get the load time and display the information on the screen as a Toast message.
In addition, we also override the shouldOverrideUrlLoading ()  method to return false. This forces android to open any URL clicks within the WebView instead of its default behavior, which is to open the URL using the Webkit browser.
private static class CustomWebViewclient extends WebViewClient {
   private static int refreshCount;
   private Context m_context;
   private long m_start;
   private CustomWebViewclient(Context context) {
      m_context = context;
   }
   @Override
   public boolean shouldOverrideUrlLoading(WebView view, String url) {
      return false;
   }
   @Override   public void onPageStarted(WebView view, String url, Bitmap favicon) {
      m_start = System.currentTimeMillis();
      refreshCount++;
   }
   @Override
   public void onPageFinished(WebView view, String url) {      long interval = System.currentTimeMillis() - m_start;
      Toast.makeText(m_context, "Loaded this webpage [" + refreshCount + "] " +
              "times in [" + interval + "] ms", Toast.LENGTH_SHORT).show();
   }
}
Again, associate the custom WebViewClient with the WebView element.
wv.setWebViewClient(new CustomWebViewclient(this));

HTML File

Finally we modify the HTML file to have two buttons,
  • one that raises an alert dialog in the browser which then displays our AlertDialog instead of the standard javascript alerts and
  • the second to reload the page in the WebView.  Note the use of the identifier “JSI” on the reloadBtn which is used to call the reload() method on the Javascript interface.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>Hello World</title>
    <!--Javascript alert function-->
    <script type="text/javascript">
        function toast() {
            alert("Raise a toast")        }
    </script>
</head>
<body>
<H1>
    Hi There...I am a local resource
</H1>
<div id="alertBtn">
    <!--Call to the Javascript alert function-->
    <input id="btn1" type="button" value="toast" onclick="toast()"/></div>
<div id="reloadBtn">
    <!--onclick function that calls the 'Java' Code -->
    <input id="btn2" type="button" value="reload" onclick="JSI.reload()"/></div>
</body>
</html>

Activity class

The overall activity class is listed here. All the Custom classes discussed above are inner classes of this activity class.
public class WebViewDemo extends Activity {
   private static final String URL_TO_LOAD = "http://google.com";
   private static final String LOCAL_RESOURCE = "file:///android_asset/html/HelloWorld.html";
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.browser_demo);
      WebView wv = (WebView) findViewById(R.id.browser1);
      loadResource(wv, LOCAL_RESOURCE);
   }
   private void loadResource(WebView wv, String resource) {      wv.loadUrl(resource);
      wv.getSettings().setJavaScriptEnabled(true);
      wv.setWebChromeClient(new CustomChromeclient());
      wv.setWebViewClient(new CustomWebViewclient(this));
      wv.addJavascriptInterface(new JavaScriptInterface(wv), "JSI");
   }  // Custom classes for WebViewclient, WebChromeClient and JavaScript interfaces...}
Happy Coding !!!.
Web Analytics