在引导程序中,还导入了一个模块cordova/platform,看看源码:
define("cordova/platform", function(require, exports, module) { module.exports = { id: "android", initialize:function() { }, objects: { }, merges: { } }; });
我们看到,在platform中,有四个属性:、
1、id:我们这里的源码是取自android子目录下,这里平台id相应的为android,其它的平台id也应与平台相对应。
2、initialize:顾名思义,这个是android平台的初始化方法。
3、objects:需要导入至全局环境的模块配置对象。
4、merges:需要导入至全局环境的模块配置对象。
那这里为什么要区分objects和merges呢?从它们的命名以及前面分析的builder模块,我们猜测,导入objects中的配置对象时,不会递归导入子属性,而导入merges中的配置对象,会递归合并。从引导程序的源码中,猜测得到了印证(参照代码中注释):
function() { var builder = require('cordova/builder'), base = require('cordova/common'), platform = require('cordova/platform'); // 在全局环境中创建公共模块,存在相同属性时,不覆盖 builder.build(base.objects).intoButDontClobber(window); // 在全局环境中导入平台配置模块,如果有相同属性,会直接覆盖整个属性 builder.build(platform.objects).intoAndClobber(window); // 在全局环境中导入平台配置模块,如果有相同属性,会递归子属性,进行覆盖 if (typeof platform.merges !== 'undefined') { builder.build(platform.merges).intoAndMerge(window); } // 平台初始化 platform.initialize(); // 触发cordovaReady事件,表示cordova已经创建好 channel.onCordovaReady.fire(); // 触发设备就绪事件 channel.join(function() { require('cordova').fireDocumentEvent('deviceready'); }, channel.deviceReadyChannelsArray); }
具体需要导入哪些模块,这个就和Android本地平台相关了,不过可以看到,导入模块都是以插件形式,这使得PhoneGap库非常灵活,可以根据需要插拔。
至此,整个PhoneGap库已经导入至全局环境,并触发相应的初始化事件。后面就是在应用程序中根据PhoneGap对平台封装的API实现自己的功能了,而PhoneGap对平台封装则是通过上一篇提及的exec或者直接通过prompt来和平台API进行交互,将常用功能封装构成PhoneGap自己的API,可以参考:PhoneGap API。
分析PhoneGap源码感受最深的有:
1、模块化:通过两个基础的define和require实现了各个相对独立的功能模块化了,这对于大型JS程序来说是非常关键的,不仅在编写代码的时候更加方便,提供了一个封装机制,更重要的是极大的提高了代码的可维护性,当然,对于我们这些开发者来说,也极大的提高了代码的可读性。
2、高度配置:通过builder模块中的include函数和一个与平台相应的配置对象,非常巧妙的实现了插件式编程,平台扩展非常方便。
3、对象字面量和JSON:这个不用说了,JSON这种数据格式在JS中已经无孔不入了。
4、设计模式的运用:构建具体模块的工厂方法、所有模块的模板方法、遍布其间的迭代方法等等,各位读者可以自己阅读源码好好体会。
当然,也有些地方觉得不是那么容易理解的,比如很多地方函数嵌套太深,形成很多闭包,这对内存和性能也是一个隐患。
这系列文章就写到这里,虽然题目叫源码分析,但其实只是对PhoneGap源码的一个组织结构以及在应用中的初始化构建做了一个初步的讨论,我自己也是初次接触PhoneGap,错误之处在所难免,望各位达人不吝赐教,如果这系列文章能起到一个抛砖引玉作用,那我也足够欣慰了。