很多时候需要在原生App中嵌入Webview,同时在Webview中处理一些事件的时候,js可能不能完全满足需求,这时候就需要通过js来调用 java的代码。
使用js调用java代码,其实是Android原生支持的,可以看这里的官方文档(翻墙) 。Webview提供了一层从从 js代码到java原生代码的映射。
定义接口:
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
定义js-java映射:
WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
在js中调用代码:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" / >
<script type="text/javascript" >
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script >
上面提供的原生做法在Android的某些版本上是有问题的,另外还存在一些安全问题。在PhoneGap的代码中提供了一种实现思路, 它自己实现了js-java的映射。具体是在webview中发起一个js的事件(js代码),然后再WebChromeClient(原生代码)中处 理这个事件。
定义接口:
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
通过拦截js事件,实现js-java的映射:
final class MyWebChromeClient extends WebChromeClient {
WebAppInterface wai;
MyWebChromeClient(Context ctx){
wai = new WebAppInterface(ctx);
}
public boolean onJsPrompt(WebView view, String url, String message, String value, JsPromptResult result){
if("toast".equals(message)){
wai.showToast(value);
}
return true;
}
}
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebChromeClient(new MyWebChromeClient(activity));
在js中调用代码:
<script type="text/javascript">
function showToast(msg) {
prompt("toast", msg);
}
</script>
<a onClick="showToast('click')"> SimpleEvent</a>
上面代码的实现思路是这样的,js代码中的showToast方法会调用 prompt 函数,并且传递了两个参数(其实prompt是js中的一个方法 ,调用这个方法之后会显示一个包含输入框的对话框,第一个参数是对话框的消息,第二个参数是对话框中输入框的内容)。这个js事件 会被自己实现的 MyWebChromeClient 捕获,然后判断消息是不是”toast”,如果是就调用 WebAppInterface 的 showToast 方法。
对于这个实现,需要小心的定义prompt函数的第一个参数,避免不小拦截到了非自己定义的消息。
PS:由于Android原生实现的一些瑕疵,所以在友盟的统计组件中得实现是采用第二种方式。
nTop 30 December 2014