



_handleMessageFromNative: function (info) {
var arg = JSON.parse(info.data);
var ret = {
id: info.callbackId,
complete: true
}
var f = this._dsf[info.method];
var af = this._dsaf[info.method]
var callSyn = function (f, ob) {
ret.data = f.apply(ob, arg)
bridge.call("_dsb.returnValue", ret)
}
var callAsyn = function (f, ob) {
arg.push(function (data, complete) {
ret.data = data;
ret.complete = complete!==false;
bridge.call("_dsb.returnValue", ret)
})
f.apply(ob, arg)
}
if (f) {
callSyn(f, this._dsf);
} else if (af) {
callAsyn(af, this._dsaf);
} else {
//with namespace
var name = info.method.split('.');
if (name.length<2) return;
var method=name.pop();
var namespace=name.join('.')
var obs = this._dsf._obs;
var ob = obs[namespace] || {};
var m = ob[method];
if (m && typeof m == "function") {
callSyn(m, ob);
return;
}
obs = this._dsaf._obs;
ob = obs[namespace] || {};
m = ob[method];
if (m && typeof m == "function") {
callAsyn(m, ob);
return;
}
}
}
首先通过json解析传入的参数,然后判断是异步处理还是同步处理,异步还是同步主要根据传入的方法名,syn.xxx表示就是同步方法,asyn表示就是异步方法,最后关键的就是调用返回方法了


js调用android中的方法
首先对于dWebview来说,他只认识一个javainterface,因为再dWebView的init方法中,只通过webview的addJavascriptInterface添加了一个一个interface,所以在web页面中调用android这边的方法,始终是通过这个_dsbridge.xxx的形式进行调用,




call: function (method, args, cb) {
var ret = '';
if (typeof args == 'function') {
cb = args;
args = {};
}
var arg={data:args===undefined?null:args}
if (typeof cb == 'function') {
var cbName = 'dscb' + window.dscb++;
window[cbName] = cb;
arg['_dscbstub'] = cbName;
}
arg = JSON.stringify(arg)
//if in webview that dsBridge provided, call!
if(window._dsbridge){
ret= _dsbridge.call(method, arg)
}else if(window._dswk||navigator.userAgent.indexOf("_dsbridge")!=-1){
ret = prompt("_dsbridge=" + method, arg);
}
return JSON.parse(ret||'{}').data
}
这个方法有三个参数,第一个是js要调用android这边的方法名称,第二个是调用这个方法需要的参数,第三个是回调函数,注意,这个回调函数一般只需要在异步调用中进行赋值,用来接收异步结果,然后 会做个判断,如果args也是函数类型的话,就是默认处理空参数有回调的方式。然后回调的执行方式是这样的,首先将回调注册到web页面的windows属性中,然后将注册的名称存放到args的json数组中,然后去调用唯一注册的js接口中的call方法
public String call(String methodName, String argStr) {
String error = "Js bridge called, but can't find a corresponded " +
"JavascriptInterface object , please check your code!";
String[] nameStr = parseNamespace(methodName.trim());
methodName = nameStr[1];
Object jsb = mJavaScriptNamespaceInterfaceMap.get(nameStr[0]);
JSONObject ret = new JSONObject();
try {
ret.put("code", -1);
} catch (JSONException e) {
e.printStackTrace();
}
if (jsb == null) {
PrintDebugInfo(error);
return ret.toString();
}
Object arg = null;
Method method = null;
String callback = null;
try {
JSONObject args = new JSONObject(argStr);
if (args.has("_dscbstub")) {
callback = args.getString("_dscbstub");
}
if (args.has("data")) {
arg = args.get("data");
}
} catch (JSONException e) {
error = String.format("The argument of \"%s\" must be a JSON object string!", methodName);
PrintDebugInfo(error);
e.printStackTrace();
return ret.toString();
}
Class<?> cls = jsb.getClass();
boolean asyn = false;
try {
method = cls.getMethod(methodName,
new Class[]{Object.class, CompletionHandler.class});
asyn = true;
} catch (Exception e) {
try {
method = cls.getMethod(methodName, new Class[]{Object.class});
} catch (Exception ex) {
}
}
if (method == null) {
error = "Not find method \"" + methodName + "\" implementation! please check if the signature or namespace of the method is right ";
PrintDebugInfo(error);
return ret.toString();
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
JavascriptInterface annotation = method.getAnnotation(JavascriptInterface.class);
if (annotation == null) {
error = "Method " + methodName + " is not invoked, since " +
"it is not declared with JavascriptInterface annotation! ";
PrintDebugInfo(error);
return ret.toString();
}
}
Object retData;
method.setAccessible(true);
try {
if (asyn) {
final String cb = callback;
method.invoke(jsb, arg, new CompletionHandler() {
@Override
public void complete(Object retValue) {
complete(retValue, true);
}
@Override
public void complete() {
complete(null, true);
}
@Override
public void setProgressData(Object value) {
complete(value, false);
}
private void complete(Object retValue, boolean complete) {
try {
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("data", retValue);
//retValue = URLEncoder.encode(ret.toString(), "UTF-8").replaceAll("\\+", "%20");
if (cb != null) {
//String script = String.format("%s(JSON.parse(decodeURIComponent(\"%s\")).data);", cb, retValue);
String script = String.format("%s(%s.data);", cb, ret.toString());
if (complete) {
script += "delete window." + cb;
}
//Log.d(LOG_TAG, "complete " + script);
mDWebView.evaluateJavascript(script);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
} else {
retData = method.invoke(jsb, arg);
ret.put("code", 0);
ret.put("data", retData);
return ret.toString();
}
} catch (Exception e) {
e.printStackTrace();
error = String.format("Call failed:The parameter of \"%s\" in Java is invalid.", methodName);
PrintDebugInfo(error);
return ret.toString();
}
return ret.toString();
}
这个方法比较长但是逻辑不会复杂,首先就是解析方法参数,命名空间.方法名的数据解析,首先获取命名空间,在通过addjavascriptinterface中维护的hashmap中获取这个命名空间对应的接口类,初始化返回的json值变量,然后解析args参数,主要判断里面是否有回调函数,就是通过args中带过来的数据进行获取。然后根据反射获取这个方法,同时可以判断出是异步方法还是同步方法,然后检查方法是否有使用@JavascriptInterface注解进行修饰,接下来就是方法处理了,首先判断是否是异步方法,如果是异步方法的话,首先通过反射先执行对应的方法,然后因为是java的异步方法,第二个参数是回调函数,在complete回调中,通过webview.evaluateJavascript方法调用在js中写的回调函数,同时组装返回变量ret的值,如果是同步的方法的话,直接反射执行方法,组装返回变量的值,最后就是讲返回变量的值返回了,回到dsbridge.js中的call函数,其实就是对返回的变量值进行json格式化处理。