在了解了phonegap的最基本的定义和调用的方法之后,继续看看和手机的通信部分.
在1.5之前的版本,phonegap在android的通信方式是通过js的prompt来实现的(具体其他文章有详细讲解),关键的部分由下面的几个函数组成
而在1.5之后,采用的往往是这种格式
首先还是从exec函数入手,分析下phonegap的通信方式,在js端的exec定义中可以看到执行命令实际只是一个简单的js的prompt函数,将调用的方法、参数等信息以字符串的方式传入。
在android端通过,下面的代码,劫持了字符串信息,并且通过分析最终调用到具体的服务类.
对普通的插件而言存在两种结果
1. 异步调用,在非异常的情况下都返回""
2. 同步调用,会将结果作为json字符串传送回js端
取得结果后js端会直接放弃所有的""结果,然后分析同步结果
对于同步的请求,在返回结果后会直接调用插件定义的回调函数进行处理.
而异步的请求,则需要通过android的处理,触发页面的页面的事件,然后相应.在最开始可以看到每个请求都有唯一的服务id,并且通过回调事件缓存池将方法缓存.
当android的任务完成以后,会通过Plugin类的success函数返回成功结果,而这个操作实际就是向webview发起一个js请求.
然后通过js端的回调服务callbackSuccess来实现异步结果返回.
但是任然有部分的代码中的返回是通过特定的函数来实现,如地理位置中的返回,就仍然采用了原有的模式(因为大部分设备使用的是浏览器自带的定位,所以感觉不到问题),所以如果不做相应修改就会产生错误.
在1.5之前的版本,phonegap在android的通信方式是通过js的prompt来实现的(具体其他文章有详细讲解),关键的部分由下面的几个函数组成
PhoneGap.exec = function(success, fail, service, action, args)
PhoneGap.callbackSuccess = function(callbackId, args)
PhoneGap.callbackError = function(callbackId, args)
而在1.5之后,采用的往往是这种格式
var exec = require("cordova/exec");
exec(successCallback, errorCallback, "Accelerometer","getAcceleration", []);
首先还是从exec函数入手,分析下phonegap的通信方式,在js端的exec定义中可以看到执行命令实际只是一个简单的js的prompt函数,将调用的方法、参数等信息以字符串的方式传入。
var r = prompt(JSON.stringify(args), "gap:"+ JSON.stringify([service,action,callbackId, true]));
在android端通过,下面的代码,劫持了字符串信息,并且通过分析最终调用到具体的服务类.
//所在函数 org.apache.cordova.CordovaChromeClient.onJsPrompt
if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
JSONArray array;
try {
array = new JSONArray(defaultValue.substring(4));
String service = array.getString(0);
String action = array.getString(1);
String callbackId = array.getString(2);
boolean async = array.getBoolean(3);
String r = ctx.pluginManager.exec(service, action, callbackId, message, async);
result.confirm(r);
} catch (JSONException e) {
e.printStackTrace();
}
}
对普通的插件而言存在两种结果
1. 异步调用,在非异常的情况下都返回""
2. 同步调用,会将结果作为json字符串传送回js端
取得结果后js端会直接放弃所有的""结果,然后分析同步结果
// line 757 成功返回处理
if (v.status === cordova.callbackStatus.OK) {
if (success) {
try {
success(v.message);
} catch (e) {
console.log("Error in success callback: "
+ callbackId + " = " + e);
}
if (!v.keepCallback) {
delete cordova.callbacks[callbackId];
}
}
return v.message;
}
// line 788 失败处理
else {
if (fail) {
try {
fail(v.message);
} catch (e1) {
console.log("Error in error callback: "
+ callbackId + " = " + e1);
}
if (!v.keepCallback) {
delete cordova.callbacks[callbackId];
}
}
return null;
}
对于同步的请求,在返回结果后会直接调用插件定义的回调函数进行处理.
而异步的请求,则需要通过android的处理,触发页面的页面的事件,然后相应.在最开始可以看到每个请求都有唯一的服务id,并且通过回调事件缓存池将方法缓存.
var callbackId = service + cordova.callbackId++;
if (success || fail) {
cordova.callbacks[callbackId] = {
success : success,
fail : fail
};
}
当android的任务完成以后,会通过Plugin类的success函数返回成功结果,而这个操作实际就是向webview发起一个js请求.
//line 157 org.apache.cordova.api.Plugin
public void success(PluginResult pluginResult, String callbackId) {
this.ctx.sendJavascript(pluginResult.toSuccessCallbackString(callbackId));
}
//line 86 org.apache.cordova.api.PluginResult
public String toSuccessCallbackString(String callbackId) {
return "require('cordova').callbackSuccess('"+callbackId+"',"+this.getJSONString()+");";
}
然后通过js端的回调服务callbackSuccess来实现异步结果返回.
但是任然有部分的代码中的返回是通过特定的函数来实现,如地理位置中的返回,就仍然采用了原有的模式(因为大部分设备使用的是浏览器自带的定位,所以感觉不到问题),所以如果不做相应修改就会产生错误.
// line 81 org.apache.cordova.GeoListener.success
void success(Location loc) {
String params = loc.getLatitude() + "," + loc.getLongitude() + ", " + loc.getAltitude() +
"," + loc.getAccuracy() + "," + loc.getBearing() +
"," + loc.getSpeed() + "," + loc.getTime();
if (id == "global") {
this.stop();
}
this.broker.sendJavascript("navigator._geo.success('" + id + "'," + params + ");");
}