Chapter 4. WebView, WebKit, and WebSettings

In this chapter, we will be introducing the WebView control and its capabilities. WebView in Android is a wrapper around the WebKit rendering engine, and can be used to display web pages inside your application. As a developer, you can use this control to render any web page as part of your application. These pages can be local or can be consumed from the Web. We will be using the WebView control to host our hybrid application. Although WebView itself is very powerful, the current API support is restricted by various specifications from standards governing bodies and individual organizations. Hence, it is often necessary to extend the API set to allow hybrid applications to access to platform capabilities.

The WebView as a Web Browser

A WebView is often used to load HTML content within a native application. The WebView enables you to embed a web browser, which does not have any chrome (browser) controls including window frames, menus, toolbars and scroll bars into your activity layout.

The WebView is capable of displaying online or offline web content within its layout using HTML5, JavaScript, and CSS technologies. It also includes standard browser features like history, zooming, JavaScript, rendering CSS, and so on.

The most common implementation is to facilitate advertisement loading from remote servers. WebView often comes in handy for rendering complex UI views. One good example is the Facebook and LinkedIn applications wherein the news feed is rendered using the WebView control.

Note

For those of you who wish to dig deeper on the subject of WebView and its integration within Android, we recommend you to have a look at WebView.java located in the frameworks project in base/core/Java/android/WebKit. In summary, you will notice that WebView is just a wrapper view, which holds the handle to the canvas on which WebKit can operate. For almost everything else, it is a pass through to a controller module that manages user interactions, user data, and web requests.

So What Is WebKit?

WebKit is a rendering engine library to render web pages in view and windows. It also features a framework to interact with user events such as following links on user clicks. WebKit has become the de facto standard for web browser engines on mobile devices.

WebKit applications behave as you would expect. The WebKit conveniently creates and manages all the views needed to handle different MIME types. When the user clicks on a link in a page, the WebKit automatically creates the views needed to display the next page. For more details on WebKit, please refer to the WebKit website.

WebKit is a part of the libraries layer in the Android platform architecture. To get more information about WebKit on Android, read Joe Bowser’s Android WebKit Development - A Cautionary Tale Presentation 1.

Caution

Since the Webkit is an open source browser engine, each mobile OS manufacturer might maintain a different version of WebKit. For example, WebKit in an iOS device is different from in an Android device. Check your WebKit HTML5 capabilities by visiting the html5test website; here you’ll find the available HTML5 APIs as well as CSS3 support.

Requesting Internet Permission from Android Manifest

In case, you want to load a URL in the WebView, you need to declare a uses-permission element just above the <application> … </application> element in the AndroidManifest.xml file. In Chapter 3, the necessary application-specific permissions are explained in detail.

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <uses-permission android:name="android.permission.INTERNET" />
        <application> ... </application>
    ...
</manifest>

Instantiating and Accessing the WebView Control

A layout denotes the visual structure of an application screen. To use a WebView in your application, we need to add the WebView control to the view hierarchy of the application. This can be done in one of two ways:

  • Using the XML-based layout files
  • Programmatically

The XML way is preferred for many developers because it is not only easy to write but also because it can be done visually using the Eclipse XML Graphical Layout Editor. To add a WebView in a view hierarchy, add the following XML tag in your layout’s XML.

<WebView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/WebView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />

A view created this way will be inflated (instantiated) by Android upon a user’s call to setContentView() API. You can obtain handle to the WebView as you do with other views using the findViewById() API.

WebView webView = (WebView) findViewById(R.id.WebView);

Alternatively, you can create an and add a WebView to the application view hierarchy programmatically, as follows:

WebView WebView = new WebView(this);
contentView.addView(webView);

Loading a Web Page

Once you have a created a WebView control, you can request it to load a web page by using the loadURL() API passing the requested URL in the function argument. WebView supports loading resources from the Web or locally from the assets or resource folder.

  • Root path to the asset folder in Android is file:///android_asset
  • Root path to the res folder in Android is file:///android_res

Caution

Please note, that the url is file:///android_asset and not file:///android_assets. This is one of the most common mistakes made by developers during development.

Note

file:/// simply denotes that you wish to access the local filesystem, and points to the root directory. Anything mentioned after this is the relative path to the resource we would like to load in the WebView. Hence, when the URL is of the form file:///android_asset, we are specifying the base URL for the path to the asset folder for the application package.

