传送门:
一、 Javascript 的源码结构
提醒一下大家 ,PhoneGap 的作者已经将 PhoneGap 的源码委托给了 Apache 基金会。 PhoneGap 的开源版本称为 cordova 。
PhoneGap 之于 Cordova ,正如 OpenJDK 之于 JDK 。两者基本上是差不多的。
cordova.android.js 是一个 build 版本。本人对其做了反 build 工作 ,cordova.android.js 展开的源码目录结构便如上所示。
从命名上其实已经可以看出 ,lib/android 属于 android 平台的专用库。其余平台基本上是 lib/windowsphone 或者 lib/ios 。而除 lib 下的 exec.js 和 platform.js 这两个是固定的。但是不同平台版本其实现是不一样的。除 lib 包外,其余所有的 js 文件都是跨平台通用的。 ( 即使有差异应该也不大 )
简单介绍一下各个目录和一些关键组件 :
cordova.js:拦截DOM,Window事件,加入自定义cordova事件,管理回调Javascript。 scripts/require.js:PhoneGap中模块化机制的基础框架。简单但是也不简单! scripts/bootstrap.js:负责cordova的启动。 common/channel.js:PhoneGap中实现事件监听的基础。 common/builder.js:具备定制化构造模块的能力。 common/plugin:如名字所示。这里放置所有平台通用的插件接口。 lib/exec.js:于上一篇解析中提到。是Javascript调用Native的入口。 lib/platform.js:与平台实现有关的初始化。 lib/android/plugin:与android平台紧密相关的插件。
二、 浅析 PhoneGap 中的模块化机制
也许是因为本人见过的 Javascript 代码太少,见到 PhoneGap 的模块化机制后便觉得非常的有趣和前卫。 Pascal 的作者沃斯曾写过一门叫做 module 的语言,其在语言级别做了模块化机制。我不知道 PhoneGap 模块化的思路是否也受 ; 此影响。
废话不多说了,从 require.js 开始看起吧。它是模块化的基础。
var require, define; (function () { var modules = {}; function build(module) { var factory = module.factory; module.exports = {}; delete module.factory; factory(require, module.exports, module); return module.exports; } require = function (id) { if (!modules[id]) { throw "module " + id + " not found"; } return modules[id].factory ? build(modules[id]) : modules[id].exports; }; define = function (id, factory) { if (modules[id]) { throw "module " + id + " already defined"; } modules[id] = { id: id, factory: factory }; }; define.remove = function (id) { delete modules[id]; }; })(); //Export for use in node if (typeof module === "object" && typeof require === "function") { module.exports.require = require; module.exports.define = define; }
代码行数的确非常短。其定义了 require 和 define 两个函数。首先 define 函数用于声明一个模块。其中 id 表示模块名称,这必须是唯一的,而 factory 便是构造模块的工厂方法。 require 函数使用懒加载的方式获得已 define 过的对应 id 的模块。
来看一个使用其的简单示例吧 :
define("cordova/plugin/android/app", function(require, exports, module) { var exec = require('cordova/exec'); module.exports = { /** * Clear the resource cache. */ clearCache:function() { exec(null, null, "App", "clearCache", []); }, /** * Load the url into the webview or into new browser instance. * * @param url The URL to load * @param props Properties that can be passed in to the activity: * wait: int => wait msec before loading URL * loadingDialog: "Title,Message" => display a native loading dialog * loadUrlTimeoutValue: int => time in msec to wait before triggering a timeout error * clearHistory: boolean => clear webview history (default=false) * openExternal: boolean => open in a new browser (default=false) * * Example: * navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000}); */ loadUrl:function(url, props) { exec(null, null, "App", "loadUrl", [url, props]); }, /** * Cancel loadUrl that is waiting to be loaded. */ cancelLoadUrl:function() { exec(null, null, "App", "cancelLoadUrl", []); }, /** * Clear web history in this web view. * Instead of BACK button loading the previous web page, it will exit the app. */ clearHistory:function() { exec(null, null, "App", "clearHistory", []); }, /** * Go to previous page displayed. * This is the same as pressing the backbutton on Android device. */ backHistory:function() { exec(null, null, "App", "backHistory", []); }, /** * Override the default behavior of the Android back button. * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired. * * Note: The user should not have to call this method. Instead, when the user * registers for the "backbutton" event, this is automatically done. * * @param override T=override, F=cancel override */ overrideBackbutton:function(override) { exec(null, null, "App", "overrideBackbutton", [override]); }, /** * Exit and terminate the application. */ exitApp:function() { return exec(null, null, "App", "exitApp", []); } }; });
这是 phonegap 模块化编程的典型写法。首先在头部定义依赖的模块组件 , 再次通过设置 module.exports 向外部暴露出对应的方法。
由于 Javascript 中在语法级别没有私有访问符。因此往往解决之道是: a. 模仿 C 风格,命名使用 _ 开头的一律表示是私有 ;b. 新建一个 private 对象 , 将其私有方法放置其中 , 起到命名空间的作用 ;c. 将私有部分用 function{} 套住 , 用 return 返回公开部分。这种做法充分发挥了 javascript 闭包的优势,但是可读性比较差。
phoneGap 的 module 机制使用了第三种做法。但是通过将构造和依赖分离开来,使得可读性大大增加。代码清晰好懂,依赖性也一目了然。
也许有朋友要问。这种模块机制碰到循环依赖的情况怎么办?例如 A 在 define 阶段 requireB , B 在 define 阶段又 requireA 。很遗憾,这种循环依赖的情况 依照 phoneGap 的模块化思路是无法实现的。因此对于关键组件的编制 ,phoneGap 总会小心翼翼地处理其依赖顺序。
通过阅读源码,发现大致的模块依赖顺序是这样子的 ( 被依赖模块到依赖模块 ):utils.js->channel.js|builder.js->cordova.js->exec.js|polling.js->callback.js->platform.js->bootstrap.js 。
三、 PhoneGap 中的事件处理机制
common/channel.js 是 PhoneGap 事件处理机制的基础。每个事件类型,都会包装成一个 Channel 对象。
既然是事件,那么就得支持基础的观察者模式吧? Channel 的 prototype 定义了事件的一些关键方法。 subscribe 用于注册一个监听器,并给监听器一个 guid 。 guid 类似 cordova.js 中的 callbackId ,只是一个流水标识。但 Channel 中的 guid 稍有些不同,指定确切的 guid 可以对监听器做覆盖操作。
utils.close 是个很有趣的方法。 Javascript 中的调用不当引起 this 不对,这是新手常见的错误。常见的做法会通过封装 apply 做 delegate 。而 close 这个方法是绝了 , 它通过闭包包装了一个指向确定 this ,调用确定 function, 使用确定实参的 final 函数。不管在什么样的环境下调用 , 这个方法总能正确执行。
subscribeOnce 类似于 YUI 或者 jquery 中的 one 。只会收到一次监听。 ( 若事件已经触发过,则在注册阶段立即回调监听 )
unsubscribe 和 fire 分别用来注销监听器和触发事件。触发事件将会引起监听器的广播操作。可选的 fireArgs 用于保证 subscribeOnce 在事件已触发的情况下能获得正确的广播参数。
Channel 本身还有一个监听注册 / 注销的事件拦截。分别是 onSubscribe 和 onUnSubscribe 。在 common\plugin\battery.js 中,我们可以看到。 battery.js 便是利用这个注册监听回调,来对 Plugin 服务做懒加载和卸载工作。
作为模块暴露公有部分的 channel 对象比较有意思。 join 这个工具方法类似 subscribeOnce, 它的第二个参数是个 Channel 数组。当且仅当所有的 Channel 事件都被 fire 后 ,join 的监听才会被回调。这个方法还是挺有用的
create 是个构造工厂方法。新构造的 Channel 事件会被放置在 channel 对象中。使用上会方便点。在 channel.create('onCordovaReady'); 后 , 便可以便捷的通过 channel[‘onCordovaReady’] 来方便的访问对应类型的 Channel 对象了。
deviceReadyMap,deviceReadyArray,waitForInitialization,initializeComplete 这四者紧密相关。它们决定了 onDeviceReady 事件在何时被触发。于 common/bootstrap.js 中我们看到下面一段代码。
channel.join(function() { channel.onDeviceReady.fire(); }, channel.deviceReadyChannelsArray);
waitForInitialization 用于添加 onDeviceReady 的等待 Channel 事件。 initializeComplete 用于触发指定的等待 Channel 事件。如果想要增加 onDeviceReady 的条件,我们只需要在 onCordovaReady 之前添加 waitForInitialization 即可。事实上,在 lib/android/plugin/storage.js 中我们便可以看到一个绝佳的例子。 cupcakeStorage 利用本地 Plugin 为不支持 localStorage API 的 WebView 提供了一个备选方案。在本地建立好备用的 sqlite 数据库后 ,cupcakeStorage 的等待时间便结束完毕。
四、 启动与 PhoneGap 自定义事件
首先上图。
上图为本人整理的启动事件序列,待会儿大家便能从源码中看到了。
待续。。。。
相关推荐
【标题】:“Android + PhoneGap + jQuery Mobile” 这个项目标题揭示了一个使用三种技术栈构建的移动应用程序:Android、PhoneGap和jQuery Mobile。Android是Google主导的开源操作系统,主要用于智能手机和平板...
**Android PhoneGap 入门详解** PhoneGap 是一个开源框架,它允许开发者使用 HTML、CSS 和 JavaScript 这些Web技术来构建原生的移动应用程序。它基于 Apache Cordova 平台,通过桥接机制,将JavaScript 与移动设备...
PhoneGap Splashscreen 知识点详解 PhoneGap 是一个开源框架,它允许开发者使用HTML、CSS和JavaScript构建原生移动应用程序。PhoneGap Splashscreen 模块则是 PhoneGap 的一个重要组件,用于在应用启动时显示一个...
### 初试PhoneGap开发框架知识点详解 #### 一、概览 本篇文章将通过一个实战案例介绍如何使用PhoneGap开发框架来构建跨平台移动应用。PhoneGap是一款开放源码的移动开发工具,允许开发者利用HTML、CSS以及...
- **plugins**:这个文件夹可能包含了已安装的PhoneGap插件,每个插件有自己的目录,包含必要的源码和配置文件,用于扩展PhoneGap的功能。 3. **开发流程**: - **安装和配置环境**:开发者需要安装PhoneGap/...
PhoneGap 插件开发详解 PhoneGap 是一个开源框架,它允许开发者使用 HTML、CSS 和 JavaScript 来构建原生移动应用程序。PhoneGap 的核心理念是通过 Web 技术来实现跨平台的移动应用开发,同时利用各平台的原生功能...
总之,Android Photogap是利用PhoneGap框架开发的Android应用实例,通过理解和学习其源码,开发者可以更好地掌握混合应用开发技术,结合Web的便捷性和Android的广泛设备支持,高效地创建跨平台的应用程序。
- 操作系统和开放联盟:讨论PhoneGap与Android操作系统的关系,以及其在开放源码社区的角色。 - 接口和工具:学习使用PhoneGap所需的开发环境和工具,如Android SDK等。 2. **HTML5 API和Event事件** - HTML5...
**CordovaTest项目详解** **一、Cordova简介** Cordova,原名为PhoneGap,是一款开源的移动应用开发框架,允许开发者使用HTML5、CSS3和JavaScript来构建跨平台的移动应用程序。它将Web应用程序封装在原生的移动...
《构建Android日历插件:Calendar-for-Android详解》 在移动应用开发中,与用户交互的组件至关重要,其中日历功能就是一个常见的需求。本文将深入探讨名为"Calendar-for-Android"的Cordova插件,它允许开发者在...
### 二开苹果CMS视频网站源码模板及封装双端APP技术详解 #### 一、苹果CMS概述 苹果CMS(Apple Content Management System)是一款广泛应用于搭建视频网站的开源内容管理系统。它以其简单易用、功能强大著称,在...
**标题解析:** "CalculadoraJSAndroid"是一个项目名称,暗示了我们正在讨论一个使用JavaScript构建的Android应用程序,它...通过深入研究项目源码,开发者可以学习到如何在Android平台上利用JavaScript实现复杂功能。
**SignalStrength 插件详解** 在移动应用开发中,了解设备的信号强度是十分重要的,尤其是在涉及通信质量或网络性能优化的情景下。SignalStrength 插件是针对 PhoneGap 平台的一个实用工具,它允许开发者获取设备的...
《CorDova技术详解:构建跨平台H5与Native交互桥梁》 在移动应用开发领域,跨平台成为了不可或缺的需求。CorDova,作为一款强大的开源框架,为开发者提供了实现HTML5(H5)、JavaScript和CSS3等Web技术构建原生移动...
**ToastyPlugin:Cordova插件详解** Cordova是一款开源的移动应用开发框架,它允许开发者使用HTML、CSS和JavaScript来构建原生的移动应用程序。Cordova通过将这些Web技术与设备APIs相结合,使开发者能够访问手机...
PhoneGap将这些Web应用封装在原生的移动应用壳中,使得它们可以在各大移动操作系统(如iOS、Android和Windows Phone)上运行,提供了一种跨平台的开发方式。QuizApp使用PhoneGap,意味着它的代码base是基于Web的,但...