一、什么是自定义api及其有何作用

自定义api,顾名思义为开发者为满足自身需求而自己创建的一个api。那么自己创建的这个api能起到什么效果和作用呢。


如果小程序里需要调用一些宿主app提供的能力,而FinClip SDK未实现或无法实现时,就可以注册一些自定义API。然后小程序里就可以像调用其他API一样调用注册的API了。

简单来说这个自定义api能起到小程序或者h5与原生app的交互作用。

注册自定义API分两个场景:1.注册给原生小程序使用的自定义API;2.注册给小程序中web-view组件加载的H5使用的自定义API。

二、如何注册及使用finclip小程序自定义api

1、ios端注册小程序自定义api

注册自定义的小程序API的函数如下所示:

  1. /**
  2. 注册扩展Api
  3. @param extApiName 扩展的api名称
  4. @param handler 回调
  5. @return 返回注册结果
  6. */
  7. - (BOOL)registerExtensionApi:(NSString *)extApiName handle:(void (^)(id param, FATExtensionApiCallback callback))handler;

比如,我这里注册一个小程序APIcustomEvent:

  1. [[FATClient sharedClient] registerExtensionApi:@"customEvent" handle:^(id param, FATExtensionApiCallback callback) {
  2. // xxxx
  3. callback(FATExtensionCodeSuccess, nil);
  4. }];

然后,在小程序的根目录创建 FinClipConf.js 文件,配置实例如下:

  1. module.exports = {
  2. extApi:[
  3. { //普通交互API
  4. name: 'customEvent', //扩展api名 该api必须Native方实现了
  5. params: { //扩展api 的参数格式,可以只列必须的属性
  6. url: ''
  7. }
  8. }
  9. ]
  10. }

extApi 是个数组,所以,您可以注册多个自定义API。

最后,在小程序里调用自定义的API,示例代码:

  1. ft.customEvent({
  2. url:'https://www.baidu.com',
  3. success: function (res) {
  4. console.log("调用customEvent success");
  5. console.log(res);
  6. },
  7. fail: function (res) {
  8. console.log("调用customEvent fail");
  9. console.log(res);
  10. }
  11. });

2、ios端注册小程序web-view组件api

小程序里加载的H5,如果也想调用宿主API的某个能力,就可以利用该方法注册一个API

  1. /// 为HTML 注册要调用的原生 api
  2. /// @param webApiName 原生api名字
  3. /// @param handler 回调
  4. - (BOOL)fat_registerWebApi:(NSString *)webApiName handle:(void (^)(id param, FATExtensionApiCallback callback))handler;

我这里为小程序里的H5注册了一个叫js2AppFunction的方法,

  1. [[FATClient sharedClient] fat_registerWebApi:@"js2AppFunction" handle:^(id param, FATExtensionApiCallback callback) {
  2. NSString *name = param[@"name"];
  3. // id params = param[@"data"];
  4. if ([name isEqualToString:@"getLocation"]) {
  5. // 执行定位逻辑
  6. // 返回结果给HTML
  7. NSDictionary *dict = @{@"errno":@"403", @"errmsg":@"无权限", @"result": @{@"address":@"广东省深圳市南山区航天科技广场"}};
  8. callback(FATExtensionCodeSuccess, dict);
  9. } else if ([name isEqualToString:@"getColor"]) {
  10. // 执行其他逻辑
  11. // 返回结果给HTML
  12. NSDictionary *dict = @{@"r":@"110",@"g":@"150",@"b":@"150"};
  13. callback(FATExtensionCodeSuccess, dict);
  14. }
  15. }];

在H5内引用我们的桥接JSSDK文件,即可调用上面的注册的方法了。
HTML内调用注册的方法示例:

  1. window.ft.miniProgram.callNativeAPI('js2AppFunction', {name:'getLocation'}, (result) => {
  2. console.log(result)
  3. });

3、android端注册小程序自定义api

自定义api示例:

  1. public class CustomApi extends BaseApi {
  2. public CustomApi(Context context) {
  3. super(context);
  4. }
  5. @Override
  6. public String[] apis() {
  7. return new String[]{"customEvent"}; //api名称
  8. }
  9. @Override
  10. public void invoke(String event, JSONObject param, ICallback callback) {
  11. // 调用方法时原生对应的操作
  12. }
  13. }

