当前位置: 首页 > 编程日记 > 正文

使用面向 iOS 的本机插件扩展 PhoneGap

本文细致探讨了 Xcode(以 iOS 设备为目标)中的 PhoneGap(也称为 Apache Cordova)应用程序本机插件。如果您刚开始接触 PhoneGap 或者需要回顾 PhoneGap 基础知识,请先阅读 Xcode for iOS 的 PhoneGap 入门,然后再继续阅读本文。

本文交替使用术语 Cordova 和 PhoneGap 指示同一开源应用程序平台,该平台可供您使用 HTML 和 JavaScript 创建本机安装的移动应用程序。PhoneGap 代码库已迁移至 Apache 软件基金会的开放资源中,名为 Cordova。Adobe 则仍以 PhoneGap 名称进行分发。有关更多信息,请参阅 Brian Leroux 发布的博客文章“PhoneGap、Cordova、名称有什么关系?”正如 Brian 在这篇文章中所说,“目前唯一的区别在于下载包名称的不同,并且这种情况仍将维持一段时间。

PhoneGap 不仅可让您利用 Web 技术为本机安装的移动应用程序构建用户界面,还能提供基于 JavaScript 的 API 供您与本机设备功能进行交互。默认情况下,PhoneGap 可访问设备摄像头、加速计、文件系统、GPS 位置及其他功能间的媒体重放。但是,PhoneGap 并未揭示供您在 JavaScript 应用程序内使用的每一个本机 API。如果您希望 PhoneGap 执行其默认功能集以外的操作,可以使用 PhoneGap 本机插件模型扩展核心 PhoneGap API 的功能。

PhoneGap 本机插件与桌面浏览器的插件不同;它们为您提供了一种插件自定义代码以增加 PhoneGap 应用程序框架功能的方式。PhoneGap 本机插件可让您以本机代码的形式创建全新的自定义功能,并通过 PhoneGap 的本机-JavaScript 桥将其显示给 PhoneGap 应用程序。这意味着,您可以显示所有本机库或框架,以便在基于 JavaScript 的 PhoneGap 应用程序内部使用。

了解 PhoneGap 本机插件的结构

在您开始编写 PhoneGap 本机插件之前,了解 PhoneGap 应用程序容器如何向基于 JavaScript 的应用程序显示本机操作系统功能将会有所帮助。

所有 Cordova API 均包含以下两个有关部件:一个可以在您的应用程序内部进行访问的基于 JavaScript 的界面,以及用于以本机代码执行操作的对应本机类。通常情况下,JavaScript 类和本机类具有相互镜像的 API,这样就能轻松地进行跟踪。JavaScript 类使用 Cordova.exec() 函数调用本机代码。当它调用 Cordova.exec时,可将其传递至结果处理程序函数和错误处理程序函数,同时还会将一组参数传递至本机代码,并将引用传递至本机类名称和本机函数名称。Cordova 将负责管理 JavaScript 与本机之间的通信,您可以专心构建自己的应用程序。

要了解有关 PhoneGap 本机插件的更多信息,请登录 Cordova wiki 查看该核心 API 的源代码。整个 PhoneGap 框架均构建于同一模式之上,您可以在这里了解这一模式。

构建首个插件

要开始构建您的首个 PhoneGap 插件,您需要按照 Xcode for iOS 的 PhoneGap 入门一文中所述的步骤创建一个新 PhoneGap 项目。我将自己的项目命名为 MyFirstPhoneGapNativePlugin。

JavaScript 类

在您设置完 Hello Xcode 项目后,即可准备为本机插件创建 JavaScript 界面。您需要使用函数(将要镜像通过本机代码显示的逻辑)创建类。在 www 文件夹下,创建一个名为 HelloPlugin.js 的 JavaScript 文件,其中包含如下所示的简单 JavaScript 类。

var HelloPlugin = { callNativeFunction: function (success, fail, resultType) { return Cordova.exec( success, fail, "com.tricedesigns.HelloPlugin", "nativeFunction", [resultType]); }};

