扩展插件开发指南_iOS

1. 扩展插件开发介绍

1.1 简介

"中控易动"平台移动端引擎通过系统Webkit浏览器,实现了HTML+CSS+Javascript开发语言和Objective-C/Java/C/C++等Native开发语言之间的桥接,极大的丰富和增强了标准Javascript的能力,令前端开发者通过JS即可调用移动设备的底层功能,如:电话、短信、定位、多媒体等,并能将如高德地图、支付宝等第三方厂商的SDK很容易的集成到自己的App中来。

为满足广大开发者自定义扩展Native plugin的需求,中控移动应用开发平台推出插件扩展SDK,本SDK开放桥接机制,方便具有一定iOS基础的开发者自由开发定义Native扩展插件,丰富JS的能力,提升App的用户体验。

1.2 阅读对象

本文档面向所有使用该SDK的iOS开发人员、测试人员、合作伙伴以及对此感兴趣的其他用户。阅读该文档要求用户熟悉iOS应用开发,并且对Html、CSS、Javascript有一定了解。"中控易动"平台移动端引擎强调传输数据的简洁性和统一性,因此选择轻量级的JSON作为Javascript和Native语言之间通讯的数据载体,所以要求开发者同时要熟悉Objective-C和Javascript中JSON格式数据的操作。

1.3 开发环境

  • Xcode9.0或更高版本
  • macOS 10.12.6以上

1.4 架构

这是图片

1.5 插件开发流程

这是图片

1.6 下载Demo和SDK

点击下载SDK(包含DEMO)

2. 插件开发

2.1 配置plugin.json

plugin.json定义了插件的基本信息,我们在开发插件之前需要先定义好插件名称、插件对应的类的名称、开放给JS的方法等。

字段解释:

  • name:对应值为插件的名称,JS中通过该名称来使用插件。
  • version:对应值为插件的版本。
  • ios_entry:对应值为插件对应的类的名称,插件类需要继承于CDVPlugin类。
  • android_entry:可选配置项,(Android端必选)安卓功能插件对应的位置。
  • android_maven_lib:可选配置项,(Android端可选)安卓端工程引入的第三方依赖。
  • methods:可选配置项。开放给JS的实例方法,多个方法以英文逗号隔开,此方法实现时需带一个参数。
  • onload:可选配置项。布尔类型,若配置,引擎将在应用启动的时候调用该插件的pluginInitialize:方法,注意该方法需是对象方法,没有参数。
  • ios_system_frameworks:可配置选项,需要添加的系统依赖,字符串数组类型。
  • ios_quriesSchemes:可配置选项,应用访问白名单,字符串数组类型。

如图,在EMobileApp工程中找到EMobileApp目录下的plugin.json文件,在里面添加模块的配置信息

这是图片

2.2 创建和配置静态库工程

打开Xcode,在菜单中选择File-New-Target...,在Framework & Library中选择Framework,创建一个名为PluginDemo的Target。

这是图片

这是图片

这里我们将PluginDemo工程作为EMobileApp工程的一个依赖工程,这样做的好处是运行EMobileApp工程时会自动编译PluginDemo工程,并且可以方便地在PluginDemo工程中打断点进行调试。

然后再按照下图,设置Framework为静态库:

这是图片

将静态库的Build Active Architecture Only设置为No

这是图片

将静态库的iOS Deployment Target设置为9.0,如图:

这是图片

设置静态库Search Paths,在Build Settings - Search Paths - Framework Search Paths 增加 $(PROJECT_DIR)/EMobileApp/Engine/Frameworks ,如图:

这是图片

2.3 创建插件类

在PluginDemo文件夹中新建一个EMDemoPlugin类,继承于CDVPlugin类,其中CDVPlugin类为插件的基类。插件开发过程中文件命名时提倡加前缀,以避免和其它插件冲突。

插件生命周期:

  • 当在前端JS中首次调用模块的方法时,引擎会调用插件类的- (void)pluginInitialize方法进行初始化;

  • 当模块所在的页面被销毁时,模块类也会被销毁,引擎会主动调用其 - (void)dispose 方法。

这是图片

这是图片

插件中的所有类,只用选择对应的 Target Membership,例如下图:

这是图片

2.4 插件中引用系统库

根据上面2.1的配置(ios_system_frameworks),添加系统依赖到主工程。(如果不需要,跳过此步骤)

这是图片

2.5 插件中引用第三方库

直接将第三方库拖入到EMobileApp工程Frameworks文件夹下。(如果不需要,跳过此步骤)例如下图:

注意

不要删除工程里面的framework;

