一、引言
WebView(网络视图)作用相当于一个迷你的浏览器,采用Webkit内核,因此完美支持html,javascript,css等。有时候,我们完 全可以把UI甚至数据处理都交给WebView,配合PHP等服务端程序,这样Android开发就变成了网页开发,可以省很多精力。目前很多android app都内置了可以显示web页面的界面,会发现这个界面一般都是由一个叫做WebView的组件渲染出来的,学习该组件可以为你的app开发提升扩展性。网上有很多介绍WebView相关的文章,我个人觉得比较好的一篇推荐给大家:Android WebView使用深入浅出 ,我在这里主要介绍Java代码怎么跟web通信。
二、WebView的使用说明
WebView是View的一个子类,可以让你在activity中显示网页。 在布局文件中写入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="wrap_content"
android:layout_height="wrap_content"
/>
加载一个网页,使用loadUrl():
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.baidu.com");
由于要访问网络,所以要在manifest中加上访问网络的权限:
<manifest ... >
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
这个时候发现一个问题,启动应用后,自动的打开了系统内置的浏览器,解决这个问题需要为webview设置 WebViewClient,并重写方法:
webview.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
WebViewClient就是帮助WebView处理各种通知、请求事件,比如自己定义了一个页面加载进度的progressbar,需要展示给用户的时候,可以通过如下方式获取webview内页面的加载进度:
webview.setWebChromeClient(new WebChromeClient(){
@Override
public void onProgressChanged(WebView view, int newProgress) {
//get the newProgress and refresh progress bar
}
});
每个页面,都有一个标题,比如www.baidu.com这个页面的title即“百度一下,你就知道”,那么如何知道当前webview正在加载的页面的title呢:
webview.setWebChromeClient(new WebChromeClient(){
@Override
public void onReceivedTitle(WebView view, String title) {
titleview.setText(title);//a textview
}
});
总之通过这个接口可以干自己的一些事, WebViewClient就是帮助WebView处理各种通知、请求事件
//设置WebViewClient
webView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
});
这个WebViewClient对象是可以自己扩展的,比如:
private class MyWebViewClient extends WebViewClient {
/*
*为了继续在WebView中显示,需要重写shouldOverrideUrlLoading方法
*默认返回:return super.shouldOverrideUrlLoading(view, url);
* 这个返回的方法会调用父类方法,也就是跳转至手机浏览器。
*返回true:webview处理url是根据程序来执行的。
*返回false:webview处理url是在webview内部执行。
*/
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().equals("www.baidu.com")) {
return false;
}
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
之后,我们就可以设置自己定义的WebViewClient了:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());
另外,在WebViewClient中常用的方法:
- doUpdateVisitedHistory(WebView view, String url, boolean isReload); //更新历史记录
- onFormResubmission(WebView view, Message dontResend, Message resend); //重新请求网页数据
- onLoadResource(WebView view, String url); //加载指定网址提供的资源
- onPageFinished(WebView view, String url); //网页加载完毕
- onPageStarted(WebView view, String url, Bitmap favicon); //网页开始加载
- onReceivedError(WebView view, int errorCode, String description, String failingUrl); //加载页面出错
三、Android中java与web的通信
Android中Java与web通信不是新的技术了,在android发布之初就支持这种方式,这里我只是对android中的Java与web通信方式做一下总结。Android中有3种方式可以实现Java与web通信。
- 重写WebViewClient
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().equals("www.demo.com")) {
// This is my web site, so do not override; let my WebView load the page
Toast.makeText(WebViewClientActivity.this, url, Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
}
通过shouldOverrideUrlLoading(WebView view, String url)返回的url获取数据,例如:url=“www.example.com?body=loadurl” 可以截取后面的body数据。
在web中调用方式:
<button onclick="window.open('www.demo.com?body=loadurl)">showTestToast</button>
2、重写WebChromeClient
final class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("MyWebChromeClient", message);
Toast.makeText(OnJsPromptActivity.this, message, Toast.LENGTH_SHORT).show();
result.confirm();
return true;
}
@Override
public boolean onJsConfirm(WebView view, String url, String message,
JsResult result) {
// TODO Auto-generated method stub
return super.onJsConfirm(view, url, message, result);
}
@Override
public boolean onJsPrompt(WebView view, String url, String message,
String defaultValue, JsPromptResult result) {
Toast.makeText(OnJsPromptActivity.this, message, Toast.LENGTH_SHORT).show();
// TODO Auto-generated method stub
//return super.onJsPrompt(view, url, message, defaultValue, result);
result.confirm();
return true;
}
}
使用onJsAlert或者onJsPrompt,onJsAlert,onJsPrompt分别对应JS中的alert和prompt。
在web中调用方式:
<button onclick="showTestToast('Hello Android!');">showTestToast</button>
<script type="text/javascript">
function showTestToast(toast) {
prompt('js prompt');
}
</script>
3、addJavascriptInterface
mWebView.addJavascriptInterface(new WebAppInterface(this), "Android");
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
addJavascriptInterface是Android提供的方法,包含两个参数。第一个是java中实现的类,类提供了javascript访问方法;第二个参数是java类映射到javascript的对象名。
在web中调用方式:
<button onclick="showTestToast('addjavascriptinterface');">showTestToast</button>
<script type="text/javascript">
function showTestToast(toast) {
Android.showToast(toast);
}
</script>
三种方法中后两种用的比较多。但是第三种方法在Android4.2一下存在安全漏洞,这种漏洞尤为在访问第三方地址时出现。在Android 4.2以上的,google作了修正,通过在Java的远程方法上面声明一个@JavascriptInterface。Android4.2以下还没有好的方法,只能限制访问特定地址实现安全。