`

PhoneGap在Android上的插件开发方法介绍

 
阅读更多

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

 

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 -->

 

参考资料

学习

讨论

作者简介

秦暕,北京理工大学研究生,目前在IBM Extreme Blue项目实习。对于操作系统、网络协议、Linux内核和移动开发十分感兴趣。

杜冰冰, IBM 中国软件开发实验室 SOA 设计中心软件开发工程师,主要从事 SOA 相关技术的研究和相关项目的实施。您可以通过以下方式与她联系 dubb@cn.ibm.com。

金千里, BM CDL 开发经理。他多年来一直致力于应用程序集成软件的开发,并精通应用程序集成、连接解决方案、面向服务架构和其他相关技术。他撰写了一本图书、一本 IBM 红皮书和多篇 developerWorks 文章。

分享到:
评论

相关推荐

    自定义plugin插件实现phonegap与Android交互

    在"自定义plugin插件实现phonegap与Android交互"这个主题中,我们主要关注的是如何通过编写自定义插件来打通JavaScript和Android之间的通信壁垒。在PhoneGap中,Plugin是连接Web层和Native层的桥梁,它们是用Java...

    phonegap在线更新插件(android)

    本插件专注于PhoneGap在Android平台上的在线更新功能,旨在解决一个特定的问题:即在Android 7.0及以上版本中,通过下载安装APK更新时可能出现的应用闪退现象。 在Android系统中,特别是从7.0版开始,谷歌引入了更...

    android与phonegap混合开发之相互跳转

    在移动应用开发领域,PhoneGap和Android是两种广泛使用的平台。PhoneGap是一种基于HTML5、CSS3和JavaScript的跨平台框架,它允许开发者使用Web技术创建原生移动应用。而Android则是Google主导的开源操作系统,提供了...

    phonegap调用android插件实现GPS定位

    在本教程中,我们将探讨如何使用PhoneGap调用Android插件来实现GPS实时定位。 一、PhoneGap与Android插件 PhoneGap的插件系统是连接Web层和原生层的关键。当在JavaScript中调用一个PhoneGap API时,实际上是在调用...

    Phonegap在安卓平台上的插件开发

    在"Phonegap在安卓平台上的插件开发"这个主题中,我们关注的是如何在PhoneGap应用中创建自定义的插件,以便将前端HTML与Android的原生代码连接起来。具体来说,这个例子涉及到将一个字符串从前端传输到Android的原生...

    phonegap+android开发环境配置

    在配置PhoneGap+Android开发环境时,首先你需要下载并安装Java Development Kit (JDK)。JDK是开发Java程序的基础,包含了编译器、调试器和各种工具,对于Android开发来说必不可少。确保安装的是与操作系统匹配的版本...

    phoneGap实现android程序开发代码

    在这个“phoneGap实现android程序开发代码”中,我们将探讨如何使用PhoneGap进行Android应用开发。 首先,我们需要安装PhoneGap的开发环境。这包括安装Java Development Kit (JDK),Android SDK,以及集成开发环境...

    phoneGap-Android开发环境搭建

    本教程将详细介绍如何搭建PhoneGap在Android平台上的开发环境,以便你可以开始利用Web技术进行Android应用的开发。 首先,我们需要安装Java Development Kit (JDK)。JDK是开发Android应用的基础,因为Android ...

    PhoneGap android的Toast插件

    Android的Toast插件是PhoneGap生态中的一个重要组件,用于在Android设备上显示短暂的通知信息,类似于原生Android开发中的Toast功能。 首先,`ToastPlugin.java`是这个插件的核心Java代码,它负责与PhoneGap的...

    phonegap在android手机上实现短信发送

    在Android平台上,PhoneGap通过WebView组件将Web应用与Android系统的功能进行桥接,使得开发者可以调用Android API,如发送短信。 在Android系统中,发送短信的功能是通过`SmsManager`类提供的。PhoneGap通过创建一...

    基于PhoneGap的Android应用开发

    本篇文章将详细介绍如何使用PhoneGap进行Android应用的开发。 #### 二、环境搭建步骤 ##### Step1:选择开发平台 首先,确定你想要开发的应用平台。在PhoneGap官网上,点击Android图标进入Android开发指南页面。 ...

    phoneGap-android实现拍照和选择图库

    在Android平台上,PhoneGap提供了一个便捷的方式来整合设备的功能,比如摄像头和图库,使得Web开发者能够轻松地实现拍照和选择图库图片的操作。 1. PhoneGap基础: PhoneGap的核心是Cordova,一个开源的移动设备...

    phonegap在android手机上webintent实现

    在Android平台上,PhoneGap通过一个WebView组件将网页内容展示在应用程序中,而WebView则可以与Android系统进行深度交互。本篇文章将详细讲解如何在PhoneGap应用中实现Android的WebIntent功能。 WebIntent是Android...

    Cordova(PhoneGap)Android Native混合开发值传递

    在“Cordova(PhoneGap)Android Native混合开发值传递”中,我们探讨的核心是如何在JavaScript和Android原生代码之间交换数据。这种交互是混合开发的关键,因为它使Web开发者能够利用原生功能,同时保持前端的灵活...

    sencha tocuh利用phonegap开发android的文件浏览器

    在本项目中,“sencha touch利用phonegap开发android的文件浏览器”,我们看到了这两个技术的结合。首先,PhoneGap的File类接口是关键,它遵循W3C的File API标准,提供了访问和操作本地文件系统的能力。开发者可以...

    phonegap插件包Android版本

    2. **Android插件机制**:在PhoneGap中,Android插件是Java代码实现的,它们作为桥接,连接JavaScript与Android的SDK。当JavaScript调用特定的PhoneGap API时,实际的执行是在Android的Activity或Service中进行的。...

    phonegap-android-master

    3. **Android SDK**:为了在Android平台上构建PhoneGap应用,开发者需要安装Android SDK,这是一个包含开发工具、API库和其他必要组件的软件开发套件。通过Android SDK,开发者可以配置Android虚拟设备(AVD)进行...

    PhoneGap开发手册

    PhoneGap基于开放源代码,允许开发者使用HTML、CSS和JavaScript来构建原生的移动应用,这些应用能够运行在多个操作系统上,如iOS、Android、Palm、Symbian、Windows Phone 7 (WP7)、Bada以及Blackberry。PhoneGap的...

    phonegap-android-plugin

    综上所述,"phonegap-android-plugin" 项目涉及到 PhoneGap 插件在 Android 上的开发和兼容性问题,开发者需要对旧插件进行适配,使其能在更现代的 Android 版本上运行。同时,项目包含了标准的 Git 忽略文件和 ...

    android之PhoneGap入门实例

    PhoneGap的核心理念是通过Web技术实现与移动设备硬件的交互,让开发者能够利用熟悉的Web开发技能开发出能在iOS、Android、Windows Phone等多平台运行的应用。 在"android之PhoneGap入门实例"中,我们首先需要了解...

Global site tag (gtag.js) - Google Analytics