// load index.html from the assets folder
WebView.loadUrl("file:///android_asset/index.html");

// load logo.png from the res folder
WebView.loadUrl("file:///android_res/drawable/logo.png");

// load a web based URL, Oreilly's homepage in this case
WebView.loadUrl("http://www.oreilly.com");

Loading HTML into WebView

You can request the WebView to render any valid HTML as a string using the loadData() method.

Let’s look at the loadData() API in a bit more detail:

loadData(String data, String mimeType, String encoding)

data specifies the data to be loaded, HTML markup in our case, into the WebView using the data URL scheme. The data URL scheme allows us to include data inline in web pages as if they were external resources. Using this technique, we can load normally separate elements such as images and stylesheets in a single HTTP request rather than multiple HTTP requests.

mimeType will denote the data type, which will be text/html.

The encoding parameter specifies whether the data is base64 or URL encoded. If the data is base64 encoded, the value of the encoding parameter must be base64. For all other values of the parameter, including null, it is assumed that the data uses ASCII encoding for octets inside the range of safe URL characters.

String data = "<!DOCTYPE html>";
data += "<head><title>Hello World</title></head>";
data += "<body>Welcome to the WebView</body>";
data += "</html>";
// args: data, mimeType, encoding
WebView.loadData(data, "text/html", "UTF-8");

the above API will be used to create a data URL of the form data:[<MIME-type>][;charset=<encoding>][;base64],<data> before it is loaded inside the WebView.

Caution

If you would like to reference a file from an arbitrary source like the res/drawable directory within your HTML documents, using something like:

// Bad example
String data = "<!DOCTYPE html>";
data += "<head><title>THIS WILL NOT WORK</title></head>";
data += "<body><img src=\"file:///android_res/drawable/logo.png\" /></body>";
data += "</html>";
WebView.loadData(data, "text/html", "UTF-8");

This code will not load the logo.png image, as JavaScript’s same origin policy restricts all the resources on the web page to originate from the same site—in this case, data:[<MIME-type>] and not file:///, as we have requested.

To avoid this restriction, Google recommends using loadDataWithBaseURL() with an appropriate base URL, which is used both to resolve relative URLs and when applying JavaScript’s same origin policy.

WebViewClient

Android’s WebView is extensible and implements a number of delegatory classes including WebViewClient and WebChromeClient, which can be used by developers to customize the default behavior of WebView and inject data in the request/response call flows.

WebViewClient is a class that the WebView refers to before it handles everything that, in some way, is related to the rendering of a page. Using this class, you can add callback methods that are invoked to inform you of changes in the rendering.

These callbacks include:

  • Start and stop loading of web requests
  • Whether the browser should load specific resources
  • Notify errors, login requests, and form resubmissions

Android WebView has a default implementation of the WebViewClient, which can be overridden by the default delegate using the setWebViewClient() method of the WebView.

webView.setWebViewClient(new WebViewClient(webView) {
  // override all the methods
});

WebChromeClient

WebChromeClient is also a delegate class, responsible for everything browser UI specific, unlike the WebViewClient, which is responsible for everything that is related to the rendering of the web content.

The WebChromeClient lets you handle the browser’s visited history, create new windows, take care of alerts, prompts, and console messages. A simple application with no requirements on the integration will be fine without overriding the default WebChromeClient delegate. You can specify your own delegate using the setWebChromeClient() method of the WebView.

webView.setWebChromeClient(new WebChromeClient(webView){
  // override all the methods
});

Loading Local Files into the WebView

Android WebView provides a very flexible set of APIs to load documents from multiple sources. However, you may have to tweak the behavior of the WebView in certain cases, as the same origin policy would restrict the locations from which the content can be loaded within the web browser—for example, loading a local file on the filesystem.

In the following sections, we will look at some of the techniques you can use to allow the web browser to load content from multiple sources.

Load local files from res/drawable into the WebView with a given base URL:

String html = "<!DOCTYPE html>";
html += "<head><title>Loading files from res/drawable directory</title></head>";
html += "<body><img src=\"logo.png\" />/body>";
html += "</html>";
WebView.loadDataWithBaseURL("file:///android_res/drawable/", html, "text/html", "UTF-8", null);

Load local files from an SD card into the WebView without a given base URL:

