在移动App开发中,为了快速迭代,通常都会使用Native+Web的模式开发。具体来说就是使用Java提供接口,使用WebView控件嵌套Web页面来实现UI和交互。
在Android中,Java可以很方便的提供接口给WebView中的Js进行调用,只要以下一行代码就能搞定:
Java
1 |
mWebView.addJavascriptInterface( new JavascriptInterface(), "custom_name" );
|
这样,JavascriptInterface的所有声明为public的方法,都能被mWebView中的Js通过以下方式调用:
JavaScript
1 |
window.custom_name.xxx(); //xxx为JavascriptInterface的公有方法
|
而Java需要调用Js时,则是通过WebView实例的loadUrl方法调用:
Java
1 |
mWebView.loadUrl( "javascript:xxx(yyy)" );
|
这其实跟你在浏览器的地址栏敲下“javascript:alert(1)”的原理是一样的。
一切看起来都是那么的美好,只是……
当Java需要传递大量字符串给Js时,URL就力不从心了。另外,从URL执行的Js,在页面没加载完成时,是有可能导致页面出现undefined错误(因为要执行的那个方法可能还没有声明呢),会引发各种奇形怪状的错误。
那要怎么办呢?
再回看上面Js调用Java接口的地方,可以发现,Js是可以直接调用Java方法并取得Java给的返回值的(必须是可序列化的数据)。那么,为何不试试把Java需要执行的Js方法,保存起来,让Js来读取、执行、并把结果写回?
步骤如下:
- Java把Js调用(命令)和回调缓存,如保存到ArrayList;
- Js定时轮询Java提供的getCommandList接口;
- Js读取到要执行命令,执行它,并把结果通过setResult写回给Java;
- Java把对应命令的回调取出并执行。
如此即完成了Java调用Js的流程。
为了方便使用,简单的封装了下,名为AndroidJavascriptBridge,可移步到Github查看源码和示例(MainActivity.java和test.js )。
使用方法
Android端调用, 加入com.imatlas.jsb 和 com.imatlas.util包, 按如下步骤调用
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 |
//1. 创建JavascriptBridge实例
final JavascriptBridge jsb = new JavascriptBridge(webView);
//2. 调用Javascript方法
Bundle params = new Bundle();
params.putString( "asdfasdf" , "123123" );
jsb.require( "alert" , params, new JavascriptBridge.Callback() {
@Override
public void onComplate(JSONObject response, String cmd, Bundle params) {
Log.i( "js response" ,response.toString());
}
});
//3. 提供Java方法给Javascript调用
//添加个 messagebox 方法给js
jsb.addJavaMethod( "messagebox" , new JavascriptBridge.Function() {
@Override
public Object execute(JSONObject params) {
Toast.makeText(getApplicationContext(), params.toString(), Toast.LENGTH_LONG)
.show();
return "{"ret":123}" ;
}
});
|
Javascript端的调用, 须先引入web/js/jsb.js, 之后按如下方式调用
Javascript
1
2
3
4
5
6
7
8
9
10 |
//1. 调用Java方法
jsb.require( 'messagebox' , { 'text' : '你好, messagebox!' }, function (response){
alert( '调用messagebox回来啦n' + JSON.stringify(response));
});
//2. 提供Javascript方法给Java调用
jsb.addJavascriptMethod( 'alert' , function (params){
alert( '------n' + JSON.stringify(params) + 'n========n' );
return { 'text' : 'alert ok' };
});
|
IOS的话就要反过来了,要改成由Objective-C来轮询Js,来实现Js对Native的调用。
嗯,等改天有时间了,就把IOS也封装进来,用起来就简单多了。
本文转自TAT.iAzrael的个人博客,地址:http://www.alloyteam.com/2013/02/java-with-javascript-more-intimate/ |