第三方的资源(bundle等)只用设置关联主工程;

这是图片

2.6 配置白名单

根据 2.1 的配置(ios_quriesSchemes)白名单。(如果不需要,跳过此步骤)例如下图:

这是图片

2.7 插件方法实现

[!WARNING]

  • 参数过多,建议用Object类型,iOS直接用字典获取即可。

2.7.1 参数介绍

1.参数类型支持: String、Number、Boolean、Object、Array

2.iOS获取参数

String类型:

NSString *str = [command argumentAtIndex:index withDefault:@"" andClass:NSString.class];

Number类型:

NSInteger a = [[command argumentAtIndex:index]integerValue];
int a = [[command argumentAtIndex:index] intValue]; 
float a = [[command argumentAtIndex:index] floatValue];

Boolean类型:

BOOL isbool = [[command argumentAtIndex:index] boolValue];

Array类型:

NSArray *arr = [command argumentAtIndex:index];

Object类型:

NSDictionary *para = [command argumentAtIndex:index];

2.7.2 返回数据介绍

1.返回数据类型支持: NSString、int、BOOL、double、NSInteger、NSArray、NSDictionary、NSData

2.成功失败回调状态:CDVCommandStatus_OK(成功回调)、CDVCommandStatus_ERROR(失败回调)

3.回调返回数据:

NSString:

[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"成功"] callbackId:command.callbackId];

int:

[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:1] callbackId:command.callbackId];

BOOL:

[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:YES] callbackId:command.callbackId];

double:

[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDouble:9.87] callbackId:command.callbackId];

NSInteger:

[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsNSInteger:9] callbackId:command.callbackId];

NSArray:

[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsArray:arr] callbackId:command.callbackId];

NSDictionary:

[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict] callbackId:command.callbackId];

NSDictionary:

[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict] callbackId:command.callbackId];

NSData:

[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsArrayBuffer:data] callbackId:command.callbackId];

2.7.2 目录解释

根据 2.1 的配置(methods),实现方法。这里我们向js端开放两个方法ckmedialog

方法参数类型为CDVInvokedUrlCommand,可以通过commandarguments属性来获取js传入的参数,通过插件commandDelegate属性的sendPluginResult:callbackId:方法回传数据给js端。

参考下方:

ckme方法

用于演示"原生获取参数"、"成功失败回调"。

  • 原生获取参数

参数是两个字符串,直接获取。参考下方:

image

参数是个对象,用字典获取。参考下方:

image

  • 成功失败回调

image

dialog方法

用于演示"页面跳转"、"使用资源文件"。对于图片、xib、js等一些静态资源在上传到云端时,必需以bundle的形式放到target目录下,才可以正确的被引入到工程中,读取相关资源的代码为:

image

2.8 调试插件方法

前端JS必须使用JSON格式数据作为JS与Native之间交换数据的传参,移动端引擎会对JS传入的参数进行解析并封装。

找到EMobileApp工程中www目录下的index.html,添加调用pluginDemo插件的ckmedialog方法的代码:

  • js传参,参数对应2.7方法的实现

参数字符串,参数是一个Object。参考下方:

这是图片

  • 另外您也可以用调试工具调用插件方法

运行EMobileApp工程到手机,点击屏幕上悬浮的调试工具按钮,找到PC端调试地址

打开电脑浏览器,输入调试地址(注意:电脑需和手机在同一个局域网),默认密码:123456

找到"单文件调试"-->"目录"-->"example"-->"example.js",添加调用pluginDemo插件的ckme方法的代码,点击运行按钮,手机端查看效果:

这是图片

3. 上传插件包

3.1 插件包介绍

插件包根目录建议以该插件的JS对象名命名,这里以PluginDemo为例,插件包内可能包含ios、android文件夹以及plugin.json,其中ios文件夹内可能包含framework、target、plugins文件夹。

目录解释:

  • target目录:存放编译生成的静态库文件(.a和.h文件)、第三方Static类型的framework库(直接添加到工程就能正常使用的是Static类型的,而需要在工程Embedded Binaries处添加才能正常使用的是Dynamic类型的)以及bundle

  • framework目录:(可选配置项)存放第三方Dynamic类型的framework库(需要在工程Embedded Binaries处添加才能正常使用的是Dynamic类型的)

3.2 制作插件包

下面以pluginDemo插件(插件里面仅有静态库)为例:

(1)新建一个plugin.json的文本文件,拷贝EMobileApp工程中plugin.json的内容到plugin.json中(注意:双引号一定要是英文状态下的)。

这是图片

(2)在plugin.json文件同级目录下创建ios文件夹。