String base = Environment.getExternalStorageDirectory().getAbsolutePath()
        .toString();
String imagePath = "file://"+ base + "/logo.png";
String html = "<!DOCTYPE html>";
html += "<head><title>Loading files from SDCard</title></head>";
html += "<body><img src=\""+ imagePath + "\" />/body>";
html += "</html>";
WebView.loadDataWithBaseURL("", html, "text/html","UTF-8", null);

Caution

One important thing to note is that the previous solution is supported only in API Level 2.2 and above. If you are using an API level lower than 2.2, an alternative solution can be executed by reading the file into a string buffer explicitly.

Load local files into the WebView by reading the contents of the file in Java and then passing the data to the WebView:

// Load an html file
String html = loadFileFromSDCard("file:///sdcard/oreilly/book/logo.png");
WebView.loadDataWithBaseURL("", html, "text/html", "UTF-8", null);

or:

// Load an image file
String pngData = loadFileFromAssets("file:///android_asset/images/logo.png");
WebView.loadData(pngData, "image/png", "UTF-8");

Load Flash Files into the WebView

In order to load flash files from SDCard into the view, you can link your flash files in the embed tag using file:/// protocol.

<!-- flash.html -->
<html>
  <head>
    <title>Playing Flash movie</title>
  </head>
  <body>
    <object width="200" height="200">
      <param name="movie" value="hybrid.swf">
      <embed src="file:///sdcard/hybrid.swf" width="200" height="200"></embed>
    </object>
  </body>
</html>

Then, you need to load your flash.html file from SDCard using the loadUrl() method.

String base = Environment.getExternalStorageDirectory().getAbsolutePath().toString();
String html = "file://" + base + "/flash.html";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        WebView.loadUrl(html);
}

Reading Files from the res/raw Directory

If you need to read a file (e.g., home.html) from the res/raw directory and display it in the WebView, you need to pass the resource ID (e.g., R.raw.home) to your reader function in order to get it as string.

WebView.loadData(getRawFileFromResource(R.raw.home), "text/html", "UTF-8");

private String getRawFileFromResource(int resourceId) {
        StringBuilder sb = new StringBuilder();
        Scanner s = new Scanner(getResources().openRawResource(resourceId));
        while (s.hasNextLine()) {
                sb.append(s.nextLine() + "\n");
        }
        return sb.toString();
}

Triggering JavaScript Functions from the Java Layer

A key aspect of an hybrid application would be its ability to allow native code to call JavaScript APIs, for delivering data, callbacks, and events. Since, there is no direct API for this in WebKit, developers often use the loadUrl() function for this purpose. The loadURL() function requests the WebView to load and execute the specified URL.

If you recall the structure of a URL, it looks something like:

    scheme: [hostaddress][params]
  |        |            |       |
  |protocol| optional   |       |
  -------- |address for |       |
           |  service   |       |
           -------------- params|

The protocol can be any valid scheme as long as there is either a valid default handler registered in WebKit for that scheme or your application serves this scheme. Examples for protocol would be http, https, ftp, JavaScript, or karura (karura://karura.js)—in our case, identifying our declared protocol scheme.

The JavaScript protocol is of special interest to us for this topic. The syntax for the JavaScript protocol is JavaScript:sScript.

This protocol scheme is used to specify a sequence of JavaScript statements to be executed by the JavaScript engine within the browser context. This is often handy in specifying event handlers for UI controls within the web page. When a browser engine is requested to browse to a JavaScript URL, it will execute the accompanying JavaScript without reloading the DOM. This is a very important feature in modern web browsers. We will use this design pattern to pass parameters from Java across to JavaScript. This is how it is done:

  1. Create a string buffer to represent the JavaScript that you wish to call.
  2. Prepend the JavaScript protocol scheme to this string.
  3. Call loadURL(), passing the string as the argument.

For example, if we wish to display an alert dialog in the WebView, as a result of some Java code execution, we would write something like:

String js = "alert('Alert from Java');";
WebView.loadUrl("JavaScript:" + js);

Opening a WebView in Fullscreen Mode

At times, you may want to display a fullscreen WebView to the user. Although you can request the WebView to cover the entire activity, by default, the activity does not cover the full screen, and you will observe a title bar and a notification bar. You can make an activity a fullscreen activity by either specifying activity flags in the manifest file or by doing it programatically.

Make an activity full screen through AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
        <activity
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
            ...
        </activity>
</manifest>

Or make an activity fullscreen programmatically:

@Override
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.main);
        ...
}

