通过WebView控件,我们可以在安卓客户端中开发一个Web应用或只是加载一个Web页面。WebView类继承了Android的View类,因此可以在activity的布局中展示Web网页。WebView控件本身并没有实现Web浏览器的所有特性,比如导航控制或地址栏。默认地,WebView做的只是展示Web网页。WebView的一个通常的使用场景是,对于篇幅较长且需要更新的信息,比如用户协议或用户指南,我们就可以通过在Activity的布局中使用WebView来展示上述类型的在线文档。另外一个使用场景是,对于经常需要通过Internet连接来获取的信息,比如邮件,通过使用WebView控件将更加方便地向用户展示所需要的信息,而不是发起一个网络请求获取数据后再解析展示在其他控件中。这个时候,我们只需要控制我们的网页适配安卓设备的屏幕以被WebView控件加载即可。
WebView控件的基本用法
要使用WebView控件,我们需要在布局文件中添加<WebView>标签,下面是一个示例:
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
上面例子中的WebView控件占据了全部的屏幕。在代码中我们通过WebView类的loadUrl()方法来加载网页,如下例所示:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");
当然,要使WebView控件正常加载网页,我们需要加*问网络的权限:
<uses-permission android:name="android.permission.INTERNET" />
在WebView中使用JavaScript脚本
WebView默认是没有开启JavaScript脚本的,我们需要通过WebView关联的WebSettings类来进行设置。WebSettings对象可以通过WebView类的getSettings()方法来获取,然后再调用WebSettings类的setJavaScriptEnabled()方法,如下面的示例所示:
WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
通过WebSettings类可以对WebView做各种有用的设置。比如,如果我们的网页只供我们的安卓应用来请求加载,我们就可以通过WebSettings类的setUserAgentString()方法来定义一个特殊的用户代理字符串,这样我们就可以在网页中检测只有来自我们的安卓应用的网页加载请求才会得到处理。
JavaScript脚本和Android代码的通信
我们可以以接口的形式在JavaScript代码和Android代码之间进行交互。比如,在JavaScript脚本中调用Android的Dialog控件,而不使用JavaScript的alert()函数来展示一个对话框。
通过WebView的addJavascriptInterface()方法,我们就可以传递一个对象到网页*JavaScript脚本调用。在下面的代码中,我们定义了一个类作为接口供JavaScript脚本调用:
public class WebAppInterface
{
/** 接口类中需要保持一个Context的引用 */
Context mContext;
WebAppInterface(Context c)
{
mContext = c;
}
/** 在网页中展示一个Android Toast信息*/
@JavascriptInterface
public void showToast(String toast)
{
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
需要注意的是,如果你的Android SDK版本在17及以上,需要在JavaScript脚本调用到的方法上加上@JavascriptInterface注解(当然,该方法也必须是public的),如果没有加上该注解,该方法将在Android 4.2及以上的版本中无法访问。
上面的例子中,WebAppInterface类提供了一个在网页中创建Android Toast信息的showToast()方法。在Android代码中,我们可以像下面的示例所示将该类的对象传递到网页上:
WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
然后在网页代码中我们就可以像下面的示例所示来使用该对象:
<input type="button" value="Say hello" onClick="showAndroidToast(‘Hello Android!‘)" />
<script type="text/javascript">
function showAndroidToast(toast)
{
Android.showToast(toast);
}
</script>
从上面的例子我们可以看出,addJavascriptInterface方法的第二个参数则为在JavaScript脚本中使用该对象的变量名。需要说明的是,JavaScript脚本对该对象的调用并非在该对象被创建的线程中而是运行在另外一个线程中。此外,允许JavaScript脚本调用我们程序的对象时,需要特别谨慎,因为这可能存在着安全问题,因此要确保我们应用加载的HTML和JavaScript是可信的。同样地,对于应用中加载的网页里的链接也要确保是可信的来源才能允许用户点击跳转。
网页导航的处理
默认情况下,当用户点击了WebView加载的网页中的链接时,安卓会自动启动系统默认的浏览器来加载该链接。但是,我们可以覆写这种默认的行为,使用我们的WebView来加载链接。这样,WebView会为我们维护用户的网页访问记录,从而我们就可以实现一种导航的功能。我们需要通过WebView的setWebViewClient()方法来提供一个WebViewClient的对象来打开用户点击的链接,示例如下:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());
这样,我们应用中用户点击的所有链接就可以被WebView所加载。如果我们需要对用户点击的链接进行更多的控制,我们可以构造一个自定义的WebViewClient并覆写它的shouldOverrideUrlLoading()方法,如下面的示例所示:
private class MyWebViewClient extends WebViewClient
{
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
//如果是可信的来源,则返回false,使用我们定义的WebView来加载页面
if (Uri.parse(url).getHost().equals("www.example.com"))
{
return false;
}
//否则,启动一个Android系统定义的专门用来处理URL的Activity来处理该链接
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
然后我们可以这样来使用:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());
这样,当用户点击一个链接时,系统就会调用shouldOverrideUrlLoading()方法,首先检测该URL是否为我们指定的域,如果匹配的话则返回false告诉系统使用我们的WebView来加载该链接。不匹配则会创建一个新的Intent启动系统默认的Activity来处理该URL,通常是调用用户设备默认的浏览器来进行处理。
网页历史导航
当使用WebView来加载网页时,WebView会自动收集用户的网页访问记录,这样我们就可以使用WebView的goBack()和goForward()方法在进行网页的导航。下面的示例中,我们使用了设备的Back按键来进行向后导航:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
//检测是否为 Back键以及是否存在网页的历史记录
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack())
{
myWebView.goBack();
return true;
}
//否则,将事件交由系统处理,通常是退出应用
return super.onKeyDown(keyCode, event);
}
如果存在用户访问的网页历史记录,WebView的canGoBack()方法则会返回true。canGoForward()方法与此类似。如果我们不做这样的检测,一旦网页记录到了结尾,goBack()或goForward()方法将会什么也不做。这通常并不是我们想要的结果。