这是图片

(3)在ios文件夹里面创建target文件夹,将EMobileApp工程编译出来的PluginDemo.framework 和 第三方文件(注意:开发插件用到的第三方framework/.a/bundle等) 拷贝到target文件夹里。

这是图片

(4)EMobileApp工程编译,参考下方

①选择Build Settings-->Valid Architectures-->arm64、armv7

这是图片

②选择Edit Scheme-->Run-->Release

这是图片

③选择真机设备编译之后生成的framework

这是图片

注意:

①如果没有第三方文件,就不需要拷贝第三方文件。

②编译.framework库必须是真机环境的,并且需要支持armv7和arm64架构,可以在终端用以下命令查看.framework库支持的架构:

lipo -info PluginDemo.framework/PluginDemo

③使用file命令查看库的类型:

file PluginDemo.framework/PluginDemo

(5)压缩插件包

①选中plugin.json和ios文件夹压缩

这是图片

②修改压缩文件名为插件名

"归档.zip" --> 修改为 "pluginDemo.zip"

这是图片 这是图片

3.3 制作插件API文档包

下面以pluginDemo插件(插件里面仅有静态库)为例:

具体参考接口文档编写规范

(1)下载标准API文档示例

(2)解压缩之后,查看"标准API文档编写.docx",根据文档进行编写

这是图片

(3)修改"a"文件夹名为插件名

"a" --> 修改为"pluginDemo"

这是图片

(4)修改插件文档,打开"README.md"文件

这是图片

修改插件信息

这是图片

(5)修改插件方法文档,有几个插件方法就创建几个.md文件,插件方法文件用插件方法命名,例如:"ckme.md"

"method1.md" --> 修改为"ckme.md"

这是图片

修改插件接口信息,打开"ckme.md"文件

下方为2个以上参数,参数为一个对象options:

这是图片

这是图片

下方为≤2个参数:

这是图片

这是图片

创建"dialog.md"文件,编写dialog方法文档:

这是图片

(6)压缩插件文档,直接选中"pluginDemo"文件夹,压缩

这是图片

3.4 上传插件包

登录到中控易动网站控制台,进入”我的插件“,点击”创建自定义插件“按钮,输入插件的相关信息

上传插件模块:3.2 生成的压缩包(pluginDemo.zip)

插件名称:自动读取

上传API文档:3.3 生成的压缩包(pluginDemo.zip)

功能描述:描述插件功能

上传插件到平台见上传插件

3.5 发布插件

若是自用,可以不用发布插件,发布插件到平台见发布插件

4.支持iOS和Android两端插件

4.1 配置plugin.json

参考Andorid开发指南

3.2 的plugin.json文件里面添加Android配置(android_entry、android_maven_lib)参考下方:

image

4.2 创建android文件夹

在plugin.json文件同级目录下创建android文件夹,把生成的aar包(具体参考Andorid开发指南)放入android文件夹内,如下图所示:

image

4.3 制作插件包

①选中plugin.json、ios文件夹、android文件夹压缩

这是图片

②修改压缩文件名为插件名

"归档.zip" --> 修改为 "pluginDemo.zip"

这是图片 这是图片

4.4 上传插件包

上传插件到平台见上传插件

最终上传的插件识别出来,如下图所示:

这是图片

4.5 发布插件包

若是自用,可以不用发布插件,发布插件到平台见发布插件

5. 其他补充

5.1 显示UI视图

CDVPlugin提供viewController属性来获取当前所在视图控制器,可通过该控制器对目标控制器进行push或者present操作

// push
[self.viewController.navigationController pushViewController:controller animated:YES];

// present
[self.viewController presentViewController:controller animated:YES completion:nil];

5.2 启动方法

如果需要插件在应用程序启动的时候就执行一些操作,需先在plugin.json中配置onload为true,然后重载插件的- (void)pluginInitialize方法,如果需要获取应用程序在启动时候的启动参数,可通过CDVPlugin提供的- (NSDictionary *)launchOptions方法获取。

5.3 资源文件的处理

对于图片、xib、js等一些静态资源在上传到云端时,必需以bundle的形式放到target目录下,才可以正确的被引入到工程中,读取相关资源的代码为:

// 加载图片
UIImage image = [UIImage imageNamed:@"SignatureBundle.bundle/1.png"];
// 加载xib
[[[NSBundle bundleForClass:self.class] loadNibNamed:@"SignatureBundle.bundle/EMLimitView" owner:self options:nil] firstObject];
// 获取path
NSString *path = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"SignatureBundle.bundle/1.png"];

results matching ""

    No results matching ""