然后将其注册到extensionApiManager中,支持单个注册和批量注册。

·Kotlin

单个注册

  1. FinAppClient.extensionApiManager.registerApi(CustomApi(this))

批量注册

  1. val apis = listOf<IApi>(CustomApi1(), CustomApi2(), CustomApi3())
  2. FinAppClient.extensionApiManager.registerApis(apis)


·Java

单个注册

  1. FinAppClient.INSTANCE.getExtensionApiManager().registerApi(new CustomApi(this));

批量注册

  1. List<IApi> apis = new ArrayList<>();
  2. IApi customApi1 = new CustomApi1();
  3. apis.add(customApi1);
  4. IApi customApi2 = new CustomApi2();
  5. apis.add(customApi2);
  6. IApi customApi3 = new CustomApi3();
  7. apis.add(customApi3);
  8. FinAppClient.INSTANCE.getExtensionApiManager().registerApis(apis);

然后,在小程序的根目录创建 FinClipConf.js 文件,配置实例如下:

  1. module.exports = {
  2. extApi:[
  3. { //普通交互API
  4. name: 'customEvent', //扩展api名 该api必须Native方实现了
  5. params: { //扩展api 的参数格式,可以只列必须的属性
  6. url: ''
  7. }
  8. },
  9. {
  10. name: 'customEvent1',
  11. params: {
  12. foo: ''
  13. }
  14. },
  15. {
  16. // foo
  17. }
  18. ]
  19. }

最后,在小程序里调用自定义的API,示例代码:

  1. ft.customEvent({
  2. url:'https://www.xxx.com',
  3. success: function (res) {
  4. console.log("customEvent call succeeded");
  5. console.log(res)
  6. },
  7. fail: function (res) {
  8. console.log("customEvent call failed");
  9. console.log(res)
  10. }
  11. })

4、android端注册小程序web-view组件api

小程序里加载的H5,如果也想调用宿主API的某个能力,就可以利用该方法注册一个API。

  1. public class WebApi extends BaseApi {
  2. public WebApi(Context context) {
  3. super(context);
  4. }
  5. @Override
  6. public String[] apis() {
  7. return new String[]{"webApiName"}; //api名称
  8. }
  9. @Override
  10. public void invoke(String event, JSONObject param, ICallback callback) {
  11. // 调用方法时原生对应的操作
  12. }
  13. }

然后将其注册到extensionWebApiManager中,同样也支持单个注册和批量注册。

·Kotlin

单个注册

  1. FinAppClient.extensionWebApiManager.registerApi(WebApi(this))

批量注册

  1. val apis = listOf<IApi>(WebApi1(), WebApi2(), WebApi3())
  2. FinAppClient.extensionWebApiManager.registerApis(apis)


·Java

单个注册

  1. FinAppClient.INSTANCE.getExtensionWebApiManager().registerApi(new WebApi(this));

批量注册

  1. List<IApi> apis = new ArrayList<>();
  2. IApi webApi1 = new WebApi1();
  3. apis.add(webApi1);
  4. IApi webApi2 = new WebApi2();
  5. apis.add(webApi2);
  6. IApi webApi3 = new WebApi3();
  7. apis.add(webApi3);
  8. FinAppClient.INSTANCE.getExtensionWebApiManager().registerApis(apis);

在H5内引用我们的桥接JSSDK文件,即可调用上面的注册的方法了。
HTML内调用注册的方法示例:

  1. window.ft.miniProgram.callNativeAPI('js2AppFunction', {name:'getLocation'}, (result) => {
  2. console.log(result)
  3. });


三、FinClip小程序自定义api常见问题

1、为什么注册的自定义小程序API不起作用

在注册自定义API时,会判断当前的小程序SDK是否初始化成功了。如果没有初始化成功,那么注册自定义Api就不会成功。
所以,注册自定义API前,一定要保证小程序已经初始化成功了。

2、在finclip fide中如何mock使用自定义api

在fide中,有mock功能可以方便开发者在开发的途中mock模拟自定义api的返回结果。如下图:
image.png
在mock中定义api接口字段及返回结果(需要注意的是,这里的JSON数据包的返回结果需要的是双引号””)
然后在小程序根目录下。
然后,在小程序的根目录创建 FinClipConf.js 文件,配置实例如下:

  1. module.exports = {
  2. extApi: [{
  3. name: 'kkshy',
  4. }]
  5. }