HelloPlugin 类包含一个名为 callNativeFunction 的函数,它接收了一个成功回调函数、一个错误回调函数和一个 resultType 字符串参数。callNativeFunction 函数包含 Cordova.exec 函数,因而将会调用实际本机代码。此类中没有其他 JavaScript,但您可以根据自身需要在此处添加 JavaScript 代码。

调用 Cordova.exec 后,将会看到以下五个参数:

  • 一个成功回调函数(本机代码层成功响应时调用的函数)引用
  • 一个错误回调函数(本机代码层错误响应时调用的函数)
  • 一个本机代码类字符串引用(我将会在下文进行详细介绍)
  • 一个应当调用的函数名称字符串引用
  • 一个将要传递至本机代码的参数数组

请记住,JavaScript 和本机代码层之间的代码执行操作并不同步,因此,在开发 PhoneGap 本机插件时需要使用回调函数和异步编码实践。

本机类

要创建本机代码层,请首先创建一个新的本机 Objective-C 类,它扩展核心 Cordova API 的 CDVPlugin 类:

  1. 右键单击 PhoneGap 项目内的 Plugins 目录,然后选择 New File(参见图 1)。

创建新文件。
图 1. 创建新文件。

  1. 在 New File 向导中,选择 Objective-C 类模板,然后单击 Next(参见图 2)。

选择 Object-C class 模板。
图 2. 选择 Object-C class 模板。

  1. 键入 HelloPlugin 作为新类的名称,并将该类纳为 CDVPlugin 的子类(参见图 3)。

命名该类。
图 3. 命名该类。

CDVPlugin 类是所有 Cordova 类均必须扩展的父类。CDVPlugin 类通过 PhoneGAP API 封装本机 JavaScript 通信所需的所有必要逻辑。PhoneGap.exec 函数可让您调用该新类上的函数。CDVPlugin 类包含一个名为writeJavascript 的核心函数,可让您调用 PhoneGap 应用程序 Web 视图内的 JavaScript。本机到 Web JavaScript 这一方向的所有通信均必须使用 writeJavascript 函数完成。

  1. 单击 Next。
  2. 出现提示后,为新文件指定位置(最好指定在 Xcode 项目内的 Plugins 目录下),然后单击 Finish 继续操作。

您将会在 PhoneGap 项目内看到一个新的头文件 (.h) 和一个新的实现文件 (.m)(参见图 4)。

图 4. 新的本机类文件。
图 4. 新的本机类文件。

  1. 接下来,在您的 .h 文件中为 nativeFunction 函数添加定义;例如:

#import <Cordova/CDV.h>@interface HelloPlugin : CDVPlugin- (void) nativeFunction:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;@end

此定义包含以下两个参数:一个是 NSMutableArray,其中包含从 JavaScript 层和选项字典(地图)接收到的参数。在本例中,您只需要关注参数数组。头文件只包含方法签名;您无需在 .h 文件中包含任何应用程序逻辑。

  1. 在您创建类签名后,将逻辑添加到 .m 文件的 nativeFunction 函数实例中。您将在下面看到此本机插件类内部使用的 Objective-C 函数示例。

#import "HelloPlugin.h"@implementation HelloPlugin- (void) nativeFunction:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options { //get the callback id NSString *callbackId = [arguments pop]; NSLog(@"Hello, this is a native function called from PhoneGap/Cordova!"); NSString *resultType = [arguments objectAtIndex:0]; CDVPluginResult *result; if ( [resultType isEqualToString:@"success"] ) { result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: @"Success :)"]; [self writeJavascript:[result toSuccessCallbackString:callbackId]]; } else { result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString: @"Error :("]; [self writeJavascript:[result toErrorCallbackString:callbackId]]; }}@end

在 nativeFunction 方法内部,您首先需要获取一个 NSString callbackId 引用,核心 PhoneGap API 借此将此函数响应映射到调用此函数的原始 JavaScript。

