在引导程序中,导入cordova/builder之后,便是导入cordova/common,这是所有平台公共的模块部分,在cordova/common构造函数中,通过返回一个配置对象,非常精巧的将公共模块组织起来,并通过引导程序中的builder.build(base.objects).intoButDontClobber(window)将这些模块在window全局中构建。
我们看看这个配置对象:
define("cordova/common", function(require, exports, module) { module.exports = { objects: { cordova: { path: 'cordova', children: { } }, Cordova: { children: { } }, PhoneGap:{ children: { } }, navigator: { children: { } }, Acceleration: { path: 'cordova/plugin/Acceleration' }, // 省略了其它一些配置 resolveLocalFileSystemURI:{ path: 'cordova/plugin/resolveLocalFileSystemURI' } } };
1、从整体上来说,配置对象是一个对象字面量,是一些属性的集合,而这些属性,会通过builder模块导入至window对象。
2、考察配置对象内部的属性对象,发现有三种情况:属性对象只有一个path子属性、属性对象只有子属性children、属性对象同时有path和children两个子属性。再回看一下builder中include代码:
(1)含有path,首先会使用require(path)导入path指定的模块,作为导入window全局的一个中间备选对象(具体导入方式和调用builder中返回方法相关)。如果没有path,则中间备选对象是一个没有属性的空对象{}。
(2)含有children的,我们可以看到,children本身也是一个和全局配置对象结构相同的配置对象,然后在builder的include方法中,将中间备选对象作为父对象,递归导入children中的模块。不含children的,则导入结束。
3、在配置对象中,有一个公共的cordova/exec我们还没有分析,这是PhoneGap库和Android的通讯方法,从代码中可以看到,在PhoneGap中只是简单的调用了prompt这个函数,在Android本地会解析传入的参数并调用相应的命令。来看看它的源码:
define("cordova/exec", function(require, exports, module) { /** * 执行cordova命令 * 同步:返回一个JSON字符串;异步:返回空字符串"",这个时候可以根据处理结果调用回调函数 * 参数:(1)success:命令执行成功回调函数 * (2)fail:命令执行失败回调函数 * (3)service:使用的服务名称 * (4)action:在cordova中运行的命令 * (5)args:0或多个参数组成的数组 */ var cordova = require('cordova'); module.exports = function(success, fail, service, action, args) { try { var callbackId = service + cordova.callbackId++;//内部回调id if (success || fail) {//至少传入了其中一个 cordova.callbacks[callbackId] = {success:success, fail:fail}; } //将参数转化为JSON字符串去执行
var r = prompt(JSON.stringify(args), "gap:"+JSON.stringify([service, action, callbackId, true])); if (r.length > 0) { var v = JSON.parse(r);//将返回结果解析成对象 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; } else if (v.status === cordova.callbackStatus.NO_RESULT) { // 清除回调函数 if (!v.keepCallback) { delete cordova.callbacks[callbackId]; } } else {// 错误 console.log("Error: Status="+v.status+" Message="+v.message); // 调用失败回调函数 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; } } } catch (e2) { console.log("Error: "+e2); } }; });
4、至于导入的具体内容,则是PhoneGap库针对移动平台开发的公共模块了,比如访问摄像机(Camera)、通讯录(Contact)等,可以参考源代码以及官方API。