PhoneGap 入门指南(四)
原文:Beginning PhoneGap
协议:CC BY-NC-SA 4.0
八、使用 PhoneGap 插件
PhoneGap 附带了一组 JavaScript APIs,用于访问原生电话功能,如摄像头、存储、联系人、地理定位等。,构建跨移动应用。如果您想做 PhoneGap API 中没有的事情,您可以利用 PhoneGap 插件。
在任何技术中,重用已经可用并经过测试的特性都是常见的做法。PhoneGap 有很多重要的第三方插件。例如,访问脸书的认证机制、访问用于移动推送通知的第三方服务等。
什么是 PhoneGap 插件?
PhoneGap 插件是 PhoneGap 功能的扩展。它访问手机上的一项功能。插件功能可能只能访问手机的本机功能,也可能提供访问云服务的功能。
任何 PhoneGap 插件都至少包含两个文件:
JavaScript 文件本地语言文件
插件的 JavaScript 文件是 PhoneGap 应用和 PhoneGap 插件之间的接口。JavaScript 文件使用 JavaScript 函数来访问插件的功能。
PhoneGap 框架使用本地语言文件来与电话交互以访问本地功能。作为插件用户,我们需要将本机代码放入我们的项目结构中。在下一节中,我们将详细研究如何使用这个插件来设置项目。
脸书认证并抓取好友
让我们利用 PhoneGap 插件构建一个小应用,登录到脸书并从脸书获取朋友的信息。
我们的 PhoneGap 应用将使用脸书本地应用通过脸书-PhoneGap 插件为用户执行单点登录(SSO)。
为 Android 设置环境
首先,我们需要为 Android 建立 PhoneGap 项目。请参考第二章为 Android 设置您的项目。一个 Android 项目配置如图图 8–1 所示。
图 8–1。 Eclipse Android 项目配置
从[github.com/davejohnson/phonegap-plugin-facebook-connect/downloads](https://github.com/davejohnson/phonegap-plugin-facebook-connect/downloads)下载脸书连接插件。
脸书连接插件是一个 zip 文件。解压到你喜欢的文件夹里。文件夹结构应类似于图 8–2。
图 8–2。 脸书-连接插件文件夹结构
接下来,您需要执行以下安装步骤:
Register Facebook Plug-in
在 plugins.xml 文件中添加以下 XML 元素作为“plugins”元素的子元素,如 Figure 8–3 所示。您可能需要使用以下命令在 res 文件夹中创建一个 xml 文件夹:
图 8–3。 脸书外挂注册
Include the native part of the plug-in into the project. Copy the libs and src folder from a Facebook-connect-plug-in folder as shown in Figure 8–4 and paste it into the root of our PhoneGap application, i.e., “FaceBookPluginExample”.
图 8–4。 脸书-连接-安卓插件原生文件夹
在项目中包含插件的 JavaScript 部分
有两个 JavaScript 文件需要包含在我们来自脸书的项目中——连接插件。
/www/pg-plugin-fb-connect.js pg-plugin-fb-connect.js文件在脸书插件的 www 文件夹下。将其复制并粘贴到我们项目的 assets/www 文件夹中。/lib/facebook_js_sdk.js facebook_js_sdk.js文件在脸书插件的 lib 文件夹下。将其复制并粘贴到我们项目的 assets/www 文件夹中。
一旦你完成了这三个步骤,你将会看到如图图 8–5 所示的 FaceBookPluginExample 项目结构。
图 8–5。 FaceBookPluginExample 项目结构
初始化脸书连接插件
第一步是确保 index.html 有一个脸书连接库,PhoneGap 库,并且是 CSS 链接的。请注意,我们包含了以下 JavaScript 文件。
JavaScript 语音间隙脸书插件 JavaScript脸书 SDK JavaScript
`
`
现在,我们将在 index.html 页面中定义 JavaScript 函数,以登录到脸书并获取好友列表。以下是登录函数的代码片段:
function login() { FB.login(function(response) {…}, { perms: "email" } ); }
login()函数调用脸书 SDK 的登录函数 FB.login()。脸书的 FB.login()有两个参数。第一个是回调 JavaScript 函数,第二个是 JSON 对象,用于指定权限。我们将’ function(response){…} ‘和’ { perms: “email” } '传递到 FB.login()。脸书的 FB.login()提示用户登录。成功登录后,它调用回调 JavaScript 函数。回调函数获取“响应”对象来标识登录状态。“perms”用于指定用户权限。你可以在脸书开发者网站上找到更多关于脸书登录 API 和用户权限的细节,网址是 http://developers . Facebook . com/docs/reference/API/permissions。
接下来,我们将看到用于获取好友列表的代码片段。为此,我们将创建一个 JavaScript 函数 getFriendList()。
function getFriendList(){ FB.api('/me/friends', function(response) { if (response.error) { alert(JSON.stringify(response.error)); } else { var friends = document.getElementById('friends'); response.data.forEach(function(item) { var d = document.createElement('div'); d.innerHTML = item.name; data.appendChild(d); }); } }); }
在 getFriendList()函数中,调用了脸书 API FB.api()。第一个参数是脸书提供的图形 API 的路径。在我们的示例中,'/me/friends '用于获取登录用户的朋友列表。第二个参数是接收响应的 JavaScript 回调函数。回调方法中执行以下操作:
使用“response.error”检查响应状态是否成功如果响应成功,那么 response 中可用的结果数据将被迭代。为每个项目创建“div”元素,并将其附加到在 index.html 定义的“friends”div 中
接下来,我们将修改 login()函数,以便在成功登录时调用 getFriendList()。
function login() { FB.login( function(response) { if (response.session) { getFriendList(); } else { alert('not logged in'); } }, { perms: "email" } ); }
这里我们检查“response.session”值的成功响应。如果它是有效的,我们就调用 getFriendList()函数。
现在,最后一步是在 PhoneGap 的初始化事件中使用 JavaScript 函数。
document.addEventListener('deviceready', function() { try { /* Initialize the Facebook plug-in. Note that you need to replace the
最后,要运行应用,您需要将脸书的 app_secret 密钥放入 AndroidManifest.xml 文件,如 Figure 8–6 所示。
图 8–6。 脸书 app _ 秘钥
您可以从脸书开发者网站[developers.facebook.com/apps](https://developers.facebook.com/apps).获取脸书应用 id 和应用密码。
在模拟器上将 FacebookPluginExample 作为 Android 应用运行。第一个屏幕将显示脸书登录页面,如图 8–7 所示。
图 8–7。 脸书登录界面
成功登录后,您将看到您的好友列表,如 Figure 8–8 所示。
**图 8–8。**脸书好友列表
您可以使用 jQueryMobile 或 Sencha Touch 以及脸书 PhoneGap 插件来开发一个有吸引力的脸书应用。此外,您可以通过使用脸书插件调用其他脸书图形 API 来添加更多功能。
C2DM 插件,用于向 PhoneGap 发送移动推送通知
推送通知或服务器推送是从服务器向客户端发送数据的最新方式。您是否注意到 Gmail 是如何接收和显示您收件箱中的新邮件的?你不需要刷新浏览器或者点击一些刷新按钮来发送请求和从服务器接收最新的数据。
最近,轮询是接收通知的一种流行技术。轮询技术定期向服务器发送请求,并用收到的响应刷新 UI。您可以将它视为一个后台进程,它以特定的预定义间隔发送请求,并从服务器接收更新或通知。这种方法有许多已知的缺点。轮询方法的主要缺点是识别合适的间隔来发送请求。如果间隔更短,可能会有不必要的请求和响应行程,从而导致带宽和服务器资源的损失。更长的时间间隔可能达不到轮询的目的,因为在接收通知时可能会有延迟,并且它不再符合发送通知的目的。如果没有新数据可用,这种方法会消耗移动电话的电池。
服务器推送允许服务器向客户端发送通知或更新,而无需等待请求。在推送技术中,客户端没有任何后台进程来发出定期请求。在服务器有更新的任何时候,它都可以将更新推送到所有注册的客户端。如果客户端是一个移动应用,这种技术被称为移动推送。
您的 PhoneGap 应用也可以通过 PhoneGap 插件利用移动推送技术。让我们为 Android 平台创建一个小的 PhoneGap 应用来接收来自 C2DM 服务的推送通知。
为 Android 设置环境
首先,我们需要为 Android 设置 PhoneGap 项目。参考第二章为 Android 设置您的项目。一个 Android 项目配置如图图 8–9 所示。
图 8–9。 Eclipse Android 项目配置
我们将使用 Android 云到设备消息(C2DM)框架进行推送通知。你可以在[code.google.com/android/c2dm/#intro](http://code.google.com/android/c2dm/#intro)了解更多关于 C2DM 服务的信息。
从[github.com/awysocki/C2DM-PhoneGap/downloads](http://github.com/awysocki/C2DM-PhoneGap/downloads)下载 C2DM PhoneGap 插件。C2DM-PhoneGap 插件是一个 zip 文件。解压到你喜欢的文件夹里。文件夹结构应该类似于图 8–10 中的列表。
**图 8-10。**C2DM-插件文件夹结构
接下来,您需要执行以下安装步骤:
Register C2DMPlug-in
在 plugins.xml 文件中添加以下 XML 元素作为“plugins”元素的子元素,如 Figure 8–11 所示。您可能需要在“res”文件夹下创建一个 xml 文件夹,并从 PhoneGap Android 示例应用中复制 plugins.xml。
图 8–11。 插件注册
Include the native part of the plug-in into the project
从 C2DM-plug-in 文件夹中复制 src 文件夹,如图 8–12 所示,并将其粘贴到我们的 PhoneGap 应用的根目录中,即“MobilePushPluginExample”。
**图 8–12。**C2DM-插件原生部分
Include the JavaScript part of the plug-in into the project
如 Figure 8–13 所示,从 C2DM-plug-in 文件夹中复制以下文件,并将其粘贴到我们应用的 assets 文件夹中。
C2DMPlugin.jsjquery_1.5.2 最小 jsPG_C2DM_script.jsindex.html 注意,即使 index.html 不是插件的一部分,我们也在项目中使用它来节省创建和包含 js 文件的时间。
图 8–13。 JavaScript 部分插件
注意,我们没有包括 Phonegap.0.9.5.js 文件,因为我们使用的是 PhoneGap-1.1.0。我们将对 PhoneGap-1.1.0 进行必要的修改。
最后,我们需要在 AndroidManifest.xml 文件中添加 C2DM 所需的权限。清单文件应该类似于下面的列表:
`
`
完成前三个步骤后,您将看到 MobilePushPluginExample 项目结构,如图 Figure 8–14 所示。
图 8–14。 MobilePushPluginExample 项目结构
修改 PhoneGap 插件-1.1.0
在写这本书的时候,一个 C2DM 插件是基于 PhoneGap 版本 0.9.5 的。要在 PhoneGap-1.1.0 中使用它,我们必须完成一些修改。
C2DMPlugin.jsfiles.
打开 C2DMPlugin.js 并转到以下函数定义:
`PhoneGap.addConstructor(function() { //Register the javascript plugin with PhoneGap PhoneGap.addPlugin(‘C2DM’, new C2DM());
//Register the native class of plugin with PhoneGap PluginManager.addService(“C2DMPlugin”, “com.plugin.C2DM.C2DMPlugin”);
//alert( “added Service C2DMPlugin”); });`
删除以下行:
//Register the native class of plugin with PhoneGap PluginManager.addService("C2DMPlugin","com.plugin.C2DM.C2DMPlugin");
在 PhoneGap-1.1.0 中,插件必须在 plugin.xml 文件中注册。PhoneGap-1.1.0 中不再提供 PluginManager。我们已经在 plugin.xml 文件中注册了 C2DM-plugin。
现在,修改后的函数如下所示:
`PhoneGap.addConstructor(function() { //Register the javascript plugin with PhoneGap PhoneGap.addPlugin(‘C2DM’, new C2DM());
//alert( “added Service C2DMPlugin”); });`
Move C2DMReceiver.java
我们必须将 C2DMReceiver.java 从 com.phonegap.c2dm 包中移到我们的应用项目中,即 org . examples . mobile push plugin . example,为此,将 C2DMReceiver.java 从 com.phonegap.c2dm 包中拖放到 org . examples . mobile push plugin . example 中,如 Figure 8–15 所示。
图 8-15。C2DMReceiver.java所在地
我们还必须修改 index.html 文件中的 PhoneGap 版本,因为我们是从插件文件夹中复制的。为此,在脚本标记中用 phonegap-1.1.0 替换 phonegap.0.9.5.js。
注册 C2DM 服务
前往[code.google.com/android/c2dm/signup](http://code.google.com/android/c2dm/signup)并填写表格以注册发送者。你必须提到 Android 应用的包名和发件人帐户电子邮件以及其他信息。对于我们的应用,包名应该是“org . examples . mobilepushplugin . example ”,我们应该使用 Google 帐户作为发件人帐户电子邮件。我们必须在 PhoneGap 应用中使用发件人帐户电子邮件 id 来注册接收通知的设备。
在 PhoneGap 中使用 C2DM 发送者帐户
C2DM 插件附带了现成的 PhoneGap deviceready 实现。我们必须使用我们的 C2DM 发送者帐户来注册通知设备。
打开 PG_C2DM_script.js 文件,转到 PhoneGap deviceready 事件实现。将“your_c2dm_account@gmail.com”修改为我们的 c2dm 发件人帐户,如图 8–16 所示。
图 8–16。 向 C2DM 发送方帐户注册应用
支持 C2DM 服务的 Android 模拟器
您需要使用目标为“Google API(Google Inc .)-API Level 8”的 AVD (Android 虚拟设备)来运行支持 C2DM 的 Android 应用。请参考第二章从“Android SDK 和 AVD 管理器”创建新的 AVD。
你还必须在模拟器中添加你的谷歌账户。为此,运行模拟器并打开设置,如图 8–17 所示。
图 8–17。 安卓设置选项
转到“帐户和同步”并点击添加帐户。你必须输入你的谷歌帐号和密码。注意,它不是 C2DM 发送者帐户。这是你的谷歌账户,你用它来从你的安卓手机中检索你的电子邮件和其他东西。
现在您已经准备好测试 C2DM 插件了。将 MobilePushPluginExample 作为 Android 应用运行。确保目标模拟器是 Google API 的模拟器。您将在模拟器上看到图 8–18 所示的屏幕。
图 8–18。??【模拟器上的 mobilepushpluginsampleoutput】??
为了理解屏幕上出现的输出,我们将查看 PG_C2DM_script.js 文件中的 devicereadyevent 回调函数。
这里,window.plugins.C2DM.register()调用插件的方法将设备或模拟器注册到 C2DM 服务中。注册成功后,C2DM 服务器返回注册 Id (REGID)。该 REGID 用于推送通知消息。但是等等,我们的设备不应该推送信息。它是一个通知接收器,对吗?在这里,我们必须理解在手机上运行的 PhoneGap 应用和在 Google 上托管的 C2DM 服务之间的应用服务器的角色。
我们用一个例子来了解一下 C2DM 推送的工作原理。假设 MobilePushPluginExample 安装在多部 Android 手机上。现在,每部手机都从 C2DM 服务接收 REGID。本质上,每个 REGID 都是唯一的。在发送 REGID 之前,C2DM 服务存储关于设备和网络的所有必需信息,以便在发送通知时进一步使用。C2DM 向设备发送通知。现在,中间的应用服务器负责识别更新的数据,并要求 C2DM 向实际的移动设备发送通知。为此,我们的服务器必须知道 REGIDs。
通常,支持 C2DM 的移动应用会将 REGID 发送到我们的服务器。服务器存储运行该应用的所有手机的注册 id。一旦服务器决定发送通知,它就使用 REGID 来请求 C2DM 服务这样做。
我们从 C2DM 服务收到了 REGID,这可以在图 8–18 中看到。现在,您可以使用这个 REGID 发送推送通知。您可以使用 Java servlet 或 php 创建服务器端代码来发送消息。要了解有关如何发送推送通知的更多信息,请访问 Android C2DM 网站:[code.google.com/android/c2dm/index.html#push](http://code.google.com/android/c2dm/index.html#push)。
此外,还有一个命令行工具可用于模拟服务器。转到[curl.haxx.se/download.html](http://curl.haxx.se/download.html)并下载特定于平台的 curl 工具。发送通知有两个步骤:
Get the authentication key
在控制台上运行以下命令:
D:\cURL>curl https://www.google.com/accounts/ClientLogin -d Email=
你必须用你注册的谷歌账号和密码替换和。
运行以上命令后,您将获得类似于以下清单的身份验证密钥:
Auth=DQAAAMEAAABrqkqH2KYjDfCD93tndEF7n81lKgf5vczCwELPSXgW6xm_9EACDu0lsJFGud7fNBI HcRV1Q6zUmLwxFFJqosdn1nYYmGah0yu7fpT8vfjNLAVx8hs5aymz9OULg-pzKOyWWa1-6BDci1TBCoP 2q6ZwJqEjzH6rArHSlD9DhruEKBrogjfBAWyeIm2fs9THvEkilSMO2Q8utoqyfG0id9keCQad5QPV7oO vNSe6urKOV4ZWEKxG7KAlXCsjW18u_m2Az6jj7DlUoVD89MeLvX0W
Send the message to your application running on a simulator
要发送通知,我们将使用身份验证密钥,并通过以下 curl 命令注册:
S:\cURL>curl --header "Authorization: GoogleLoginauth=
将替换为从步骤 1 接收的认证密钥,并由模拟器上的应用接收 REGID。我们正在向模拟器发送“这是测试消息”文本作为推送通知。
我们将在模拟器上看到我们的应用收到的通知,如图 8–19 所示。
图 8–19。 模拟器上的推送消息
如果您想利用 iPhone-PhoneGap 应用的推送通知服务,您可以使用 PhoneGap 插件,该插件位于:[github.com/urbanairship/ios-phonegap-plugin](https://github.com/urbanairship/ios-phonegap-plugin)。它使用城市飞艇服务来推送移动通知。
结论
PhoneGap 插件动态地扩展 PhoneGap 应用,使其包含越界特性。通过使用插件,PhoneGap 应用几乎可以使用任何本机功能。
插件是 PhoneGap 的好朋友,但社区对插件的支持还处于早期阶段。与此同时,PhoneGap 背后的组织正在使流行的插件成为官方的。然而,插件支持还远远不够完善。这方面的一个例子是尝试为 iPhone 编写一个脸书连接应用。当我们试图在 PhoneGap 1.1.0 中使用这个插件时,我们发现它不起作用。我们还发现包含这个插件非常麻烦。我们猜测,对于即将发布的 PhoneGap 来说,对插件的支持将会得到改善,插件将更容易捆绑并在 PhoneGap 应用中使用。
在本章中,我们只讨论了用于脸书连接和云推送的 Android PhoneGap 插件。出于同样的原因,我们添加了关于 iPhone 插件的指针,这些插件需要改进,才能方便有效地使用。
九、扩展 PhoneGap
到目前为止,我们已经看到 PhoneGap 有两个部分
我们从 PhoneGap 应用中调用的 JavaScript 部分我们在 PhoneGap 项目中包含的一个本机部分,用于公开本机电话功能。
这两个部分适用于我们希望访问常见电话功能的情况,包括以下内容:
照相机加速计文件系统地理位置存储服务
然而,我们经常需要超越这些特性。
JavaScript 限制
我们已经看到 JavaScript 在过去十年中性能有所提高;它比五年前快了 100 倍。然而,即使这是真的,有时应用需要做大量的照明,在后台做事情,或者做复杂的操作。出于性能原因,这些最好在本机代码中完成。
例如,如果我们想下载一个多部分文件,它涉及到并行下载文件的不同部分,然后检查其校验和。这一部分最好用 Java 为 Android 编写,用 Objective-C 为 iPhone 编写。
解
如果你还记得第一章的话,我们说过 PhoneGap 是 JavaScript 世界和本地世界之间的桥梁。整个 PhoneGap 框架是基于插件架构的。这意味着 PhoneGap 提供了一种将 JavaScript 函数(以及参数、返回类型和回调)映射到本机代码的机制。
我们可以向 PhoneGap 应用添加本机代码,并使用 JavaScript 轻松公开代码。为此,我们需要两部分
完成繁重工作的本机代码公开此本机代码的 JavaScript 代码
两者都被 PhoneGap 框架粘合在一起。
建筑
PhoneGap 架构如图 9–1 所示。正如我们所观察到的,PhoneGap 有两个部分:PhoneGap JavaScript 引擎和 PhoneGap 原生引擎。我们将本机代码作为插件添加到 PhoneGap 本机引擎,并将 JavaScript 代码作为插件添加到 PhoneGap JavaScript 引擎。
图 9–1。 PhoneGap 架构
范围
本章重点介绍如何扩展 PhoneGap 功能,以暴露更多的本机代码。
但是,请注意,即使您编写了 PhoneGap 插件,注入插件的唯一方法是将插件源代码添加到您的项目中。目前还没有办法将插件构建到包中,并将包添加到 PhoneGap 项目中。当您使用 PhoneGap build 时,这会阻止您使用自定义插件。
对于这一章,让我们保持插件的本质非常简单。我们称之为 helloworld 插件。我们向插件传递一个名称,然后我们得到一个字符串“Hello !现在的时间是”。
这样,我们主要关注插件的桥方面。
为 Android 扩展 PhoneGap
首先,我们将插件创建为 Android PhoneGap 应用的一部分,然后将插件提取出来。这是必需的,因为
该插件需要 PhoneGap jar。我们需要测试插件。
一个插件有两个部分,PhoneGap 框架(桥)的两边各有一个。我们有一个原生部分(一个类扩展插件)和一个使用 PhoneGap 的 JavaScript 框架的 JavaScript 文件。
在我们开始之前,让我们创建一个 Android PhoneGap 项目(参见图 9-2)。第二章中有说明。
图 9–2。 新安卓项目
然后我们需要为 PhoneGap 配置基本的 Android 项目。
更改 MainScreen 类以扩展 DroidGap。将 PhoneGap jar 添加到类路径中。将 PhoneGap JavaScript 库添加到 assets/www 文件夹。
Android 项目看起来如图 9–3 所示。
图 9–3。 安卓项目结构
声明插件的本机部分
现在我们为插件添加一个合适的包,比如“org.examples.phonegap..plugins.simpleplugin”然后我们声明一个名为 Simple Plug-in 的类,它扩展了 PhoneGap 的 com.phonegap.api.Plugin 类,如图 Figure 9–4 所示。
图 9–4。 声明插件的原生部分
一旦你点击“完成”按钮,你将得到如下所示的代码
`package org.examples.phonegap.plugins.simpleplugin;
import org.json.JSONArray;
import com.phonegap.api.Plugin; import com.phonegap.api.PluginResult;
/** * @author rohit * */ public class SimplePlugin extends Plugin {
/* (non-Javadoc) * @see com.phonegap.api.Plugin#execute(java.lang.String, org.json.JSONArray, java.lang.String) */ @Override public PluginResult execute(String action, JSONArray data, String callbackId) { // TODO Auto-generated method stub return null; }
}`
当我们扩展com.phonegap.api.Plugin类时,我们必须实现 execute 方法。execute 方法的参数是
动作:要执行的动作。例如,对于基于文件的插件,可以是打开、关闭、读取、写入等。数据:插件 JavaScript 端传过来的数据。这是从 PhoneGap 的 JavaScript 应用传递到本机代码的数据。例如,对于基于文件的插件,可以是文件名、数据等。CallbackId :回调 JavaScript 函数时使用。
execute 方法的返回类型是 PluginResult。PluginResult 通常接受一个状态枚举和一个描述原因或更多信息的其他参数。
例如,新的 PluginResult(状态。OK);
状态枚举有许多值;所有这些都描述如下(名称不言自明)
没有结果好类未找到异常非法访问异常实例化 _ 异常格式错误 _URL_EXCEPTIONio _ exception(io _ 异常错误)无效 _ 操作JSON _ exception(JSON _ 异常)错误
下面是 hello 插件的实现,它接受一个名称并返回“Hello !时间是文本。
`package org.examples.phonegap.plugins.simpleplugin;
import java.util.Date;
import org.json.JSONArray; import org.json.JSONException;
import com.phonegap.api.Plugin; import com.phonegap.api.PluginResult; import com.phonegap.api.PluginResult.Status;
/** * @author rohit * */ public class SimplePlugin extends Plugin {
public static String ACTION_HELLO=“hello”;
/* * (non-Javadoc) * * @see com.phonegap.api.Plugin#execute(java.lang.String, * org.json.JSONArray, java.lang.String) */ @Override public PluginResult execute(String action, JSONArray data, String callbackId) { PluginResult pluginResult = null; if (ACTION_HELLO.equals(action)) {
String name = null; try { name = data.getString(0);
String result = "Hello " + name + "! The time is " + (new Date()).toString();
pluginResult = new PluginResult(Status.OK, result);
return pluginResult; } catch (JSONException e) { pluginResult = new PluginResult(Status.JSON_EXCEPTION, “missing argument name”); } } else { pluginResult = new PluginResult(Status.INVALID_ ACTION, “Allowed actions is hello”); } return pluginResult; } }`
您可以在上面的代码中看到,在处理请求之前,我们显式地检查了一个操作。如果动作不是由插件处理的,我们返回Status.INVALID_ACTION。第二个检查是针对参数的。如果我们在获取第一个字符串参数时得到任何 JSON 异常,我们返回Status.INVALID_JSON。当动作和参数正确时,我们创建一个字符串“Hello < name >!时间是<时间>,用Status.OK返回。
请注意,您不必从这个方法中产生任何线程。您的整个方法可以是同步的。这将不会传递调用该代码的 JavaScript 插件调用。这是由 PhoneGap 内部处理的,这就是为什么我们在 JavaScript 中有成功和失败回调(您将在下一节看到)。
声明插件的 JavaScript 部分
这个插件的 JavaScript 部分是在一个名为 simpleplugin.js 的文件中声明的。
Plug-in Registration
在 PhoneGap 插件的 JavaScript 部分,事情是从调用在 PhoneGap 中添加插件开始的。
PhoneGap.addConstructor(**function**() { // Register the Javascript plug-in with PhoneGap PhoneGap.addPlugin('SimplePlugin', **new** SimplePlugin()); });
插件在/res/xml/plugins.xml 文件中注册。将以下 XML 元素添加为 plugins.xml 文件中“plugins”元素的子元素:
注意:这里我们做了两件事
将 JavaScript 对象注册为名为“SimplePlugin”的插件将 PhoneGap Java 类注册为名为“SimplePlugin”的服务您可以将此视为类名“org.examples.phonegap.plugins.simpleplugin.Simple Plugin.”的别名 Create the JavaScript object SimplePlugin.
这是通过声明一个 JavaScript 函数来完成的。
var SimplePlugin = function() { }
Add a plug-in function.
在这一步中,我们将添加插件函数,我们的 JavaScript 将调用该函数。在下面的函数中,我们实际上将调用委托给本机 PhoneGap 桥,要求它实际调用“SimplePlugin”服务,即“org.examples.phonegap.plugins.simpleplugin.SimplePlugin”类。此外,我们注册了两个回调:一个是调用成功时的回调,另一个是调用失败时的回调。然后我们声明我们想要调用的动作。您可能还记得,我们的插件类中有处理“hello”服务的代码。最后,记住我们插件类的执行方法需要一个参数JSONArray;在这里,我们将其作为[name]传递。
`SimplePlugin.prototype.hello = function(name, successCallback, failureCallback) {
PhoneGap.exec( successCallback, // Success Callback failureCallback, // Failure Callback ‘SimplePlugin’, // Registered plug-in name ‘hello’, // Action [name] //Argument passed in ); };`
完整的 JavaScript 文件 simpleplugin.js 如下所示:
`/** * * @return Instance of SimplePlugin * / var SimplePlugin = function() {
}
/** * @param name * The name passed in * @paramsuccessCallback * The callback that will be called when simple plugin runs * successfully * @paramfailureCallback * The callback that will be called when simple plugin * fails */ SimplePlugin.prototype.hello = function(name, successCallback, failureCallback) { PhoneGap.exec(successCallback, // Success Callback failureCallback, // Failure Callback ‘SimplePlugin’, // Registered Plug-in name ‘hello’, // Action [ name ]); // Argument passed in };
/** *
*
Register the Simple Listing Javascript plugin.
*/ PhoneGap.addConstructor(function() { // Register the Javascript plug-in with PhoneGap PhoneGap.addPlugin(‘SimplePlugin’, new SimplePlugin()); });`
调用插件
是时候测试我们的插件了。为此,我们需要以下内容:
HTML 文件PhoneGap js 文件插件 js 文件插件 Java 文件
您的 Android 项目应该如 Figure 9–5 所示。
图 9–5。 Android PhoneGap 插件项目结构
您的 index.html 文件应该如下所示:
`
PhoneGap
var text = textbox.value;
window.plugins.SimplePlugin.hello(text, //success callback
function(result) { output.innerHTML = result; } //failure callback, , function(err) { output.innerHTML = “Failed to invoke simple plugin”; }); });
}, true);
Simple Plugin Demo
Enter Name Output:
Say Hello
`
在这里,您应该注意到插件的调用如下。我们首先传递包含名称的文本,然后注册一个成功的回调和一个失败的回调。
window.plugins.SimplePlugin.hello( text, //success callback function (result) { output.innerHTML = result; }, //failure callback function (err) { output.innerHTML = "Failed to invoke simple plugin"; } );
最后,当我们运行这个 Android 项目时,我们会看到下面的输出,如 Figure 9–6 所示。
**图 9–6。**Android 上的 PhoneGap 插件输出
分享 Android PhoneGap 插件
就 PhoneGap framework 1 . 1 . 0 版(写这本书时的版本)而言,没有办法打包和共享你的插件。
共享插件的唯一方式是通过
共享 Java 源文件共享 JavaScript 源文件自述文件,说明如何使用插件
PhoneGap 插件通常在[github.com/phonegap/phonegap-plugins](https://github.com/phonegap/phonegap-plugins).上传。如果您希望贡献您的工作,您可以与 PhoneGap 团队合作,将您的插件添加到这个存储库中。
为 iPhone 扩展 PhoneGap
PhoneGap 为 XCode 提供插件,用于创建基于 PhoneGap 的应用。在写这本书的时候,PhoneGap 从 0.9.5 版本升级到了 1.1.0 版本。iPhone-PhoneGap 插件框架有一些变化。本章重点介绍 1.1.0 插件开发。
安装 1.1.0 XCode 扩展的步骤:
下载 PhoneGap 1.1.0 zip 并解压。转到 iOS 文件夹,安装 PhoneGapInstaller.pkg。
安装 PhoneGap 的 1.1.0 XCode 插件后,从 XCode 创建一个基于 PhoneGap 的应用,如图图 9–7 和图 9–8 所示。
图 9–7。 创建新的 iOS PhoneGap 项目
图 9–8。 创建一个新的 iOS PhoneGap 项目
按照第三章中的步骤将 www 文件夹添加到项目中。现在运行项目,并确保您能够看到基于 iPhone PhoneGap 的应用。
声明插件的本机部分
PhoneGap 1.1.0 插件的本机部分需要添加到插件文件夹中。这在图 9–9 中进行了描述。
图 9–9。 iPhone 插件原生部分
在插件文件夹中创建一个 Objective-C 类。让我们把这个类命名为 SimplePlugin。SimplePlugin 扩展了 PGPlugin。SimplePlugin.h 文件如下所示。
`#import
@interface SimplePlugin :PGPlugin {
} /** * Sets the idleTimerDisable property to true so that the idle timeout is disabled */
(void) hello:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
@end`
这里我们声明一个函数名“hello”,它有如下签名:
- (void) hello:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
这个函数不返回任何东西。相反,它需要两个参数
争论选择
插件或输入(在我们的例子中是名称)的任何参数都使用“参数”传递
现在让我们实现 SimplePlugin 的 hello 函数。在第一个版本中,我们将从插件返回一个字符串“hello world”。此外,我们将解释如何访问传递的参数,以及如何调用成功和失败的回调。
注意插件是从 JavaScript 调用的,如下所示:
window.plugins.SimplePlugin.hello( “Bob”, //success callback function(result){ alert(“plugin returned “+result); }, //failure callback, function(err){ alert(“got error when invoking the plugin”); } );
下面是插件方法的框架代码。
插件可以访问输入参数,在我们的例子中是“Bob”,从 arguments 对象中提取它。注意,arguments 数组中的第一个对象总是 callbackId,用于回调 JavaScript 回调函数。我们可以从索引 1 开始提取实际参数(在我们的例子中,只有“Bob”)。
NSString * name = [arguments objectAtIndex:1];
如果我们有另一个参数,我们将在索引 2 处访问它。
现在让我们关注如何调用成功或失败的 JavaScript 回调函数。这从 PluginResult 对象的声明开始。接下来声明另外两个对象,一个用于 callbackId(帮助我们调用回调函数),另一个是一个字符串,JavaScript 字符串,我们将把它嵌入到 HTML 页面中以实际调用回调。
NSString* jsString = nil; NSString* callbackId = [arguments objectAtIndex:0];
现在让我们来看一下成功和失败条件的代码流。这显示在下面的代码中。
如果一切顺利,我们创建一个状态为 PGCommandStatus_OK 的结果对象。然后我们从结果中创建 jsString 对象,传递 callbackId。最后,我们编写 JavaScript,通过调用[self writeJavascript:jsString]来实际调用成功回调。
在失败的情况下,我们创建一个状态不是 PGCommandStatus_OK 的 PluginResult 对象,并为错误/失败回调创建 jsString。最后,我们使用[self:write JavaScript:jsString]调用错误/失败回调:
`PluginResult* result=nil; NSString* jsString=nil; NSString* callbackId=[argumentsobjectAtIndex:0];
if(success){ result=[PluginResultresultWithStatus:PGCommandStatus_OK]; jsString=[resulttoSuccessCallbackString:callbackId]; } else{ result=[PluginResultresultWithStatus:PGCommandStatus_ILLEGAL_ACCESS_EXCEPTION]; jsString=[resulttoErrorCallbackString:callbackId]; }
[selfwriteJavascript:jsString];`
如果我们希望在调用成功或失败回调时传递数据,我们可以通过在创建 PluginResult 对象时传递一个附加参数来实现。这里我们通过调用 PluginResult 的 resultWithStatus:messageAsString 函数来传递一个字符串。
result = [PluginResultresultWithStatus:PGCommandStatus_OK messageAsString:@”Hello World”];
完整的 SimplePlugin 如下所示。注意,这里我们没有负路径,因此,我们只为成功回调创建 jsString。
`#import “SimplePlugin.h”
@implementation SimplePlugin
(void) hello:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options { PluginResult* result = nil; NSString* jsString = nil; NSString* callbackId = [arguments objectAtIndex:0]; NSString* name = [arguments objectAtIndex:1]; NSDate* date = [NSDate date]; NSDateFormatter* formatter = [[[NSDateFormatteralloc] init] autorelease];
//Set the required date format
[formatter setDateFormat:@“yyyy-MM-ddhh:mm:ss”];
//Get the string date
NSString* dateStr = [formatterstringFromDate:date];
NSString* returnStr = [NSStringstringWithFormat:@“Hello %@.The time is %@!”, name,dateStr];
result = [PluginResultresultWithStatus:PGCommandStatus_OK messageAsString:returnStr]; jsString = [result toSuccessCallbackString:callbackId ];
[selfwriteJavascript:jsString]; } @end`
只是创造了。h 和。m 文件并将文件放在插件文件夹中是不够的。我们需要向 PhoneGap 框架注册我们的 SimplePlugin。在 Supporting Files 文件夹中的 PhoneGap.plist 文件中添加一个条目就可以做到这一点。
这显示在图 9–10 中。
图 9-10。 注册 PhoneGap 插件
声明插件的 JavaScript 部分
iPhone 插件的 JavaScript 部分和你见过的 Android 不同。
这主要分两步完成
声明一个名为 SimplePlugin 的 JavaScript 类,并向其添加一个方法,在我们的示例中为“hello”。在 hello 函数中,我们将 JavaScript 参数映射到目标插件类和方法。第二部分是为 SimplePlugin 创建一个方法 install,通过调用 phonegap . add constructor(simple plugin . install)注册 JavaScript 插件;
我们先来关注一下插件的 hello 功能。注意,我们在插件内部调用 PhoneGap.exec 函数。
继 PhoneGap.exec 的签名之后
PhoneGap.exec(<
注意我们如何将 hello 函数的第一个参数“name”作为参数数组的一部分传递。successCallback 和 errorCallback 作为 PhoneGap.exec 函数的第一个和第二个参数。插件类和方法名作为第三和第四个参数。
SimplePlugin.prototype.hello = function(name,successCallback, errorCallback) { PhoneGap.exec( successCallback, errorCallback, "SimplePlugin", "hello", [name]); };
JavaScript 部分的完整代码如下所示。
`if (!PhoneGap.hasResource(“simpleplugin”)) { PhoneGap.addResource(“simpleplugin”);
/** * @returns instance of powermanagement */
function SimplePlugin() {};
/** * * @param name Given the name, successCallBack gets the string “Hello ! The time is .” * @paramsuccessCallback function to be called when the wake-lock was acquired successfully * @paramerrorCallback function to be called when there was a problem with acquiring the wake-lock */ SimplePlugin.prototype.hello = function (name, successCallback, errorCallback) { PhoneGap.exec(successCallback, errorCallback, “SimplePlugin”, “hello”, [name]); };
/** * Register the plug-in with PhoneGap */ SimplePlugin.install = function () { if (!window.plugins) window.plugins = {};
window.plugins.SimplePlugin = new SimplePlugin();
return window.plugins.SimplePlugin; };
PhoneGap.addConstructor(SimplePlugin.install); }`
调用插件
为了测试插件,我们将创建一个 PhoneGap 应用,并从那里调用插件。这部分和安卓的一模一样。
你需要遵循这些步骤
包括 PhoneGap 1.1.0 js 文件。包括 simpleplugin.js 文件。注册按钮点击调用插件。注册成功和失败回调以显示结果。
index.html 的完整源代码如下:
`
PhoneGap
btn.addEventListener(‘click’, function() {
var text = textbox.value;
window.plugins.SimplePlugin.hello(text, //success callback
function(result) { output.innerHTML = result; } //failure callback, , function(err) { output.innerHTML = “Failed to invoke simple plugin”; }); });
}, true);
Simple Plugin Demo
Enter Name Output:
Say Hello
`
当您运行 PhoneGap 示例时,您将看到如图 Figure 9–11 所示的应用。
图 9–11。??【PhoneGap】插件输出
共享 iPhone PhoneGap 插件
您需要共享以下文件来共享插件。
SimplePlugin.h简单插头.m简单插头.js
将上述文件列表添加到插件文档中。还要记录如何从 JavaScript 调用插件。
为 BlackBerry 扩展 PhoneGap
与 Android 类似,PhoneGap 针对 BlackBerry 的插件有两个部分,分别位于 PhoneGap 框架(桥)的两侧。我们有一个原生部分(一个类扩展 PhoneGap 的插件)和一个使用 PhoneGap 的 JavaScript 框架的 JavaScript 文件。
我们假设您使用的是高于 1.5 版的 BlackBerry WebWorks SDK 版本。
我们假设 BlackBerry WebWorks SDK 安装在 C:\BBWP 上,我们安装了 Java 1.6 SDK 和 Ant,并且在 path 中。我们还假设我们的开发目录是 D:\PhoneGap-Plugin,我们在 D:\ PhoneGap-Plugin \ PhoneGap-1 . 1 . 0 目录中有 PhoneGap SDK。参考第三章回忆 BlackBerry PhoneGap 开发的系统要求。
创建和测试 BlackBerry 插件的步骤如下:
创建插件 Java 文件,并将其转储到 PhoneGap SDK 的框架中。创建 BlackBerry PhoneGap 项目来测试插件。然后编译 BlackBerry PhoneGap 项目来编译插件 Java,您将它转储到 PhoneGap SDK 的框架文件夹中。如果出现编译错误,您需要删除您在步骤 2 中创建的项目,修复 Java 文件,并从步骤 2 开始重复。当插件 Java 文件编译无误时,您就可以转储 JavaScript 插件文件并编写 HTML 页面来使用该插件。
声明插件的本机部分
BlackBerry 插件类与 Android 插件类非常相似。唯一不同的是 BlackBerry 插件类使用 PhoneGap 1.1.0 框架;因此,有几个不同之处。
以下是 BlackBerry 插件类的框架:
`package com.phonegap.plugins;
import com.phonegap.api.Plugin; import com.phonegap.api.PluginResult;
import java.util.Date; import com.phonegap.json4j.JSONArray;
public class HelloWorldPlugin extends Plugin {
private static final String ACTION_HELLO=“hello”;
/** * Executes the requested action and returns a PluginResult. * * @param action The action to execute. * @paramcallbackIdThe callback ID to be invoked upon action completion. * @paramargsJSONArry of arguments for the action. * @return A PluginResult object with a status and message. */ public PluginResult execute(String action, JSONArray data, String callbackId) { return null; }
/** * Called when the plug-in is paused. */ public void onPause() {
}
/** * Called when the plug-in is resumed. */ public void onResume() {
}
/** * Called when the plug-in is destroyed. */ public void onDestroy() {
} }`
注意,我们不是将这个插件类转储到我们的项目区域,而是转储到 PhoneGap SDK 区域。Figure 9–12 中的屏幕截图显示了我们复制这个插件类的位置。您可能需要创建插件文件夹。
图 9–12。?? 插件的原生部分
这里的主要问题是,在继续之前,您需要在上面的目录中有一个适当的 Java 插件类(它可以编译)。我们会引导你度过这一关。
下一步是创建 BlackBerry WebWorks PhoneGap 项目。
$>D: $>cd d:\PhoneGap-plugin\phonegap-1.1.0 $>ant create -Dproject.path=D:\PhoneGap-Plugin\BB-Plugin-Test
这将向您显示图 9–13 中所示的目录。
图 9–13。 PhoneGap 黑莓项目结构
现在让我们确保我们的插件类是否编译。
$>cd D:\PhoneGap-Plugin\BB-Plugin-Test $>ant build
如果上述步骤在 HelloWorldPlugin 中显示了一些编译错误,您需要
修复那些编译错误。删除位于 D:\ PhoneGap-Plugin \ b B- Plugin-Test 的项目。使用 Ant create-D project . path = D:\ PhoneGap-Plugin \ b B- Plugin-Test 重新创建项目。使用“ant build”检查编译。
现在,您已经解决了编译空白 Java 插件类的问题,让我们在其中放一些代码。
下面是插件类的完整代码(这与 Android 插件非常相似)。我们公开一个名为“hello”的动作,并期望一个名为“name”的参数假设有人用“Rohit”这个名字叫出了“hello”这个动作,我们会返回“Hello Rohit!时间是。”
`package com.phonegap.plugins;
import com.phonegap.api.Plugin; import com.phonegap.api.PluginResult;
import java.util.Date; import com.phonegap.json4j.JSONArray;
public class HelloWorldPlugin extends Plugin {
private static final String ACTION_HELLO=“hello”;
/** * Executes the requested action and returns a PluginResult. * * @param action The action to execute. * @paramcallbackIdThe callback ID to be invoked upon action completion. * @paramargsJSONArry of arguments for the action. * @return A PluginResult object with a status and message. */ public PluginResult execute(String action, JSONArray data, String callbackId) { PluginResult pluginResult=null; if (ACTION_HELLO.equals(action)) {
String name; try { name = data.getString(0); String result = "Hello " + name + "! The time is " + (new Date()).toString(); pluginResult = new PluginResult(PluginResult.Status.OK, result); returnpluginResult; } catch (Exception e) { pluginResult = new PluginResult(PluginResult.Status.JSONEXCEPTION, “missing argument name”); }
} else { pluginResult = new PluginResult(PluginResult.Status.INVALIDACTION, “Allowed actions is hello”); } return pluginResult; }
/** * Called when the plug-in is paused. */ public void onPause() {
}
/** * Called when the plug-in is resumed. */ public void onResume() {
}
/** * Called when the plug-in is destroyed. */ public void onDestroy() {
} }`
请注意,您必须在 PhoneGap 的框架中再次转储修改后的 HelloWorldPlugin.java,如图 9–13 所示。您还必须使用 Ant create-D project . path = D:\ PhoneGap-Plugin \ b B- Plugin-Test 删除并重新创建项目,以测试插件。
声明插件的 JavaScript 部分
同样,插件的 JavaScript 部分与插件的 Android JavaScript 部分非常相似。在这种情况下,我们在函数声明中声明所有内容,并调用它。
(function () { var HelloWorld = function () { return { hello: function (message, successCallback, errorCallback) { PhoneGap.exec(successCallback, errorCallback, 'HelloWorldPlugin', 'hello', [message]); } } }; ` PhoneGap.addConstructor(function () { // add the plug-in to window.plugins PhoneGap.addPlugin(‘simpleplugin’, new HelloWorld());
// register the plug-in on the native side phonegap.PluginManager.addPlugin(‘HelloWorldPlugin’, ‘com.phonegap.plugins.HelloWorldPlugin’); }); })();`
第一步是创建一个名为 HelloWorld 的 JavaScript 对象,并在其中声明一个名为“hello”的函数。该函数在内部调用 PhoneGap 注册的服务,该服务又调用实际的本地类。
现在我们有了这个对象,它将从我们的 HTML 中被调用,我们需要将这个对象注册为 PhoneGap JavaScript 插件。我们还需要将服务名“helloworldplugin”映射到类“com . phonegap . plugins . hello world plugin”,所有这些都是在 PhoneGap.addConstructor()调用中完成的。
我们使用 PhoneGap.addPlugin()将“simpleplugin”名称映射到 JavaScript 插件对象。这将插件公开为 windows.plugins.simpleplugin。
然后我们用 phonegap。PluginManager.addPlugin()将服务名映射到实际的 Java 类。
这就完成了我们创建插件的 JavaScript 部分。我们将把这个 JavaScript 放在项目的 www 目录中。
调用插件
为了调用插件,我们修改了项目 www 目录中的 index.html 文件。
这与我们之前为 Android 和 iPhone 所做的非常相似。
下面是用于调用我们的插件的代码片段:
window.plugins.simpleplugin.hello( document.getElementById("name").value, //success callback function (message) { document.getElementById("output").innerHTML = message; }, //failure callback function () { log("Call to plugin failed"); } );
正如我们前面所做的,我们提供名称;在这种情况下,名称来自输入类型文本元素。然后我们提供一个成功回调和一个失败回调。在成功回调中,我们在 id 为“output”的 div 中设置返回值。
以下是 index.html 页面的完整代码:
`
function onDeviceReady() { }
function sayHello() {
window.plugins.simpleplugin.hello(document.getElementById(“name”).value, //success callback
function(message) { document.getElementById(“output”).innerHTML = message; }, //failure callback
function() { log(“Call to plugin failed”); });
}
// register PhoneGap event listeners when DOM content loaded
function init() { document.addEventListener(“deviceready”, onDeviceReady, true); }
Simple Plugin Demo
Enter Name Output:
Say Hello
…
`
最后一步是运行 WebWorks BlackBerry 项目。转到命令提示符,转到项目目录,并运行以下命令:
$>ant build load-simulator
这将打开黑莓模拟器,你可以看到我们的应用在里面运行。在文本框中输入一个值,然后点击按钮。您将看到如图图 9–14 所示的结果。
图 9–14。??【PhoneGap】插件输出
共享 BlackBerry PhoneGap 插件
要共享插件,您需要发布两个文件
helloworldplugin.javahelloworld.js
将上述内容添加到关于如何从 JavaScript 调用插件的文档中。
结论
虽然 JavaScript 对于开发跨移动应用来说是一种快速而灵活的语言,但在实现复杂的处理和后台工作时,JavaScript 有某些固有的局限性。有时有必要使用本机代码来执行繁重的工作。
PhoneGap 的架构允许我们扩展其插件,为我们的 PhoneGap 应用引入本机代码。