接下来,此方法使用 NSLog 将消息写入 Xcode 调试控制台;这只是表明它目前正在执行本机代码。

写入到调试控制台后,该函数将会检查传递到该函数的 resultType,然后创建相应的 CDVPluginResult 实例。resultType 值是一个简单字符串。如果 resultType 是 success",则该函数将创建 success 结果,并使用 [self writeJavascript] 函数将成功回调函数写入 JavaScript 层。任何其他 resultType 参数值均将生成 error 结果,并且该函数会将错误回调写入 JavaScript 层。

当您将成功或错误回调函数写回 JavaScript 时,始终使用 CDVPluginResult 实例。但是,您也可以使用writeJavascript 函数将任意 JavaScript 字符串传递回 JavaScript 层。这项技术甚至还可用于将数据从本机层实时推送至 JavaScript 层。

调用插件

鉴于您已经创建插件,因而可以从 PhoneGap 应用程序内部进行调用。

  1. 首先,您需要向新插件的 JavaScript 接口类 (HelloPlugin.js) 添加一个引用。在您的 index.html 文件内添加一个新的 <script> 标记:

<script type="text/javascript" charset="utf-8" src="HelloPlugin.js"></script>

  1. 同样也是在onDeviceReady() 函数后,添加 JavaScript 以调用本机插件及处理插件结果。添加名为callNativePluginnativePluginResultHandler 和 nativePluginErrorHandler 的 JavaScript 函数,如下所示:

function callNativePlugin( returnSuccess ) { HelloPlugin.callNativeFunction( nativePluginResultHandler, nativePluginErrorHandler, returnSuccess );} function nativePluginResultHandler (result) { alert("SUCCESS: \r\n"+result );}function nativePluginErrorHandler (error) { alert("ERROR: \r\n"+error );}

  1. callNativePlugin 函数只需调用 JavaScript 的本机插件类接口。当其调用 callNativeFunction 方法时,即会传递从本机代码层接收到的成功和错误状态回调函数。如果本机层成功返回回调函数,将会调用nativePluginResultHandler 函数,而当本机层传回错误回调时,则调用nativePluginErrorHandler 函数。
  1. 接下来,根据下列代码添加两个 JavaScript 按钮以调用该插件。

<body onload="onBodyLoad()"> <h1>Hey, it's Cordova!</h1> <button onclick="callNativePlugin('success');">Click to invoke the Native Plugin with an SUCCESS!</button> <button onclick="callNativePlugin('error');">Click to invoke the Native Plugin with an ERROR!</button></body>

单击第一个按钮将调用 callNativeFunction 方法,同时生成参数 "success"。PhoneGap 将于随后执行本机代码并在 JavaScript 层调用成功回调(它将会调用 nativePluginResultHandler 函数)。

当您单击第二个按钮时,将会调用 callNativeFunction 方法,同时生成参数 "error"。PhoneGap 将执行本机代码并在 JavaScript 层调用错误回调(它将会调用 nativePluginErrorHandler 函数)。

映射本机代码类

此时,您几乎已将所有事物串联起来并可准备执行操作,但您还必须再完成一个步骤,才能调用 JavaScript 中的本机代码。

您必须添加一个映射,以便 Cordova 识别您的本机代码类。还记得在调用 Cordova.exec 时用来识别本机类的字符串引用吗?您需要将该字符串映射到 Cordova.plist 文件中的实际类实例。Cordova.plist 文件包含当前 Cordova 项目的所有配置信息。

  1. 在项目导航器中,打开 Supporting Files 文件夹,然后单击名为 Cordova.plist 的文件。
  2. 在右侧向下滚动至 Plugins 条目并单击将其展开。
  3. 添加一个带有 code>com.tricedesigns.HelloPlugin 项和 "HelloPlugin" 值的条目(参见图 5),用贵公司的标识替换 com.tricedesigns。当调用 Cordova.exec 时,您将利用此字符串引用识别第三个参数中的本机类。

key 是 PhoneGap.exec 映射至本机代码类所使用的唯一一个字符串引用。value是将要调用的实际本机类名称。

  1. 保存更改。

