`
sd6733531
  • 浏览: 66531 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

android phonegap源码详解(二)

阅读更多

传送门:

PhoneGap源码详解一

PhoneGap源码详解二

PhoneGap源码详解三

 

 

一、 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 自定义事件

首先上图。


 

上图为本人整理的启动事件序列,待会儿大家便能从源码中看到了。

待续。。。。

 

 

  • 大小: 9.6 KB
  • 大小: 125.4 KB
1
0
分享到:
评论
15 楼 sd6733531 2012-08-10  
xiaofancn 写道
您好,我想问一下,我用mapabc重写了
https://github.com/apache/incubator-cordova-android/blob/master/framework/src/org/apache/cordova/GeoBroker.java

相关的类,还是提示无法获取位置信息。希望你能分析分析一下这个问题。


这个便涉及MapABC API与此结合的问题了.
具体情况还需要具体分析,兄台可以按照如下顺序排查:
剪去phonegap,原生层与mapabc的api结合是否成功
js层调用map abc插件时,原生层是否正确收到.参数和方法是否正确,所在线程是否正确
如若还是不能解决的话,可以加群讨论
14 楼 xiaofancn 2012-08-07  
您好,我想问一下,我用mapabc重写了
https://github.com/apache/incubator-cordova-android/blob/master/framework/src/org/apache/cordova/GeoBroker.java

相关的类,还是提示无法获取位置信息。希望你能分析分析一下这个问题。
13 楼 sd6733531 2012-07-29  
wmyzcs 写道

多谢兄台支持!
12 楼 wmyzcs 2012-07-29  
11 楼 Riddle0531 2012-07-11  
sd6733531 写道
Riddle0531 写道
Riddle0531 写道
channel = {
            /**
             * Calls the provided function only after all of the channels specified
             * have been fired.
             */
            join: function (h, c) {
                var i = c.length;
                var len = i;
                var f = function() {
                    if (!(--i)) h();
                };
                for (var j = 0; j < len; j++) {
                    !c[j].fired ? c[j].subscribeOnce(f) : i--;
                }
                if (!i) h();
            },
            create: function (type, opts) {
                channel[type] = new Channel(type, opts);
                return channel[type];
            },
这个channel是什么?object/function? 为什么不需要var开头;求关键字-自行学习

h  这里是什么function呢?
前辈,加不上,说服务器维护;能加我吧 717633529


Riddle兄,这里讲话不方便,直接加q群聊吧
248908795

10 楼 sd6733531 2012-07-11  
Riddle0531 写道
Riddle0531 写道
channel = {
            /**
             * Calls the provided function only after all of the channels specified
             * have been fired.
             */
            join: function (h, c) {
                var i = c.length;
                var len = i;
                var f = function() {
                    if (!(--i)) h();
                };
                for (var j = 0; j < len; j++) {
                    !c[j].fired ? c[j].subscribeOnce(f) : i--;
                }
                if (!i) h();
            },
            create: function (type, opts) {
                channel[type] = new Channel(type, opts);
                return channel[type];
            },
这个channel是什么?object/function? 为什么不需要var开头;求关键字-自行学习

h  这里是什么function呢?


Riddle兄,这里讲话不方便,直接加q群聊吧
248908795
9 楼 Riddle0531 2012-07-11  
Riddle0531 写道
channel = {
            /**
             * Calls the provided function only after all of the channels specified
             * have been fired.
             */
            join: function (h, c) {
                var i = c.length;
                var len = i;
                var f = function() {
                    if (!(--i)) h();
                };
                for (var j = 0; j < len; j++) {
                    !c[j].fired ? c[j].subscribeOnce(f) : i--;
                }
                if (!i) h();
            },
            create: function (type, opts) {
                channel[type] = new Channel(type, opts);
                return channel[type];
            },
这个channel是什么?object/function? 为什么不需要var开头;求关键字-自行学习

h  这里是什么function呢?
8 楼 Riddle0531 2012-07-11  
channel = {
            /**
             * Calls the provided function only after all of the channels specified
             * have been fired.
             */
            join: function (h, c) {
                var i = c.length;
                var len = i;
                var f = function() {
                    if (!(--i)) h();
                };
                for (var j = 0; j < len; j++) {
                    !c[j].fired ? c[j].subscribeOnce(f) : i--;
                }
                if (!i) h();
            },
            create: function (type, opts) {
                channel[type] = new Channel(type, opts);
                return channel[type];
            },
这个channel是什么?object/function? 为什么不需要var开头;求关键字-自行学习
7 楼 Riddle0531 2012-07-11  
楼主可以做篇文章从代码层逐步分析下channel.js的工作原理 和机制是如何实现的吗?我也努力研究 ;还有能加您qq什么的吗想交流下phoneGap
6 楼 sd6733531 2012-07-11  
Riddle0531 写道
主要还是.js太久没写不太熟悉了;
比如
this.events = {
            onSubscribe:null,
            onUnsubscribe:null
        };

我就不太清楚,这是类的定义吗?我还是一边看一边复习和学习JS吧


这是Channel对象的一个注册/注销触发器。类似C#中的delegate/event用法
当Channel对象被调用subscribe/unsubscribe的时候,会触发onSubscribe/onUnsubscribe。
很实用的一点便是可以拦截得知当前注册该通道(Channel)的监听器数目。上述的battery.js例子便是据此判定启用和关闭plugin。(无监听器注册通道,关闭Native的Battery监听。有监听器注册通道,打开Native的Battery监听)
5 楼 Riddle0531 2012-07-11  
主要还是.js太久没写不太熟悉了;
比如
this.events = {
            onSubscribe:null,
            onUnsubscribe:null
        };

我就不太清楚,这是类的定义吗?我还是一边看一边复习和学习JS吧
4 楼 sd6733531 2012-07-10  
Riddle0531 写道
如果有个zip 那当然最好不过了;
正在研读您的 - PhoneGap中的事件处理机制 这个部分真是挑战...
有没有推荐个读懂的思路;或者一些必备的知识背景


兄台,你要的zip包我已经传上去了。
PhoneGap的事件处理机制,兄台哪里不懂呢?
会javascript语法,了解观察者模式应该就能看懂
3 楼 Riddle0531 2012-07-10  
如果有个zip 那当然最好不过了;
正在研读您的 - PhoneGap中的事件处理机制 这个部分真是挑战...
有没有推荐个读懂的思路;或者一些必备的知识背景
2 楼 sd6733531 2012-07-10  
写正则逐个文件抽取出来.
开头有个:xx file的标志吧.兄台如果需要现成的话,我上传个zip包吧
1 楼 Riddle0531 2012-07-10  
问下 如何反build .js代码呢?谢谢

相关推荐

    android+phonegap+jquery mobile

    【标题】:“Android + PhoneGap + jQuery Mobile” 这个项目标题揭示了一个使用三种技术栈构建的移动应用程序:Android、PhoneGap和jQuery Mobile。Android是Google主导的开源操作系统,主要用于智能手机和平板...

    android PhoneGap 入门

    **Android PhoneGap 入门详解** PhoneGap 是一个开源框架,它允许开发者使用 HTML、CSS 和 JavaScript 这些Web技术来构建原生的移动应用程序。它基于 Apache Cordova 平台,通过桥接机制,将JavaScript 与移动设备...

    phonegap-splashscreen

    PhoneGap Splashscreen 知识点详解 PhoneGap 是一个开源框架,它允许开发者使用HTML、CSS和JavaScript构建原生移动应用程序。PhoneGap Splashscreen 模块则是 PhoneGap 的一个重要组件,用于在应用启动时显示一个...

    初试PhoneGap开发框架

    ### 初试PhoneGap开发框架知识点详解 #### 一、概览 本篇文章将通过一个实战案例介绍如何使用PhoneGap开发框架来构建跨平台移动应用。PhoneGap是一款开放源码的移动开发工具,允许开发者利用HTML、CSS以及...

    phonegap backup

    - **plugins**:这个文件夹可能包含了已安装的PhoneGap插件,每个插件有自己的目录,包含必要的源码和配置文件,用于扩展PhoneGap的功能。 3. **开发流程**: - **安装和配置环境**:开发者需要安装PhoneGap/...

    phonegap-plugin

    PhoneGap 插件开发详解 PhoneGap 是一个开源框架,它允许开发者使用 HTML、CSS 和 JavaScript 来构建原生移动应用程序。PhoneGap 的核心理念是通过 Web 技术来实现跨平台的移动应用开发,同时利用各平台的原生功能...

    Android_photogap

    总之,Android Photogap是利用PhoneGap框架开发的Android应用实例,通过理解和学习其源码,开发者可以更好地掌握混合应用开发技术,结合Web的便捷性和Android的广泛设备支持,高效地创建跨平台的应用程序。

    中科院计算所Android开发技术培训大纲.doc

    - 操作系统和开放联盟:讨论PhoneGap与Android操作系统的关系,以及其在开放源码社区的角色。 - 接口和工具:学习使用PhoneGap所需的开发环境和工具,如Android SDK等。 2. **HTML5 API和Event事件** - HTML5...

    CordovaTest:通过Cordova默认案例生成的Android项目源码-源码通

    **CordovaTest项目详解** **一、Cordova简介** Cordova,原名为PhoneGap,是一款开源的移动应用开发框架,允许开发者使用HTML5、CSS3和JavaScript来构建跨平台的移动应用程序。它将Web应用程序封装在原生的移动...

    Calendar-for-Android

    《构建Android日历插件:Calendar-for-Android详解》 在移动应用开发中,与用户交互的组件至关重要,其中日历功能就是一个常见的需求。本文将深入探讨名为"Calendar-for-Android"的Cordova插件,它允许开发者在...

    二开苹果cms视频网站源码模板_可封装双端app等.txt

    ### 二开苹果CMS视频网站源码模板及封装双端APP技术详解 #### 一、苹果CMS概述 苹果CMS(Apple Content Management System)是一款广泛应用于搭建视频网站的开源内容管理系统。它以其简单易用、功能强大著称,在...

    CalculadoraJSAndroid:使用JavaScript为Android应用程序开发的计算器

    **标题解析:** "CalculadoraJSAndroid"是一个项目名称,暗示了我们正在讨论一个使用JavaScript构建的Android应用程序,它...通过深入研究项目源码,开发者可以学习到如何在Android平台上利用JavaScript实现复杂功能。

    SignalStrength

    **SignalStrength 插件详解** 在移动应用开发中,了解设备的信号强度是十分重要的,尤其是在涉及通信质量或网络性能优化的情景下。SignalStrength 插件是针对 PhoneGap 平台的一个实用工具,它允许开发者获取设备的...

    TestCordova.zip

    《CorDova技术详解:构建跨平台H5与Native交互桥梁》 在移动应用开发领域,跨平台成为了不可或缺的需求。CorDova,作为一款强大的开源框架,为开发者提供了实现HTML5(H5)、JavaScript和CSS3等Web技术构建原生移动...

    ToastyPlugin:cordova插件

    **ToastyPlugin:Cordova插件详解** Cordova是一款开源的移动应用开发框架,它允许开发者使用HTML、CSS和JavaScript来构建原生的移动应用程序。Cordova通过将这些Web技术与设备APIs相结合,使开发者能够访问手机...

    QuizApp:电话应用程序是一个测验。 使用的技术

    PhoneGap将这些Web应用封装在原生的移动应用壳中,使得它们可以在各大移动操作系统(如iOS、Android和Windows Phone)上运行,提供了一种跨平台的开发方式。QuizApp使用PhoneGap,意味着它的代码base是基于Web的,但...

Global site tag (gtag.js) - Google Analytics