Android的WebView是基于webkit内核的,WebView中集成了JS与Java互调的接口函数,通过addJavascriptInterface(Object obj, String interfaceName)方法,可以将Java的类注册进webkit,给网页上的JS进行调用,而且还可以通过loadUrl(String url)方法是给webkit传递一个uri,供浏览器来进行解析,实现Java和JS方法的交互。
更多详细的文档介绍可以参考Android Developers中关于WebView的详细介绍,链接如下:http://developer.android.com/guide/webapps/webview.html
这里列举一个简单的例子来示例一下WebView与JS之间的交互流程,如有写的不足的地方,欢迎大家拍砖!
WebViewDemo 源代码如下:
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
public class WebViewDemo extends Activity {
public static final String TAG = WebViewDemo.class.getSimpleName();
private Handler mHandler = new Handler();
private WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
super.onCreate(savedInstanceState);
initView();
}
@SuppressLint("SetJavaScriptEnabled")
private void initView() {
mWebView = (WebView) findViewById(R.id.mWebView);
//WebSettings 几乎浏览器的所有设置都在该类中进行
WebSettings webSettings = mWebView.getSettings();
webSettings.setSavePassword(false);
webSettings.setSaveFormData(false);
webSettings.setJavaScriptEnabled(true);
webSettings.setSupportZoom(false);
mWebView.setWebViewClient(new MyWebViewClient());
mWebView.setWebChromeClient(new MyWebChromeClient());
/*
* DemoJavaScriptInterface类为js调用android服务器端提供接口
* android 作为DemoJavaScriptInterface类的客户端接口被js调用
* 调用的具体方法在DemoJavaScriptInterface中定义:
* 例如该实例中的clickOnAndroid
*/
mWebView.addJavascriptInterface(new DemoJavaScriptInterface(),"Android");
mWebView.loadUrl("file:///android_asset/page.html");
}
/**
* 继承WebViewClient类,对WebView中页面开始加载、页面加载完毕、页面加载出错、url拦截等事件的处理
* @author Bingbing Feng
*
*/
final class MyWebViewClient extends WebViewClient{
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.i(TAG, "shouldOverrideUrlLoading url="+url);
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.i(TAG, "onPageStarted url="+url);
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
Log.i(TAG, "onPageFinished url="+url);
super.onPageFinished(view, url);
}
@Override
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
Log.e(TAG, "onReceivedError errorCode="+errorCode);
super.onReceivedError(view, errorCode, description, failingUrl);
}
}
/**
* 继承WebChromeClient类,对js弹出框事件进行处理
* @author Bingbing Feng
*
*/
final class MyWebChromeClient extends WebChromeClient {
@Override
public void onProgressChanged(WebView view, int newProgress) {
Log.i(TAG, "onProgressChanged newProgress="+newProgress);
super.onProgressChanged(view, newProgress);
}
@Override
public boolean onJsAlert(WebView view, String url, String message,
JsResult result) {
Log.i(TAG, "onJsAlert message="+message);
//对alert的简单封装
new AlertDialog.Builder(WebViewDemo.this).
setTitle("Alert").setMessage(message)
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
})
.create().show();
result.confirm(); //一定不能少
return true;
}
@Override
public boolean onJsConfirm(WebView view, String url, String message,
JsResult result) {
Log.i(TAG, "onJsAlert message="+message);
return super.onJsConfirm(view, url, message, result);
}
@Override
public boolean onJsPrompt(WebView view, String url, String message,
String defaultValue, JsPromptResult result) {
Log.i(TAG, "onJsAlert message="+message);
return super.onJsPrompt(view, url, message, defaultValue, result);
}
}
final class DemoJavaScriptInterface {
DemoJavaScriptInterface() {}
/**
* 该方法被浏览器端调用
* Caution: If you've set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface
*/
@JavascriptInterface
public void clickOnAndroid() {
mHandler.post(new Runnable() {
public void run() {
//native调用js中的onJsAndroid方法
mWebView.loadUrl("javascript:onJsAndroid()");
}
});
}
/** JS调用native方法显示一个Toast */
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(getApplicationContext(), toast, Toast.LENGTH_SHORT).show();
}
}
}
绑定一个回调的代理类JavaScriptInterface,并给它一个调用的名称Android
mWebView.addJavascriptInterface(new DemoJavaScriptInterface(),"Android");
WebView addJavascriptInterface(Object obj, String interfaceName) 为javascript提供一个回调的接口,这里要注意,一定要在单独的线程中实现,要不会阻塞线程的。
addJavascriptInterface(Object obj, String interfaceName) 中obj代表一个java对象,这里我们一般会实现一个自己的类,类里面提供我们要提供给javascript访问的方法,interfaceName则是访问我们在obj中声明的方法时候所用到的js对象,调用模式为window.interfaceName.方法名()。
通过Log信息我们会发现回调接口中的方法(Obj 对象中提供给javascript访问的方法)运行在一个名为WebViewCoreThread的线程中,而不是main线程(UI线程),如果回调方法中需要执行某些耗时操作,建议在一个新的线程中去执行这些耗时操作。
Java调用HTLM页面中的JS方法,只需知道JS的方法名称即可:
mWebView.loadUrl("javascript:onJsAndroid()");
WebView与JS方法交互
到这里WebView与JS的交互就已经完成了,大家可以动手实验一下!