`
longgangbai
  • 浏览: 7330290 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

phonegap底层原理学习和研究(二)

阅读更多

  转载自IBM中国开发网站:

http://www.ibm.com/developerworks/cn/opensource/os-cn-android-phonegap/#major1

PhoneGap 简介

PhoneGap 是利用 HTML 来开发移动应用的一个开放源代码的框架,利用它就可以仅仅使用 HTML 和 Javascript 实现一次编写,多个移动平台运行的应用。目前已经可以支持 Android、iOS、BlackBerry 等 6 个平台。在完成这篇短文的过程中,PhoneGap 正式发布了 1.0.0 版本。因而短文中的版本使用的是 1.0.0rc2 版本的代码。

PhoneGap 在 Android 平台上的实现的框架是利用了在本地代码和浏览器间建立中间层来实现对 Java 代码的隔离。利用浏览器的接口和网络 socket 接口实现数据的通讯。因此在对 PhoneGap 框架的理解上,需要从 Java 端和浏览器端两部分来分别学习。

关于 Android 开发环境和 PhoneGap 开发环境的搭建,请参考参考资料中的开发者网站实施。

Java 端介绍

Java 端作为后台调用 Android 本地 SDK 的接口,主要实现了如下的功能:

  1. 建立通讯机制,提供接口给浏览器端,方便 JavaScript 进行调用。
  2. 数据队列的维护,以保证浏览器端的调用后产生的数据可以回送。
  3. 插件体系的建立,提供整个框架的可扩展性。

而这三部分的功能对应到代码中则是如下的几个重要的 Java 类:

  1. DroidGap、CallbackServer
  2. CallbackServer
  3. Plugin、PluginManager

因此我们需要依次来了解这几个重要的 Java 类的具体实现,这样才可以对 PhoneGap 在 Android 上的体系有一个很好的了解。

DroidGap 的实现

当我们完成一个基本的 PhoneGap 的示例后,我们就会发现,在使用 PhoneGap 进行开发的手机应用中,第一步就是将继承关系 extends Activity 修改为 extends DroidGap。因此,DroidGap 是整个应用开始的地点,首先需要了解 DroidGap 的内容。

在源码中可以看到 DroidGap 继承自 PhonegapActivity,而 PhonegapActivity 是一个抽象类,继承自 Activity,但是具体的实现都是集中在 DroidGap 类中。

因此,我们继续回到 DroidGap 类中,当我们知道 DroidGap 类也是一个 Acitvity 后,就会明白,DroidGap 在 onCreate 方法中实现了整个类最初的一些操作,代码的实现则集中在 onCreate() 和 init() 这两个方法中,具体的流程如下:

  1. 设置 WebView

设置 WebView 的代码都集中在 init() 方法中,其中一个值得注意的工作是设置 WebChromClient。代码中提供了一个继承自 WebChromClient 的类,重写了其中的 onJsAlert,onJsConfirm,onJsPrompt 等方法。而在 onJsPrompt() 方法中,实现了 PhoneGap 中 Java 端和浏览器端通讯的关键一步。因此,值得我们专门的关注其代码,具体的功能实现代码如下,我们已经过滤了一些错误处理、安全验证等等可能会妨碍我们对重要的功能实现理解的代码:


代码清单 1. WebView 代码

				
 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 = pluginManager.exec(service, action, callbackId, message, async); 
 result.confirm(r); 
 } catch (JSONException e) { 
 e.printStackTrace(); 
 } 
 } 
 // Polling for JavaScript messages 
 else if ...... 

 

在此,我们就可以明白,实现 JavaScript 与 Java 端通讯的原理是 JavaScript 利用 prompt 来传递调用信息的数据,在 onJsPrompt 中,重写的方法截获了这些数据,在完成了对数据格式等等分析后,按照要求进行具体的调用。而具体的调用利用是的 PluginManager 类,这将在随后说明。

  1. 绑定 js

在完成 WebView 的设置后,再将 PhoneGap 和 js 绑定,实现 js 与 PhoneGap 的通讯。在这一步中主要的内容就是实例化了 CallbackServer 和 PluginManager 两个类。因此,更多的内容会在随后对这两个类的介绍中再说明。

  1. 载入 URL

LoadUrl 方法也是实现一个 PhoneGap 示例后很熟悉的方法,在 loadUrl 中,完成基本的字符串处理后,主要利用 runOnUiThread 开始处理,其中第一步检测是否需要提供载入的显示,之后使用 WebView 的 loadUrl 载入内容,并且设置超时时间。

至此,Java 端的准备工作也就完成,实现了 UI 的载入。可以看到,在 DroidGap 类中最重要的一个部分就是截获 JavaScript 的 prompt 数据。这是实现浏览器端和 Java 端通讯的基础。

Plugin 的实现

Plugin 是一个抽象类,实现了 IPlugin 接口,PhoneGap 中利用 Android SDK 实现逻辑代码的途径就是通过继承 Plugin 来实现。应此 Plugin 本身非常简单,最主要的部分是提供一个 execute 方法,如下:

 public abstract PluginResult execute(String action, JSONArray args, String callbackId); 

 

Plugin 的实现中的重要逻辑在其中来实现,它返回的是一个 PluginResult 对象,这个对象主要负责传递数据信息,包括的成员主要如下:

	 private final int status; 

 

用于返回状态,status 与一个 enum 类型相关,用于标注插件的执行结果如何。

	 private final String message; 

 

用于返回数据信息。

PluginManager 的实现

PluginManager 事实上是 DroidGap 类和具体的继承自 Plugin 的插件的联系纽带,由它来寻找和载入插件,并且调用。

首先,PluginManager 在构造函数中,调用了 loadPlugins 方法,该方法负责解析 xml 配置文件,对应每个 plugin,调用一次 addService 用于注册插件,具体的注册地点,是通过维护一个 HashMap<String, String> 来实现,分别保存 serviceType, className。在成员中,有另外一个 HashMap<String, IPlugin> 用于实现 className 和 IPlugin 类的绑定。这样就实现了 serviceType 和 IPlugin 的对应。

在 PluginManager 中,执行插件的方法 exec 是主要功能,我们将会详细说明一下这个方法的过程:

  1. 利用查询之前提到的 HashMap<String, String> 将 service 和 className 对应起来,这样我们就获得了提供功能的插件类的位置。
  2. 通过 getClassByName 来获得插件类。
  3. 完成类型检测,确定对应的类是一个插件类。
  4. 执行 addPlugin 方法,其中则将第 2 步中获得插件类的 className 和具体的 Plugin 接口的实现绑定,具体的实现就是上文中提到的 HashMap<Strig,IPlugin>。
  5. 判断 Plugin 是否需要异步执行,再根据情况,选择直接执行或者是建立新的线程来执行。
  6. 完成执行后,得到的数据会根据情况交给 CallbackServer 来处理,PluginManager 会调用 DroidGap 中的 sendJavaScript 来将数据交给 CallbackServer,事实上,DroidGap 中的 sendJavaScript 不过是对 CallbackServer 中的 sendJavaScript 包装,实际调用的是 CallbackServer 中的 sendJavaScript 方法,这涉及到了 CallbackServer 类,随后就会说明。

执行结果的转换则是利用 PluginResult 中的一些 to***String 方法。这些方法返回了一个 String 类型,其中包括了具体的 JSON 对象和 callbackId,具体的形式则是一个 js 代码,用于前端的调用。

CallbackServer 的实现

CallbackServer 实现了 Runnable 接口,具体的功能就是维护一个数据的队列,并且建立一个服务器,用于 XHR 的数据传递,对数据的队列的维护利用的是 LinkedList<String>。

由于实现的是 Runnable 接口,在 CallbackServer 中,最主要的方法就是 run() 方法,run() 方法的具体内容简介如下:

  1. 首先利用 ServerSocket 监听端口,具体端口则自由分配。
  2. 在 accept 后则是对 HTTP 协议的解析,和对应的返回 status code。
  3. 在验证正确后,利用 getJavascript 方法得到维护的 LinkedList<String>() 中的保存的 js 代码,如果为空则返回 null。
  4. 这些具体的 string 类型的 js 代码则利用 socket 作为 response 返回给前端。

之后就是对队列维护的方法,这时理解之前的 sendJavaScript 则很简单,该方法与 getJavaScript 相反,一个是从 LinkedList 中取出 js 代码,一个则是加入。

综上,CallbackServer 实现的是两个功能,一个是 XHR 的 SocketServer,一个是对队列的维护。而完成 CallbackServer 类的说明后,Java 端的主要功能也都说明完毕。随后会说明浏览器端的说明,在完成浏览器端说明后,我们就会明白整个 PhoneGap 框架运行的原理。

 

 

浏览器端介绍

浏览器端的 JavaScript 代码较多,但是实现其中核心功能的代码都在 PhoneGap 类中,其他的都是 PhoneGap 框架中自带的一些 Plugin 的 JavaScript 代码。

在浏览器端,其中一个最重要的函数就是 PhoneGap.exec 函数,因为大部分的函数调用,最终都会在这里实现与本地 Java 端的数据通讯,转而去调用 Java 端的 Plugin 来实现具体的执行。主要的内容如下,我们已经去除一些非功能的错误处理代码段,集中于具体的功能实现:


代码清单 2. PhonGap.exec 代码

				
 var callbackId = service + PhoneGap.callbackId++; 
 if (success || fail) { 
    PhoneGap.callbacks[callbackId] = {success:success, fail:fail}; 
 } 
 var r = prompt(PhoneGap.stringify(args), "gap:"+ 
 PhoneGap.stringify([service, action, callbackId, true])); 
 // If a result was returned 
 if (r.length > 0) { 
    eval("var v="+r+";"); 
    // If status is OK, then return value back to caller 
    if (v.status === PhoneGap.callbackStatus.OK) { 
       ...... 
    }else if ...... 
 } 

 

在以上标红加粗的代码段上,我们可以看到,调用的是 prompt 方法 , 我们在之前特别提到了,PhoneGap 在 DroidGap 类中,继承了一个 WebChromeClient,其中重写了方法 onJsPrompt,这样在 Java 端,就截获了浏览器端的调用。现在可以回到之前的 Java 端的说明,查看之前列出的 onJsPrompt 代码,联系之前的 Java 端的介绍,就会觉得豁然开朗了,剩下了流程也就顺理成章了。通过 r 的返回值,就可以轻松的返回数据给浏览器端了。

这时我们会有一个好奇,那就是 CallbackServer 的 SocketServer 的作用在哪里,因为至此我们已经看到了整个数据在浏览器端和 Java 端的通讯,那么这样的一个 SocketServer 又是提供的什么数据通讯呢?

显然,在 PluginManager 中的 exec中,我们会返回执行获得的数据,但是,在使用异步调用的时候,立即返回的则是一个空字符串,也即没有数据返回,之后插件会在一个新的线程中执行,等到异步的插件执行的结果返回数据后,会放入到队列中,等待 XHR 的获得。而 XHR 的调用是在 JavaScript 代码初始化中开始调用的,其中由于 JsCallBack 函数有使用轮询保证自己循环执行。这样就可以不断的获得异步数据。

 

 

Hello 插件的实现

掌握了上文中对 PhoneGap 框架的分析,我们就可以通过自己实现相关的插件来完成自己希望实现的功能,这样就可以不断丰富自己应用的功能。我们假设开发者已经熟悉了 PhoneGap 和 Android 的基本开发知识,Android 和 PhoneGap 开发环境搭建已经完成。

在具体的 Plugin 实现中,要分两个部分来实现,Java 代码和 JavaScript 代码,就此流程,我们来通过一个简单的例子来看一下如何具体的完成 Plugin 的实现。

在 Java 端,我们要继承一个 Plugin 类,实现其中的 execute 方法,在这里,我们省略具体的功能逻辑。

在 JavaScript 端,我们要利用现有 PhoneGap.exec 来调用具体的 Java 端,而且需要注意的是要在 PhoneGap 中注册这一个插件,PhoneGap.addConstructor就在 JavaScript 端调用 Java 端代码,完成添加,当然直接修改 XML 文件来实现也可以。

首先,完成 Java 端的代码实现。

我们实现一个简单的字符串回射程序,来模拟具体的逻辑,代码如下:


清单 3. 插件实例 Java 端代码

				
 @Override 
 public PluginResult execute(String action, JSONArray args, String callbackId) { 
 PluginResult.Status status = PluginResult.Status.OK; 
 PluginResult r=null; 
 if (action.equals("sayHello")){ 
 r = new PluginResult(status,"Hello"); 
 }else if (action.equals("saySth")){ 
 r = new PluginResult(status,args); 
 } 
 return r; 
 } 

 

实现的功能如下:

  1. 如果 action 的参数是 sayHello,则返回字符串“Hello”。
  2. 如果是 saySth,则返回 args 中的内容。

之后,完成 JavaScript 代码

请注意 JavaScipt 代码是需要 HTML 代码包含后才能使用的:


清单 4. 插件实例 JavaScript 端代码

				
     var Hello=function(){ 
     } 
     Hello.prototype.saySth = function(msg, callback, fail) { 
 return PhoneGap.exec(function(args) { 
     callback(args); 
 }, function(args) { 
 if(typeof fail == 'function') { 
     fail(args); 
 } 
 }, 'Hello', 'saySth', [msg]); 
     } 
     Hello.prototype.sayHello = function(callback, fail) { 
 return PhoneGap.exec(function(args) { 
  callback(args); 
 }, function(args) { 
 if(typeof fail == 'function') { 
 fail(args); 
 } 
 }, 'Hello', 'sayHello',['sayHello']); 
     } 
     PhoneGap.addConstructor(function() { 
    PhoneGap.addPlugin('hello', new Hello()); 
    //PluginManager.addService("Hello","qj.Hello"); 
     }) 

 

在这里我们需要有一个特别的说明:

在上述 JavaScript 代码中,我们注释了 addConstructor 函数中的一行,因为我们在开发过程中发现这条代码的执行在 Javascript 端没有被实现。

因此这段代码具体的执行则需要我们在 Java 端实现代码,那么为了实现这段 JavaScript 代码所做的补偿性的 Java 代码要在自己实现的 Java 端的 onCreate 函数中实现,内容是很简单的一句(当然,也可以通过修改 xml 文件来实现这一功能,上文提到过,PluginManager 类会扫描 xml 文件来依次以对应 xml 文件中的插件名作为参数执行这一调用):

 this.pluginManager.addService("Hello", "qj.Hello"); 

 

注意第二个参数是实现的插件的代码的位置,Hello 插件的位置是“src.qj.Hello.java”,对应的位置信息就是去除 .java 后缀名后的位置信息,整个项目的组织结构如图。


图 1. 项目组织结构图示例
图 1. 项目组织结构图示例

至此,Hello 插件已经实现,如果需要调用,则 JavaScript 代码如下:


清单 5. 插件调用代码

				
 window.plugins.hello.sayHello(function(arg){alert(arg);}, 
 function(arg){alert(arg);}); 
 window.plugins.hello.saySth("Bingo",function(arg){alert(arg);}, 
 function(arg){alert(arg);}); 

 

我们简单的将返回的数据通过 alert() 展示出来,插件的执行结果如下:

点击 SayHello,


图 2. 点击 SayHello 示例
图 2. 点击 SayHello 示例

点击 SayBingo


图 3. 点击 SayBingo 示例
图 3. 点击 SayBingo 示例

结束语

至此插件的开发已经完成,其中很大的篇幅都是通过对 PhoneGap 的框架的说明,让我们可以对插件的运行过程有一个更加底层的认识,我想这是比实现一个简单的插件更加重要的东西。如果读者需要了解更多的信息,请浏览参考资料中的开发者网站,获得更加实时的信息。

<!-- CMA ID: 812102 --><!-- Site ID: 10 --><!-- XSLT stylesheet used to transform this file: dw-document-html-6.0.xsl -->

 

分享到:
评论

相关推荐

    phonegap底层原理学习和研究(一)

    PhoneGap底层原理的学习和研究是理解如何将这些Web技术转化为可在iOS、Android等平台上运行的本地应用的关键。在本篇文章中,我们将深入探讨PhoneGap的核心概念、工作流程以及其与Android平台的集成。 首先,...

    PhoneGap介绍与原理

    ### PhoneGap介绍与原理 #### 背景与挑战 随着移动互联网的快速发展,各种平台如雨后春笋般涌现,其中包括移动设备、桌面应用、Web应用及Flash应用等。这种多平台的趋势为企业和个人开发者带来了前所未有的机遇,...

    phonegap学习资料

    ### PhoneGap 学习资料详解 #### 一、PhoneGap 概述 **PhoneGap** 是一个移动开发框架,允许开发者使用 **HTML**、**JavaScript** 和 **CSS** 开发跨平台的移动应用程序。该技术最早由 **Nitobi Software** 公司在...

    IONIC+PhoneGap项目源码

    1. "深入浅出 phonegap 代码.zip" - 这个文件可能是关于PhoneGap的教程或者示例代码,包含了深入讲解PhoneGap使用方法的代码示例,可以帮助初学者理解PhoneGap的工作原理和实践应用。 2. "ionic-1.1.zip" - 这是...

    phonegap源码+示例

    这个资源包含PhoneGap的源代码,版本为Cordova2.9,以及相关的示例程序,这为我们深入理解PhoneGap的工作原理和开发流程提供了宝贵的材料。 Cordova2.9是PhoneGap的一个重要版本,它在那时提供了对多种移动操作系统...

    phonegap完整例子!

    PhoneGap是一个开源框架,它允许开发者使用HTML5、CSS3和JavaScript来构建跨平台的移动应用。这个"phonegap完整例子!"是针对Android平台的一个示例项目,...这些内容为深入学习和实践PhoneGap开发提供了全面的指导。

    phoneGAP2.9.1.zip

    - **熟悉的开发环境**:对于熟悉Web开发的程序员来说,PhoneGap使用HTML、CSS和JavaScript,这意味着他们无需学习新的编程语言。 - **设备API访问**:通过PhoneGap,Web应用可以访问手机硬件功能,如相机、联系人...

    phonegap源码

    总的来说,"phonegap-2.7.0源码"是一个宝贵的学习和研究资源,对于理解PhoneGap的工作原理、Web与原生平台之间的交互,以及早期移动应用开发的历程都有重要的价值。通过深入研究,开发者可以提升自己的技能,同时也...

    phoneGap cordova 学习示例

    PhoneGap和Cordova是两个密切相关的移动应用开发框架,它们允许开发者使用HTML、CSS和JavaScript来构建跨平台的原生...在实际开发中,理解并熟练运用PhoneGap和Cordova的原理和特性,能够显著提升开发效率和应用质量。

    PhoneGAP实例源码

    通过研究这些源码,开发者不仅可以学习到PhoneGap的基本用法,还能了解到如何利用PhoneGap调用设备API,如网络通信、传感器数据、用户界面交互等。这对于希望入门移动开发或者提升PhoneGap技能的开发者来说是一份...

    PhoneGap实例

    通过学习和分析`phonegap100_apidemo`中的代码,开发者不仅能理解PhoneGap的工作原理,还能掌握如何将这些技术应用到实际项目中,从而构建出功能丰富的跨平台移动应用。在实践中,不断调试和优化这些示例,有助于...

    PhoneGap学习[归纳].pdf

    PhoneGap学习 PhoneGap是一个强大的开源框架,它允许开发者使用熟悉的Web技术如HTML、CSS和JavaScript来创建跨平台的移动应用。这一框架的核心理念是将Web开发的便捷性引入到移动应用开发中,使得开发者可以构建能...

    PhoneGap开发者指南源码

    通过这份"PhoneGap开发者指南源码",开发者不仅能学习到PhoneGap的基本用法,还能深入理解其工作原理,进而开发出具有丰富功能和优秀用户体验的跨平台移动应用。同时,不断实践和探索,将使开发者在PhoneGap开发领域...

    android phonegap源码详解(二)

    PhoneGap的工作原理是通过`WebViewClient`和`WebChromeClient`的子类来拦截WebView的加载事件,当遇到特定的URL(如`file:///android_asset/cordova.js`)时,会触发原生方法的调用。这些调用最终会到达`Plugin...

    PhoneGap Demo下载.rar

    通过学习和调试这个Demo,你可以了解PhoneGap的工作原理,为之后开发更复杂的应用打下基础。同时,这也是检查和解决PhoneGap环境问题的一个好方法,如果你在搭建环境时遇到困难,对照这个Demo的配置和运行过程,或许...

    PhoneGap demo

    这个"PhoneGap demo"作为一个实际案例,可以帮助开发者理解PhoneGap的工作原理,学习如何将Web技术应用于移动开发,同时也可以借鉴其设计和实现方式,提升自己的开发技能。尽管对于初学者来说可能有一定难度,但它...

    PhoneGap环境搭建demo

    PhoneGap是一种开源框架,它允许开发者使用HTML5、CSS3和JavaScript来构建原生的移动应用程序,而无需深入学习各种平台的原生编程语言。PhoneGap环境搭建是开发跨平台移动应用的第一步,这里我们将详细讲解如何进行...

    PHONEGAP入门经典源码

    总之,"PHONEGAP入门经典源码"是学习PhoneGap的宝贵资料,通过深入研究源码,不仅可以掌握PhoneGap的基本使用,还能提升跨平台移动开发的实战能力。在实践中不断探索,结合理论学习,相信你可以快速成长为一名熟练的...

    Android和PhoneGap打包本地网站和在线网站

    在移动应用开发领域,Android和PhoneGap是两个重要的技术平台。Android是由Google开发的开源操作系统,主要用于智能手机和平板电脑,而PhoneGap则是一种跨平台的移动应用开发框架,它允许开发者使用HTML、CSS和...

Global site tag (gtag.js) - Google Analytics