Other GUI toolkits let you use HTML for presenting information, from limited HTML renderers (e.g., Java/Swing and wxWidgets) to embedding Internet Explorer into .NET applications. Android is much the same, in that you can embed the built-in web browser as a widget in your own activities, for displaying HTML or full-fledged browsing. The Android browser is based on WebKit, the same engine that powers web browsers such as Apple’s Safari and Google’s Chrome.
The Android browser is sufficiently complex that it gets its own Java package (android.webkit
). Using the WebView
widgetitself can be simple or powerful, based on your requirements.
For simple stuff, WebView
is not significantly different from any other widget in Android—pop it into a layout, tell it which URL to navigate to via Java code, and you are finished.
For example, here is a simple layout with a WebView
(from WebKit/Browser1
):
<?xml version="1.0" encoding="utf-8"?>
<WebViewxmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webkit"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
As with any other widget, you need to tell it how it should fill up the space in the layout (in this case, it fills all remaining space).
The Java code is equally simple:
package com.commonsware.android.browser1;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.webkit.WebView;
public class BrowserDemo1 extends Activity {
WebView browser;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
browser=(WebView)findViewById(R.id.webkit);
browser.loadUrl("http://commonsware.com");
}
}
The only thing unusual with this edition of onCreate()
is that we invoke loadUrl()
on the WebView
widget, to tell it to load a web page (in this case, the home page of some random firm).
However, we also need to make one change to AndroidManifest.xml
, requesting permission to access the Internet:
<?xml version="1.0"?>
<manifestxmlns:android="http://schemas.android.com/apk/res/android"
package="com.commonsware.android.browser1">
<uses-permission android:name="android.permission.INTERNET"/>
<applicationandroid:icon="@drawable/cw">
<activityandroid:name=".BrowserDemo1" android:label="BrowserDemo1">
<intent-filter>
<actionandroid:name="android.intent.action.MAIN"/>
<categoryandroid:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
<supports-screens android:largeScreens="true"
android:normalScreens="true" android:smallScreens="true" android:anyDensity="true"/>
</manifest>
If we fail to add this permission, the browser will refuse to load pages. Permissions will be covered in greater detail in Chapter 38.
The resulting activity looks like a web browser, but with hidden scrollbars, as shown in Figure 15–1.
As with the regular Android browser, you can pan around the page by dragging it, while the D-pad moves you around all the focusable elements on the page. What is missing is all the extra stuff that make up a web browser, such as a navigational toolbar.
Now, you may be tempted to replace the URL in that source code with something that relies on JavaScript, such as Google’s home page. By default, JavaScript is turned off in WebView
widgets. If you want to enable JavaScript, call getSettings().setJavaScriptEnabled(true);
on the WebView
instance. This option is covered in a bit more detail later in this chapter.
There are two main ways to get content into the WebView
. One, described in the previous section, is to provide the browser with a URL and have the browser display that page via loadUrl()
. The browser will access the Internet through whatever means are available to that specific device at the present time (Wi-Fi, 2G, 3G, 4G, WiMAX, EDGE, HSDPA, HSPA, well-trained tiny carrier pigeons, etc.).
The alternative is to use loadData()
. Here, you supply the HTML for the browser to view. You might use this to do the following:
There are two flavors of loadData()
. The simpler one allows you to provide the content, the MIME type, and the encoding, all as strings. Typically, your MIME type will be text/html
and your encoding will be UTF-8
for ordinary HTML.
For example, you could replace the loadUrl()
invocation in the previous example with the following:
browser.loadData("<html><body>Hello, world!</body></html>",
"text/html", "UTF-8");
You would get the result shown in Figure 15–2.
This is also available as a fully buildable sample, as WebKit/Browser2
.
As previously mentioned, the WebView
widget doesn’t have a navigation toolbar. This allows you to use it in places where such a toolbar would be pointless and a waste of screen real estate. That being said, if you want to offer navigational capabilities, you can, but you have to supply the UI.
WebView
offers ways to perform garden-variety browser navigation, including the following methods:
reload()
: Refreshes the currently viewed web pagegoBack()
: Goes back one step in the browser historycanGoBack()
: Determines if there is any history to go back togoForward()
: Goes forward one step in the browser historycanGoForward()
: Determines if there is any history to go forward togoBackOrForward()
: Goes backward or forward in the browser history, where a negative number as an argument represents how many steps to go backward, and a positive number represents how many steps to go forwardcanGoBackOrForward()
: Determines if the browser can go backward or forward the stated number of steps (following the same positive/negative convention as goBackOrForward()
)clearCache()
: Clears the browser resource cacheclearHistory()
: Clears the browsing historyIf you are going to use the WebView
as a local UI (versus browsing the Web), you will want to be able to get control at key times, particularly when users click links. You will want to make sure those links are handled properly, either by loading your own content back into the WebView
, by submitting an Intent
to Android to open the URL in a full browser, or by some other means (see Chapter 22).
Your hook into the WebView
activity is via setWebViewClient()
, which takes an instance of a WebViewClient
implementation as a parameter. The supplied callback object will be notified of a wide range of events, from when parts of a page have been retrieved (onPageStarted()
, etc.) to when you, as the host application, need to handle certain user- or circumstance-initiated events, such as onTooManyRedirects()
or onReceivedHttpAuthRequest()
.
A common hook will be shouldOverrideUrlLoading()
, where your callback is passed a URL (plus the WebView
itself), and you return true
if you will handle the request or false
if you want default handling (e.g., actually fetch the web page referenced by the URL). In the case of a feed reader application, for example, you will probably not have a full browser with navigation built into your reader. In this case, if the user clicks a URL, you probably want to use an Intent
to ask Android to load that page in a full browser. But if you have inserted a “fake” URL into the HTML, representing a link to some activity-provided content, you can update the WebView
yourself.
As an example, let’s amend the first browser demo to make it an application that, upon a click, shows the current time. From WebKit/Browser3
, here is the revised Java:
public class BrowserDemo3 extends Activity {
WebView browser;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
browser=(WebView)findViewById(R.id.webkit);
browser.setWebViewClient(new Callback());
loadTime();
}
void loadTime() {
String page="<html><body><a href="clock">"
+new Date().toString()
+"</a></body></html>";
browser.loadData(page, "text/html", "UTF-8");
}
private class Callback extends WebViewClient {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
loadTime();
return(true);
}
}
}
Here, we load into the browser (loadTime()
) a simple web page that consists of the current time, made into a hyperlink to the /clock
URL. We also attach an instance of a WebViewClient
subclass, providing our implementation of shouldOverrideUrlLoading()
. In this case, no matter what the URL, we want to just reload the WebView
via loadTime()
.
Running this activity gives the result shown in Figure 15–3.
Selecting the link and clicking the D-pad center button will “click” the link, causing the page to be rebuilt with the new time.
With your favorite desktop web browser, you have some sort of settings, preferences, or options window. Between that and the toolbar controls, you can tweak and twiddle the behavior of your browser, from preferred fonts to the behavior of JavaScript. Similarly, you can adjust the settings of your WebView
widget as you see fit, via the WebSettings
instance returned from calling the widget’s getSettings()
method.
There are lots of options on WebSettings
to play with. Most appear fairly esoteric (e.g., setFantasyFontFamily()
). However, here are some that you may find more useful:
setDefaultFontSize()
(to use a point size) or setTextZoom()
(to use constants indicating relative sizes like LARGER
and SMALLEST
)setJavaScriptEnabled()
(to disable it outright) and setJavaScriptCanOpenWindowsAutomatically()
(to merely stop it from opening pop-up windows)setUserAgent()
, so you can supply your own user agent string to make the web server think you are a desktop browser, another mobile device (e.g., an iPhone), or whatever