最后就是小程序中的调用

  1. ft.kkshy({
  2. success: function(res) {
  3. console.log("success");
  4. console.log(res);
  5. },
  6. fail: function(res) {
  7. console.log("fail");
  8. console.log(res);
  9. }
  10. });

3、使用flutter接入的话,自定义api是否支持通过success方法接收flutter的回调数据

答案是支持的,

  1. typedef ExtensionApiHandler = Future Function(dynamic params)

自定义的方法返回的结果会返回给小程序

4、在自定义接口的invoke()方法中跳转到宿主App的其它页面,做完一系列操作之后,按系统返回键想返回小程序,结果却返回到了宿主App中启动小程序的页面,为什么?
  1. 原因:跳转到宿主App其它页面这一步,是通过宿主App中的Context实例来启动Activity的,并且没有把Activity压入新的任务栈中。Android小程序SDK是多进程架构的,小程序和宿主App处于不同进程中,所处的任务栈自然也是不同的。小程序跳转到宿主App的页面,新打开的页面是添加到宿主App原有的任务栈中的,当从页面返回时,执行的逻辑是在原生App中原有的任务栈中弹出页面,因此会看到原生App的页面被逐个关闭,最后返回到原生应用启动小程序的页面,并没有返回小程序。
  2. 解决方案:

方案1(推荐):
通过ICallback的startActivity或startActivityForResult来跳转到宿主App的其它页面。
这是推荐的方案,因为这样做是在小程序所在的任务栈打开新宿主App的Activity的,Activity的入栈出栈都是在同一个任务栈中完成的,没有任务栈切换的过程。
更重要的一个原因是:如果需要通过startActivityForResult来启动Activity并在页面返回时获取到回传的数据,只有使用这种方案,自定义接口的onActivityResult才会执行,才能拿到返回的数据。
此方案使用示例:

  1. @Override
  2. public void invoke(String event, JSONObject param, ICallback callback) {
  3. Intent intent = new Intent();
  4. intent.setClass(mContext, SecondActivity.class);
  5. callback.startActivityForResult(intent, 100);
  6. }

方案2(不推荐):
如果一定要使用宿主App中的Context实例来启动Activity,就需要对启动原生页面的Intent设置”支持多任务栈”和“开启新任务栈”的Flag,这样可以在原生App的进程中新开一个任务栈,开启新任务栈之后,新打开的页面将被逐个压入这个新任务栈中,当结束完原生页面的所有操作之后逐个页面返回时,便会从这个新任务栈中将页面逐个弹出,当这个新任务栈中的所有页面都被弹出后,便会回到小程序进程的任务栈。

因此,在自定义接口的invoke()方法中,如果需要跳转到原生应用的其它页面执行某些操作,并期望当关闭这些原生页面后能够返回小程序,那么建议在执行跳转的时候为Intent对象同时增加Intent.FLAG_ACTIVITY_MULTIPLE_TASK和FLAG_ACTIVITY_NEW_TASK,如下:

  1. Intent intent = new Intent();
  2. intent.setClass(context, SecondActivity.class);
  3. intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
  4. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  5. context.startActivity(intent); // context是宿主App中的Context实例

使用此方案,如果通过startActivityForResult来启动Activity,当页面返回时,自定义接口的onActivityResult不会被调用,因此不推荐。

5、taro中如何给打包后文件添加FinChatConf.js

taro中可以使用copy配置项,将FinChatConf.js复制到打包后的文件之中,具体写法可参考如下:

  1. module.exports = {
  2. // ...
  3. copy: {
  4. patterns: [
  5. { from: 'FinChatConf.js', to: 'dist/FinChatConf.js' } // 指定需要 copy 的文件
  6. ]
  7. }
  8. }

具体可参考taro文档http://taro-docs.jd.com/taro/docs/config-detail#copy

四、FinClip小程序自定义api示例


自定义api相关示例代码可见:https://github.com/finogeeks/auth_demo_android
[

](https://finclip.com/mop/document/develop/component/overview.html#%E8%A7%86%E5%9B%BE%E5%AE%B9%E5%99%A8)