Caution

When you set your activity to fullscreen mode, the resize event is not fired when the soft keyboard comes out in the WebView. We have done numerous experiments to capture the resize event from JavaScript, but with no luck. This could be Android limitation or a bus. This issue has been raised to Android developers at Google. The alternative solution of how to mitigate this issue is addressed in the next section.

Enabling a Resize Event in JavaScript While Your Application Is Fullscreen

To enable a resize event while your application is fullscreen, do the following:

  • Use the res/values/styles.xml file to make your application fullscreen and turn off the window title.
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="Theme" parent="android:Theme.Light">
        <item name="android:textViewStyle">@style/Theme.TextView</item>
        <item name="android:windowTitleStyle">@style/WindowTitle</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowNoTitle">true</item>
    </style>

    <style name="WindowTitle" parent="@android:style/Theme">
        <item name="android:textSize">10sp</item>
        <item name="android:textColor">@android:color/white</item>
    </style>

    <style name="Theme.TextView" parent="@android:style/Widget.TextView">
        <item name="android:textSize">10sp</item>
        <item name="android:textColor">@android:color/black</item>
    </style>

</resources>
  • Apply this theme to your application using the following XML attribute in your manifest.
<application
        android:icon="@drawable/icon"
        android:label="Demo"
        android:theme="@style/Theme" > ... </application>
  • You can now capture the resize event in your HTML.
$(window).bind('resize', function() {
        console.error('onResize');
});

Binding Java Objects to WebView Using the addJavaScriptInterface() Method

The WebView allows developers to extend the JavaScript API namespace by defining their own components in Java and then making them available in the JavaScript environment. This technique comes in handy when you wish to access a platform feature not already available in JavaScript or wish to consume a component written in Java through JavaScript.

The addJavaScriptInterface() method of the WebView can be used for this purpose.

JavaScriptInterface JavaScriptInterface = new JavaScriptInterface(this);
myWebView = new MyWebView(this);
myWebView.addJavaScriptInterface(JavaScriptInterface, "HybridNote");

In this example, JavaScriptInterface is bound to the JavaScript environment of WebView and is accessible using the HybridNote object (aka namespace). Depending upon the Android version, either all public or some special methods of the bound objects will be accessible inside the JavaScript code. Once the object is added to the WebView using the function specified earlier, the object will be available to JavaScript only after the page in the WebView is loaded next or the existing page is reloaded. This can be achieved by calling the loadData() function of the WebView object.

Caution

Although addJavaScriptInterface() is powerful for building hybrid apps, using this method presents a wide range of security issues because the same-origin policy (SOP) does not apply to this method, and third-party JavaScript libraries or an untrusted child iframe from a different domain may access those exposed methods in the Java layer. As a result of this, attackers can take advantage of an XSS vulnerability and execute native code or inject malicious code into your application.

From the JavaScript layer, all the public methods of the exposed Java objects can be accessed in Android versions below Jelly Bean MR1 (API Level - 17). For Jelly Bean MR1 API Level and above, exposed functions should specifically be annotated with @JavaScriptInterface to prevent any unwanted methods from being exposed.

The JavaScript layer does not have direct access to the exposed Java object’s fields. If needed, explicit getters and setters must be provided for accessing the fields.

@JavaScriptInterface Annotations

If you set your targetSdkVersion to 17 (or higher) in AndroidManifest.xml all the methods that are accessed by JavaScript must have @JavaScriptInterface annotations.

import android.WebKit.javaScriptInterface;

// SDK version 17 or above.
@JavaScriptInterface
public void showToast(String toast)  {
        // show toast...
}

In Android 2.3, the addJavaScriptInterface() method does not work as expected. However, given 2.3 is still the most used version of Android, you may want your application to work on 2.3 devices as well.

Developers across the Web have come up with a number of workarounds to take care of this. You can find one such implementation at Android 2.3 WebView’s broken AddJavascriptInterface website.

Another approach is to use an onJsPrompt() callback. Wherein the message or the defaultValue parameter can be used to pass the name of the method to be executed in the native environment along with params.