编辑 Cordova.plist。
图 5. 编辑 Cordova.plist。

现在,您可以启动该应用程序并进行彻底检查。

要启动该应用程序,请单击 Run 按钮或选择 Product > Run。

在 iOS Simulator 中(或连接设备上)启动该应用程序后,您将会看到带有两个按钮的简单界面(参见图 6)。单击任一按钮调用本机插件的本机代码,无论调用成功回调还是错误回调,都会通过 JavaScript 显示一条警告消息。

iOS 模拟器中运行的应用程序。
图 6. iOS 模拟器中运行的应用程序。

当调用本机代码时,您还能够在 Xcode 调试控制台窗口中看到输出内容,反映调用本机插件 NSLog 生成的输出内容(参见图 7)。

Xcode 调试控制台的记录信息。
图 7. Xcode 调试控制台的记录信息。

相关文章:

算法总结---最常用的五大算法(算法题思路)

算法总结---最常用的五大算法&#xff08;算法题思路&#xff09; 一、总结 一句话总结&#xff1a; 【明确所求&#xff1a;dijkstra是求点到点的距离&#xff0c;辅助数组就是源点到目标点的数组】 【最简实例分析&#xff1a;比如思考dijkstra&#xff1a;假设先只有三个点】…

软切换中的测量

软切换中的测量 同频测量&#xff1a; CPICH RSCP、Ec/N0, 事件触发报告&#xff0c;1A,...,1F 1A&#xff0c;相对门限增加事件&#xff0c;表示一个小区的质量已经接近最好小区或者活动集质量 1B&#xff0c;相对门限删除事件&#xff0c;表示一个小区…

测试与封装5.1.5.2

1.第一阶段目标 - 把计算的功能封装成类。2.设计测试用例&#xff1a;用白盒与黑盒测试设计技术&#xff0c;为计算核心设计测试用例。3.在实验环境中&#xff08;如MyEclipse集成开发环境Junit测试框架&#xff09;运行测试用例&#xff0c;分析测试结果&#xff0c;找出程序问…

