S. Gökhan Topçu
gtopcu@gmail.com
gtopcu@gmail.com
Android has a whole dedicated package; android.webkit.* for embedding web pages or creating HTML-based UIs for your apps. You need to use an android.webkit.WebView widget for the task, and you need to add the permission:
<uses-permission android:name="android.permission.INTERNET" />
to your AndroidManifest.xml if you want your app to be able to access the internet. WebView is based on the modern WebKit engine which powers Chrome, Safari, Android & iOS and webOS browsers. Thus it supports Javascript (though you need to enable it first) and has good support for HTML5. WebViews embedded into Android apps run independent from the main Android browser, so security-sensitive browser data such as cookies and history are completely isolated from each other.
Creating a WebView is the same as any other widget; declare it in your layout and access in your code through its ID.
Loading a web page in WebKit
Let's declare the WebKit widget in our layout file first:
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Important: match_parent was introduced with Android 2.2, for older versions, you need to use fill_parent instead.
As you can see, there's only the android:id attribute and layout parameters required in our layout. Below is a simple Activity using this WebView which loads Google using the loadUrl() method:
code:
output:
package com.ggit.android;
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
public class BrowserActivity extends Activity {
private WebView webView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView)findViewById(R.id.webview);
webView.loadUrl("http://www.google.com");
}
}
output:
![]() |
| Figure 1: Loading Google in Turkish using WebView |
If a WebView is all your activity needs to contain, you can call setContentView(new WebView(this)); instead in your activity's onCreate() method to achieve the same result. Also note that the loadUrl() method does not throw an exception if the web page loads with errors.
As you can see, there are no navigation controls or an address bar by default in a WebView. If you want your users to be able to navigate, you need to create a custom UI, but it is a better idea to actually launch the Android's built-in browser using an Intent such as:
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com")));
You might still decide that you need to use a WebView widget indeed if you're going to show users some static HTML embedded within your project or a single webpage. Or, you might again use a WebView to provide your users a customized browser for a certain activity, to inject Javascript which will interact with your Java code, or put restrictions on user's navigation etc.
You can also clear the WebView cache using clearCache() and clear browsing history using clearHistory() which will remove WebView's internal history; afterwards, there won't be any pages from history to navigate back or forward to.
Below is a simple activity which loads a constant HTML into a WebView using the loadData() method. You can use the same layout file through all of the examples given in this tutorial as we'll only have a WebView widget in our layout.
code:
output:
output:
If you "pinch" the screen, you will also see the zoom controls we activated using setBuiltInZoomControls(true);
output:
If you want to handle javascript events, you need to set the WebView's android.webkit.WebChromeClient in the same manner using the method setWebChromeClient(new CustomChromeClient()); and override the methods for the events you're interested in.
android.webkit.WebView
android.webkit.WebSettings
android.webkit.WebViewClient
android.webkit.WebChromeClient
android.webkit.WebViewFragment
Navigation Control
You can control WebView's navigation through it's methods such as reload(), goBack(), goForward(), goBackOrForward() and check if navigation is possible through canGoForward() and canGoBackOrForward(). These are the same methods you will need to attach to your buttons if you're planning to create a custom navigation UI.You can also clear the WebView cache using clearCache() and clear browsing history using clearHistory() which will remove WebView's internal history; afterwards, there won't be any pages from history to navigate back or forward to.
Loading static HTML into a WebView
You can load static HTML to a WebView widget using the loadData() method. You need to supply a MIME type and encoding along with a String representing your data which you might be a constant value in your class, dynamically generated data, or a complete webpage stored in a file in your project. If you also have Javascript in your HTML, you may need to use loadDataWithBaseURL() instead to get around the "same origin" issue while loading scripts from different urls.
Below is a simple activity which loads a constant HTML into a WebView using the loadData() method. You can use the same layout file through all of the examples given in this tutorial as we'll only have a WebView widget in our layout.
code:
package com.ggit.android;
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
public class BrowserActivity extends Activity {
private WebView webView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView) findViewById(R.id.webview);
webView.loadData(
"<html><body>This is static HTML loaded by WebView</body></html>",
"text/html", "UTF-8");
}
}
output:
![]() |
| Figure 2: WebView loaded with static HTML |
Playing around with the WebView settings
You can get the settings for your WebView by calling the method getSettings() and change the available ones as you require afterwards. Some of the popular settings include enabling Javascript, setting a user agent, setting font size & family, enabling file, database and geolocation accesses and enabling built-in zoom controls which appear when the user "pinches" the screen.
For example, you can set a custom user agent string to "fool" the web page you're loading to think that you're requesting it from a full desktop Google Chrome browser instead of Android using the following code:
webView.getSettings().setUserAgentString("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5");
And below is a modified version of our previous example with more of these settings in action:
package com.ggit.android;
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;
public class BrowserActivity extends Activity {
private WebView webView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView)findViewById(R.id.webview);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setBuiltInZoomControls(true);
settings.setTextSize(WebSettings.TextSize.LARGEST);
//settings.setDefaultFontSize(48);
settings.setFixedFontFamily("sans");
webView.loadData("<html><body>This is static HTML loaded by WebView " +
"using modified settings</body></html>", "text/html", "UTF-8");
}
}
output:
![]() |
| Figure 3: WebView with modified settings using getSettings() method |
If you "pinch" the screen, you will also see the zoom controls we activated using setBuiltInZoomControls(true);
Intercepting links and handling browser events using a WebViewClient
Either from an external webpage or a static file, if you want to to be notified of events such as link clicks, form submissions, web page errors, page loads, authorization requests and so forth, you need to set a custom android.webkit.WebViewClient for your WebView widget. Subclass this class and override the methods for the events you want to track, and set your new custom class as the client for your WebView using setWebViewClient(new CustomClient()); Below is an example of how you can track user clicks and handle them yourself if you want to. You will need to override the method shouldOverrideUrlLoading() which will be called using your WebView widget and the address of the webpage the link has in its "href" attribute. You need to return true if you will be handling the link yourself, otherwise WebView will try to the navigate to the clicked link.
package com.ggit.android;
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
public class BrowserActivity extends Activity {
private WebView webView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView) findViewById(R.id.webview);
webView.setWebViewClient(new CustomClient());
webView.loadData(
"<html><body><a href=\"click\">Click me</a> to see me intercept a link</body></html>",
"text/html", "UTF-8");
}
private class CustomClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.equals("click")) {
Toast.makeText(BrowserActivity.this, "Gotcha!",
Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
}
}
![]() |
| Figure 4: Intercepting links from WebView |
If you want to handle javascript events, you need to set the WebView's android.webkit.WebChromeClient in the same manner using the method setWebChromeClient(new CustomChromeClient()); and override the methods for the events you're interested in.
Calling Java code from Javascript
WebView widget also allows you to call your java code from the javascript embedded in the web page you're loading by setting a javascript interface class using the method addJavascriptInterface(). You need to use this feature with caution though, especially if you don't own the javascript code of the webpage you are trying to load since the script can manipulate your app through all the methods the interface provides.
And needless to say, you also need to enable javascript for the code below to work :)
code:
package com.ggit.android;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.webkit.WebView;
import android.widget.Toast;
public class BrowserActivity extends Activity {
private WebView webView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView) findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new CustomInterface(this), "interface");
webView.loadData("<html>"
+ "<script type=\"text/javascript\"> "
+ " function showToast(toast) { "
+ " interface.showToast(toast); "
+ " } "
+ "</script> "
+ "<body><input type=\"button\" value=\"Show Toast\" onClick=\"showToast('Gotcha!')\"</body>"
+ "</html>", "text/html", "UTF-8");
}
private class CustomInterface {
Context context;
CustomInterface(Context context) {
this.context = context;
}
//Annotation required if minSdkVersion or targetSdkVersion is 17 or higher
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(context, "Javascript: " + toast, Toast.LENGTH_SHORT)
.show();
}
}
}
![]() |
| Figure 5: Calling Java from Javascript inside a WebView |
Screen sizes, CSS and DOM
By default, a WebView widget will assume the webpage you are loading is built for a medium-density (mdpi) screen and scales it when it's run on different densities; shrinking for smaller densities and enlarges for larger ones by using predefined factors. Starting with Android 2.0 (API 5), WebView supports CSS and DOM along with custom tags, so you can use these in your webpage and change the default scaling behavior by using the predefined DOM property: window.devicePixelRatio. Check the javadocs if you need such control over your WebView.
Fragments and WebView
Android team introduced the new android.webkit.WebViewFragment with Android 3.0 (API 11 - Honeycomb) which constructs a WebView and sets it as the fragment's layout automatically, and pauses/resumes it simultaneously with the fragment itself. Unfortunately, this fragment is not available in the v4 support library (Android Compatibility Library) so you need to be targeting Android devices with a minimum API 11 version (<uses-sdk android:minSdkVersion="11"/>) and use Android SDK 11 or higher to be able to use this fragment.
Further Reading:
API Guides: Building Web Apps using WebViewandroid.webkit.WebView
android.webkit.WebSettings
android.webkit.WebViewClient
android.webkit.WebChromeClient
android.webkit.WebViewFragment





No comments:
Post a Comment
Please leave your feedback below if you found this blog useful, thanks.