@Override
public boolean onJsPrompt(WebView view, String url, String message,
        String defaultValue, JsPromptResult result) {

        // Check the url to ensure that the request originated from
        // whitelisted source

        // Check to see if message or defaultValue contain JavaScript request.
        if (defaultValue.startsWith("karura:")) {
                // process the request
        } else{
                // display the confirmation dialog to the user if required
        }

        return trueOrFalse; // based on whether you handled the notification
}

Security Considerations for Hybrid Applications

In Android versions before 4.2 (Jelly Bean, targetSdkVersion 17), the JavaScript layer, upon getting access to the exposed Java object, can access all of the object’s public members using reflection. Reflection is a powerful set of APIs, commonly used by programs that require the ability to examine or modify the runtime behavior of applications running in the Java Virtual Machine.

For platforms before API level 17, you can use reflection inside of JavaScript by calling something like:

function execute(cmdArgs) {
        boundObj.getClass().forName("Java.lang.Runtime").getMethod("getRuntime",
                null).invoke(null,null).exec(cmdArgs);
}

var p = execute(["/data/data/com.yourapp/malicious-app"]);
document.write(getContents(p.getInputStream()));

This could allow an attacker to run malicious Java code in the host application’s context, which could pose a security risk.

As an application developer, care must be taken to ensure that we expose the Java object to WebView only as necessary, especially in the case of running JavaScript from untrusted sources such as external websites and so on.

For increased security, you should also load all the external JavaScript files over the Secure Sockets Layer (SSL) protocol. Any exceptions to this should be explicitly reviewed and approved by you.

HttpOnly Cookies and the Secure Flag

Cookies are one of the most common ways developers store application data. Among other things, it is used to remember the state of the web application in the previous run. Access to this data by untrusted JavaScript could pose a huge risk to your application. To prevent this, you can make your cookies HttpOnly in the HTTP response.

The HttpOnly cookie flag became a standard with the RFC #6265 document that can be found at the ietf.org website.

An HttpOnly flagged cookie cannot be stolen easily via non-HTTP methods, such as JavaScript or Flash using document.cookie as a pervasive attack technique.

Here’s an example of how the HttpOnly attribute is visible in the HTTP headers:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Set-Cookie: id=cdb6352b48e62e0691efe552e3e4cecb; path=/; HttpOnly

If you use the SSL protocol for delivering your web content and need to set cookies using JavaScript, then you need to enable the secure flag in your cookie function in order to set a secure cookie.

document.cookie = "name=value; expires=date; path=path; domain=domain; secure";

Caution

On the Android developer website, there are great tips about WebView security. For additional information, please refer to the Android WebView API website.

Domain Whitelisting

You can create an allowed list of domains that WebView can view if your application needs to navigate to domains outside the expected domain. Just use the shouldOverrideUrlLoading(WebView view, String url) method:

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (!Uri.parse(url).getHost().equals("www.oreilly.com")) {
                return false;
        }
        view.loadUrl(url);
        return true;
}

Caution

However, restricting loading remote resources within the shouldOverrideUrlLoading(WebView view, String url) method does not intercept the requests that are made from IFRAME, XmlHttpRequests Ajax Object, and SRC attributes in HTML tags.

A solution to the problem mentioned in the Warning would be to intercept the request and manually load different content into this view.

@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        if (url.contains(".js")) {
                String str = "alert('This is a replaced JavaScript code.')";
                InputStream is = null;
                try {
                        is = new ByteArrayInputStream(str.getBytes("UTF8"));
                } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                }
                String type = "application/JavaScript";
                return new WebResourceResponse(type, "UTF-8", is);
        }
        return super.shouldInterceptRequest(view, url);
}

Configuring WebView Settings with WebSettings

WebView in Android, provides a very comprehensive configuration interface, WebSettings, which can be used to customize the behavior of the WebView at runtime. The WebSettings object is valid only during the lifecycle of a WebView. In other words, an IllegalStateException will be thrown if you try to access any method from a WebView.getSettings() object if a WebView is already destroyed.

You can retrieve WebSettings with WebView.getSettings() API.

WebView WebView = new WebView(this);
WebSettings settings = WebView.getSettings();

Preventing Local Files from Being Loaded in the WebView