Java项目:企业员工绩效工资管理系统(java+SpringBoot+FreeMarker+Mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 超级管理员等角色&#xff0c;除基础脚手架外&#xff0c;实现的功能有&#xff1a; 超级管理员&#xff1a;系统管理、用户管理&#xff08;冻结等&#xff09;、职称管理、部门管理&#xff08;工资项&am…

Sql server 阻塞定位

很多人都遇到过这样的情况&#xff0c;当网站达到一定的访问量&#xff0c;数据库就会成为瓶颈&#xff0c;进而引起阻塞。有人认为这可能就是硬件的极限了&#xff0c;于是想办法增加硬件设备。而我本人认为问题的元凶可能是性能不高的sql脚本&#xff0c;引起了阻塞。如果你和…

基于EasyNVR摄像机网页无插件直播服务二次开发实现H5播放页面的简单集成方案...

我们通常在构架一套视频SaaS应用的过程中&#xff0c;将平台设计为3层&#xff1a;视频硬件层&#xff08;视频源&#xff09;、视频能力平台&#xff08;vPaaS&#xff09;、视频应用平台&#xff08;vSaaS&#xff09;&#xff0c;视频硬件包括各种IPC、NVR、编码器等视频生成…

active set + serving cell

空闲态&#xff1a;这时候手机只能使用一路信号&#xff0c;应该是最强的那一路。手机在空闲态时不断地搜索各个导频的强度&#xff0c;如果搜到比当前使用的导频更强的&#xff0c;那么它就自发的进行切换。这个切换的过程是手机自发的过程&#xff0c;不需要基站的参与。业务…

Java项目:医院分诊挂号住院管理系统(java+SpringBoot+FreeMarker+Mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 主要实现了从挂号预约到分诊住院出诊等一些列医院基本操作流程的全部功能&#xff0c;系统分医生、患者、管理员三个角色&#xff0c;除基础脚手架外&#xff0c;实现的功能有&#xff1a; 管理员&#xff…

网站压力测试工具webbench

webbench最多可以模拟3万个并发连接去测试网站的负载能力&#xff0c;个人感觉要比Apache自带的ab压力测试工具好&#xff0c;安装使用也特别方便。  1、适用系统&#xff1a;Linux  2、编译安装&#xff1a; 引用wget http://blog.zyan.cc/soft/linux/webbench/webbench-1…

运维人员处理云服务器故障的方法总结

2019独角兽企业重金招聘Python工程师标准>>> 我们团队为Ucloud云计算服务提供专家技术支持,每天都要碰到无数的用户故障,毕竟IAAS涉及比较底层的东西,不管设计的是大客户也好还是小客户,有了问题就必须要解决,也要要是再赶上修复时间紧、奇葩的技术平台、缺少信息和…

玉米田Corn Fields

传送门 #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; #define ll long long #define re register const int mod1e8; void read(int &a) {a0;int d1;char ch;while(chgetchar(),ch>9||ch…

Java项目:酒店管理系统(java+Springboot+Mybatis+Beetl+Layui)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 此系统用的是springboot框架&#xff0c;前端框架主要用的是layui&#xff0c;表格用的bootstrap 表格&#xff0c;都是一些主流的框架&#xff0c;前端模板引擎用的是beetl&#xff0c;操作简单&#xff0c…

word导入中的一个乱码

2019独角兽企业重金招聘Python工程师标准>>> 在做一个题库的项目中,需要将word中的试题导入到数据库中,中间过程真是坎坷,且不说word中的公式,图片等等格式,还有凌乱的排版,还有一些不明觉厉的乱码; 由于PHP暂时不能胜任,所以使用了C#开发了一个客户端来导入,时间很…

Eclipse中git检出、更新、提交、合并分支、以及解决冲突

一、、检出git代码 在eclipse中空白区域右键 Import 检出项目&#xff1b;选择git方式检出 选择用git urI 链接的方式检出项目并点击继续 在这里填写你的git项目地址、账号密码 二、更新 1、先更新 "远程服务器 --> 本地服务器"&#xff0c;再进行 更新 " 本…

Cell select

WCDMA系统的小区重选采用R准则&#xff0c;适用于同频、异频和异系统的小区重选。UE在空闲模式下&#xff0c;要随时监测当前小区和邻区的信号质量&#xff0c;以选择一个最好的小区提供服务&#xff0c;这就是小区重选过程&#xff08;cell reselection&#xff09;。而切换是…

Java项目:茶叶售卖商城系统(java+SSM+JSP+EasyUi+mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 这是一个应用SSM框架的项目&#xff0c;前端页面整洁清晰。该系统有两个角色&#xff0c;一个是普通用户&#xff0c;另一个是管理员。 普通用户具有注册、登录、查看商品、添加购物车、添加商品收藏、下订…

SOAP消息的传递

上一篇说了SOAP消息的创建&#xff0c;那么创建好了的SOAP消息要怎么发送给服务端呢&#xff1f; public class SoapTest {private String wsdlUri "http://localhost:9999/ns?wsdl";private String ns "http://lenve.server/";Testpublic void test3()…

mfc---手动给toolbar按钮添加消息View中

手动给toolbar按钮添加消息View中&#xff1a; .h&#xff1a; afx_msg void OnButtonBG(); .cpp: ON_COMMAND(ID_BUTTON_BG,OnButtonBG) .cpp: void OnButton()转载于:https://www.cnblogs.com/xiaoxiaocaicai/p/3595290.html

费马小定理求素数

/*---------------------------------------------------费马小定理:如果n是一个素数&#xff0c;a是小于n的任意正整数&#xff0c;那么a的n次方与a模n同余。(俩个数称为模n同余&#xff0c;如果它们除以n的余数相同。数a除以n的余数称为a取模n的余数&#xff0c;或简称为a取模…

Java项目:垃圾分类查询管理系统(java+SSM+jsp+MySQL+bootstrap)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; jspssm&#xff08;springspringmvcmybatis&#xff09;mysql实现的垃圾分类查询管理系统: 系统主要实现的功能有&#xff1a; 1&#xff1a;前端垃圾分类查询&#xff0c;前端采用bootstrap框架&#xff…

适合所有尺寸打印马赛克

CGFloat width 40;CGFloat height 40;//获取屏幕宽高//获取屏幕对象UIScreen *screen [UIScreen mainScreen];//获取屏幕大小CGRect screenFrame [screen bounds];//单独取出屏幕的宽高 // CGFloat screenWidth screenFrame.size.width;CGFloat screenWidth CGRectGet…

MVC使用Flash来显示图片

Insus.NET实现一些网站模版&#xff0c;如用户能动态变更网站的头&#xff0c;中间或是脚的部位&#xff0c;就是不太确定用户上传的是图片&#xff0c;还是Flash。因此想到一个较好的解决方法&#xff0c;就是使用Flash的组件去显示来源的图片或是.swf文件。这样的话&#xff…

shuffle调优

目录 一、概述二、shuffle的定义三、ShuffleMananger发展概述四、HashShuffleManager的运行原理 4.1 未经优化的HashShuffleManager4.2 优化后的HashShuffleManager五、SortShuffleManager运行原理 5.1 普通运行机制5.2 bypass运行机制六、shuffle相关参数调优 spark.shuffle.f…

Java8 以后的 LocalDateTime,你真的会用吗?

本文从 LocalDateTime 类的创建、转换、格式化与解析、计算与比较以及其他操作几个方面详细介绍了 LocalDateTime 类在 Java 8 中的使用。掌握 LocalDateTime 类的使用可以大大提高日期时间处理效率和质量,希望本文对读者有所帮助。

斐波那契算法举例(iterative Fibonacci algorithm)

// count_change.cpp : Defines the entry point for the console application.// #include "stdafx.h" /*-------------------------------------------------------------实例&#xff1a;要想得到一个迭代的斐波那契算法需要一点点智慧。给了半美元、四分之一美…

Java项目:零食商城系统(java+SSM+jsp+MySQL+EasyUI)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 系统主要实现的功能有&#xff1a;用户浏览商品、加入商品到购物车、登录注册、提交订单&#xff0c;会员中心修改个人信息、查看订单等。 后台管理员登录后可以分角色添加管理员&#xff0c;不同角色有不同…

skiplist 跳表(1)

最近学习中遇到一种新的数据结构&#xff0c;很实用&#xff0c;搬过来学习。 原文地址&#xff1a;skiplist 跳表 为什么选择跳表 目前经常使用的平衡数据结构有&#xff1a;B树&#xff0c;红黑树&#xff0c;AVL树&#xff0c;Splay Tree, Treep等。 想象一下&#xff0c;给…

前端学习笔记系列一:14 vue3.X中alias的配置

第一步&#xff1a; 第二步&#xff1a; // vue.config.js module.exports { configureWebpack: { resolve: { alias: { assets: /assets, components: /components, views: /views, } } }, } 并且&#xff0c;在没有自行配置alias的时候&#xff0c;就已经可以使用inquire(‘…

【转】sed 简明教程

本文转自&#xff1a;http://coolshell.cn/articles/9104.html awk于1977年出生&#xff0c;今年36岁本命年&#xff0c;sed比awk大2-3岁&#xff0c;awk就像林妹妹&#xff0c;sed就是宝玉哥哥了。所以 林妹妹跳了个Topless&#xff0c;他的哥哥sed坐不住了&#xff0c;也一定…

帕斯卡三角形(Pascal's triangle)

// The following code is compiled on VC2005 // #include "stdafx.h" /*-----------------------------------------------下面数值模式称为帕斯卡三角形(Pascals triangle)11 11 2 11 3 3 11 4 6 4 1 ...三角形边界上的数都是1&#xff0c;内部的每个数数是位…