扩展实现
1.功能说明 1.1 扩展介绍 宿主方可根据自己的业务需求对小程序的能力进行扩展。扩展分为如下三种:
纯前端扩展:如果只想扩展前端组件,则参考前端扩展 ,前端开发 extension.js 并集成到客户端。
纯客户端扩展:如果能力只涉及客户端,则参考如下文档。
跳转到宿主 App 的页面,无需开发端能力,参考 2.1
获取宿主 App 的数据或提供宿主 App 的组件,需要开发端能力,参考 2.2
扩展既包含前端也包含客户端,则 extension.js 及端能力都需要开发,参考 2.3 。
1.2 扩展流程 扩展端能力使用协议分发(scheme)的方式,下面是扩展流程图
1.3 端能力介绍 1.3.1 协议介绍 小程序中的端能力是通过协议方式进行调起的,具体格式如下:
1 scheme://component/action?params=$params&callback=$callback
scheme:为宿主方 App 的协议头,宿主开源平台上注册的 schemeHead ;
component 与 module:component 表示业务类型标识,小程序标识为 swanAPI ,module 表示模块类型标识,默认为空,扩展无需关注 module
action:端能力的方法。
params:小程序传递给端的参数、params 格式为 json 数组。
callback:协议中的一级回调函数,端能力调用成功或失败,NA 端都必须进行回调
Demo 工程的扩展协议示例如下:
1 2 // 扩展示例,详见 Demo 工程 swandemo://swanAPI/exampleOfExtension?params=$params&callback=$callback
1.3.2 端能力介绍 端能力指的是是客户端提供的能力,可提供宿主的特定组件或宿主数据。扩展需要增加 BBASMPlugin 类的分类并提供实现方法。
2.开发指南 2.1 扩展层 - 小程序跳转到宿主特定页面 说明:如宿主有私有小程序需要打开宿主的指定页面,则可以通过实现如下方法来打开指定页面,可参考 Demo 中 BBASMUtilImplement 类的 pageTransition 方法
1 2 3 4 5 6 + (void)pageTransition:(NSDictionary *)optionsDict callback:(void (^)(BOOL success))callback secondCallback:(void (^)(NSString *status, NSString *message, NSDictionary * _Nullable data))secondCallback { // 解析 optionsDict 参数,跳转到指定宿主页面 }
2.2 扩展层 - 小程序端能力开发 新建 BBASMPlugin 的分类,需要 #import <BBAMNP/BBASMPlugin.h> 详见 Demo 层 SwanExtPlugin 中的 BBASMPlugin+Test 类
2.2.1 写端能力描述表 小程序 SDK 2.23.0 后需对扩展的端能力上方加 端能力描述注释 (必须要加,否则端能力无法调通)。描述注释具体格式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 /** * 描 述: 扩展端能力示例,仅供宿主参考,宿主无需拷贝到工程 * 示 例: swandemo://swanAPI/exampleOfExtension?params=$params&callback=$callback * 文 档: **** * 备 注: * ********** description ************ * @name: swandemo.exampleOfExtension * @authority: swanAPI * @path: /exampleOfExtension * @args: [{"name": "cb", "value": "string"}, {"name": "param1", "value": "string="}, {"name": "param2", "value": "object="}, {"name":"param3","value":"boolean="}, {"name":"param4","value":"number="}, {"name": "param5", "value": {"arrayOf": "string="}}] * @config: {"swan": {"web": {"invoke": "swan.message.url", "handler": "bridge"}, "jsc": {"invoke": "swan.method.url", "method": "_naSwan.bridge.postMessage"}}} */
描述:端能力描述
示例:端能力协议示例,宿主需要改协议头(swandemo)和 方法(exampleOfExtension),其它无需修改
文档:端能力文档, 百度系宿主需要在 es 平台上注册,并提供文档链接
备注:
@name: 宿主hostname.端能力方法名
@authority: 固定为 swanAPI ,宿主无需修改
@path: /端能力方法
@args: 小程序传递给端能力的参数,json格式的键值对:[{“key” : “参数名”, “value” : “参数类型”}]
@config: 固定格式,宿主无需修改
注意点 :
参数中 value 如果包含=说明此参数非必传,必传参数如果不传,能力会返回失败
参数里如果包含 cb 表明此端能力有异步操作的情况,前端会等待客户端回调结果后再返给小程序开发者成功的回调
端能力注释需要写到 .h 文件的端能力函数申明前
写完后需要执行端能力描述表,重新收集端能力
2.2.2 开发实现层 详见 Demo 层 SwanExtPlugin 中的 BBASMPlugin + Test.m ,主要是进行参数校验,客户端逻辑,执行一级回调和二级回调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 - (void)exampleOfExtension:(BBASchemeDispatcher *)dispatcher { // 1: 参数校验 NSDictionary *params = dispatcher.optionsDict; NSString *appID = [Pyramid.bba_MNPUtilities currentAppID:dispatcher]; if (CHECK_DICTIONARY_INVALID(params) || CHECK_STRING_INVALID(appID)) { // 参数校验失败,使用doCallbackWithStatus一级回调返给前端失败的回调。 [dispatcher doCallbackWithStatus:kBBASDCallBackParamsErrorStatus message:kBBASDCallBackParamsErrorMSG data:nil]; } // 2: 执行端上代码 NSString *color = @"#FF00FF"; // 3: 使用doCallbackWithStatus一级回调返给前端成功的回调。 [dispatcher doCallbackWithStatus:kBBASDCallBackSuccessStatus message:kBBASDCallBackSuccessMSG data:@{@"color": color}]; // 4: 如果参数中cb有值,则说明还需要二级回调(二级回调指的是需要端上异步取值的情况)。需执行doCallbackWithJSMethod返给前端回调结果 NSString *cb = params[@"cb"]; if (CHECK_STRING_VALID(cb)) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [dispatcher doCallbackWithJSMethod:cb data:@{kBBASMPluginKeyStatus : kBBASDCallBackSuccessStatus, kBBASMPluginKeyMessage : kBBASDCallBackSuccessMSG, kBBASMPluginKeyData : @{@"color": color}}]; }); } }
2.2.3 联调端能力 开发者打开百度开发者工具,调用 swan.hostname.action(),hostname.action() 是具体的端能力描述表中定义端能力的 name,例如 Demo 中端能力名为 swandemo.exampleOfExtension,编译预览生成二维码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 swan.swandemo.exampleOfExtension({ param1: "param1", param5: ["a", "b", "c"], success: res => { swan.showModal({ title: 'success', content: '调用成功' }); }, fail: err => { swan.showModal({ title: 'fail', content: "调用失败" }); } });
端上用 App 扫码打开此小程序,如断点执行到端上的逻辑的话说明端能力联调成功。
2.3 开发的能力包含前端 extension.js 2.1 前端 extension.js 包集成 按照前端的扩展功能 ,开发扩展前端能力,生成 extension.js(可能还有 extension.css)文件,对文件进行 zip 格式压缩为 extension.zip ,同时需要一个 extension-config.json 文件描述 extenson 包的版本号;宿主工程中需要预置这个扩展包。extension-config.json 文件格式:(必须要有 version name 和 version code )
1 2 3 4 { "sm-core-extension-version-name":"1.20.6", "sm-core-extension-version-code" : 1020006 }
注:extension.zip 包如果包含多个文件,压缩 zip 包时一定要注意了,在 mac 上选中多个文件进行压缩成 zip 文件,如果单独为文件夹压缩,扩展包的路径会找不到,导致扩展的端能力就调不起来。在沙箱里面的 extension 包的路径为:Documents/SwanCaches/swan-core-extension/preset (或者 remote)/1.0.0(版本号)/(包含 extension.js、extension.css )
2.2 实现扩展协议接口 需要实现配置 中的“Extension 配置”接口:具体实现参考如下代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 + (NSString *)presetExtensionPackageBundlePath { NSString *extensionPath = [[NSBundle mainBundle] pathForResource:@"BBAMNPPyramid.bundle" ofType:nil]; if (CHECK_STRING_VALID(extensionPath)) { NSString *extensionPackagePath = [NSString stringWithFormat:@"%@/sm-core-extension.zip", extensionPath]; return extensionPackagePath; } return nil; } /// 从extension-config.json读取version name + (NSString *)presetExtensionPackageVersion { NSDictionary *presetExtConDic = [self presetExtConDic]; if (CHECK_DICTIONARY_VALID(presetExtConDic)) { return presetExtConDic[@"sm-core-extension-version-name"]; } return nil; } /// 从extension-config.json读取version code + (NSNumber *)presetExtensionPKGVersionCode { NSDictionary *presetExtConDic = [self presetExtConDic]; if (CHECK_DICTIONARY_VALID(presetExtConDic)) { return presetExtConDic[@"sm-core-extension-version-code"]; } return nil; }