The setAllowFileAccess() API allows developers to control access to local files by the WebView. This API is one of several WebView settings you can configure at runtime. By default, this setting is enabled for accessing files in the filesystem. This setting does not restrict the WebView to load local resources from the file:///android_asset (assets) and file:///android_res (resources) directories. For security reasons, if your app does not require access to the filesystem, it is a good practice to turn this setting off.

settings.setAllowFileAccess(false);

Enabling JavaScript

For security reasons, JavaScript is disabled in the WebView by default. You can enable/disable JavaScript using setJavaScriptEnabled() method.

settings.setJavaScriptEnabled(true);

Note

We suggest that you always include all the JavaScript libraries in the assets directory of your application within your hybrid app.

If you are using third-party JavaScript libraries in your application, eventually, your application will inherit all the bugs and vulnerabilities that may cause undesired situations for your application. Some developers prefer downloading third-party JavaScript from their own web servers to mitigate the risks of being hacked. This allows them to react more quickly than others in removing the malicious code from the web server.

Again, ideally, you should deliver all your JavaScript files within your application.

Turning on some of the WebView settings unnecessarily may result in unexpected behavior in your application. Hence, it is a good practice to turn off features not required by your application.

For example, if you are not using a Flash plug-in, turn it off using the setPluginState(PluginState.OFF) method, which may prevent attackers from compromising your app via third-party plug-ins.

WebView WebView = new WebView(this);
WebSettings settings = WebView.getSettings();
settings.setPluginState(PluginState.OFF);

Note

We encourage you to read the following research papers published by Syracuse University in New York:

Visit the “Attacks on WebView in the Android Systems” article.

Visit the “Touchjacking Attacks on Web in Android, iOS, and Windows Phone” article.

Note

As an Android developer, you should always follow the best practices of different remediation and mitigation strategies for your mobile app.

Setting Default Font Size

By default, the WebKit renders and displays fonts in 16 sp (scale-independent pixels) unit. This unit enables WebView to adjust the font size for both screen density and the user’s preference. If you would like to change the font size to something other than the default size, you can use the setDefaultFontSize() method with the preferred font size value.

WebView WebView = new WebView(this);
WebSettings settings = WebView.getSettings();
settings.setDefaultFontSize(20);

Zoom Controls

Setting the setBuiltInZoomControls() method to false will prevent the built-in zoom mechanisms. Setting this to true will allow the setDisplayZoomControls() method to show onscreen zoom controls. setDefaultZoom(ZoomDensity.FAR) sets the default zoom density of a web page. Setting its value to FAR makes it appear in 240 dpi at 100%. setSupportZoom() with false value will set whether the WebView should support zooming using its onscreen zoom controls and gestures or not.

From the user experience perspective, turning off zooming for the most of the mobile apps will be ideal for many users unless the application features require zooming.

WebView WebView = new WebView(this);
WebSettings settings = WebView.getSettings();
settings.setBuiltInZoomControls(false);
settings.setDefaultZoom(ZoomDensity.FAR);
settings.setSupportZoom(false);

Hardware Acceleration

Android uses some form of hardware accelerated drawing since version 1.0, basically, for compositing windows. However, the local window changes are done in software. Historically, the Android browser used a rendering technique optimized for minimizing errors, not speed of rendering. Starting at version 3.0, Android introduced full hardware acceleration for applications. This is not enabled by default for applications targeted for platforms below version 4.0. The web browser itself moved to a tile-based rendering architecture as opposed to display list architecture, which makes it more responsive.

If you wish to enable hardware acceleration in your application or activity, you can set android:handwareAccelerated="true" in your manifest.

// enable hardware acceleration using code (>= level 11)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    WebView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
settings.setRenderPriority(WebSettings.RenderPriority.HIGH);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);

Warning

If you enable hardware acceleration for your application, make sure you test it. Enabling hardware acceleration has side-effects, the most important one being that it adds a significant amount of memory requirements to your application (approx. 7-8M at minimum). This can have huge impact on low end devices.

Given that the Android ecosystem is so heavily fragmented, it is possible that you may observe issues with hardware-accelerated WebView. To selectively turn off hardware acceleration for your WebView, you can either set it to android:handwareAccelerated="false" for the entire application or the activity hosting the WebView in the application manifest file.

You can achieve the same effect programmatically using the following code:

// selectively disable hardware acceleration for WebView
// honeycomb (3.0) and higher
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        WebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Get Building Hybrid Android Apps with Java and JavaScript now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.