凡泰极客
作者凡泰极客·2022-04-02 16:44
市场经理·凡泰极客

手把手第十二篇:在 FinClip 小程序中引入自有 API

字数 8231阅读 565评论 0赞 0

手把手第十二篇:在 FinClip 小程序中引入自有 API

手把手第十二篇:在 FinClip 小程序中引入自有 API

在上期文章中,我们主要将 FinClip SDK 引入了自有 App。本期文章中,我们将一起聊聊如何在 FinClip 小程序中引入自有 API。

本期文章属于《手把手系列教学》的第十二篇,如果你还不太了解这一系列,可以点击 > 这里 > 查看详情。
    • -

什么是自定义 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 的函数如下所示:

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

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

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

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

module.exports = {
  extApi:[
    { //普通交互API
      name: 'customEvent', //扩展api名 该api必须Native方实现了
      params: { //扩展api 的参数格式,可以只列必须的属性
        url: ''
      }
    }
  ]
}
extApi 是个数组,所以,您可以注册多个自定义API。

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

ft.customEvent({
    url:'https://www.baidu.com',
    success: function (res) {
        console.log("调用customEvent success");
        console.log(res);
    },
    fail: function (res) {
        console.log("调用customEvent fail");
        console.log(res);
    }
});

2. iOS 端注册小程序 web-view 组件 API

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

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

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

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

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

HTML 内调用注册的方法示例:

window.ft.miniProgram.callNativeAPI('js2AppFunction', {name:'getLocation'}, (result) => {
    console.log(result)
});
3. Android 端注册小程序自定义API

自定义 API 示例:

public class CustomApi extends BaseApi {

    public CustomApi(Context context) {
        super(context);
    }

    @Override
    public String[] apis() {
        return new String[]{"customEvent"}; //api名称
    }

    @Override
    public void invoke(String event, JSONObject param, ICallback callback) {
        // 调用方法时原生对应的操作
    }
}

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

Kotlin

单个注册

FinAppClient.extensionApiManager.registerApi(CustomApi(this)) 

批量注册

val apis = listOf(CustomApi1(), CustomApi2(), CustomApi3())
FinAppClient.extensionApiManager.registerApis(apis) 

Java

单个注册

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

批量注册

List apis = new ArrayList<>();

IApi customApi1 = new CustomApi1();
apis.add(customApi1);

IApi customApi2 = new CustomApi2();
apis.add(customApi2);

IApi customApi3 = new CustomApi3();
apis.add(customApi3);

FinAppClient.INSTANCE.getExtensionApiManager().registerApis(apis); 

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

module.exports = {
  extApi:[
    { //普通交互API
      name: 'customEvent', //扩展api名 该api必须Native方实现了
      params: { //扩展api 的参数格式,可以只列必须的属性
        url: ''
      }
    },
    {
        name: 'customEvent1',
        params: {
            foo: ''
        }
    },
    {
        // foo
    }
  ]
}

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

ft.customEvent({
    url:'https://www.xxx.com',
    success: function (res) {
        console.log("customEvent call succeeded");
        console.log(res)
    },
    fail: function (res) {
        console.log("customEvent call failed");
        console.log(res)
    }
})
4. Android 端注册小程序 web-view 组件 API

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

public class WebApi extends BaseApi {

    public WebApi(Context context) {
        super(context);
    }

    @Override
    public String[] apis() {
        return new String[]{"webApiName"}; //api名称
    }

    @Override
    public void invoke(String event, JSONObject param, ICallback callback) {
        // 调用方法时原生对应的操作
    }
}

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

Kotlin

单个注册

FinAppClient.extensionWebApiManager.registerApi(WebApi(this)) 

批量注册

val apis = listOf(WebApi1(), WebApi2(), WebApi3())
FinAppClient.extensionWebApiManager.registerApis(apis)

Java

单个注册

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

批量注册

List apis = new ArrayList<>();

IApi webApi1 = new WebApi1();
apis.add(webApi1);

IApi webApi2 = new WebApi2();
apis.add(webApi2);

IApi webApi3 = new WebApi3();
apis.add(webApi3);

FinAppClient.INSTANCE.getExtensionWebApiManager().registerApis(apis); 

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

HTML 内调用注册的方法示例:

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

FinClip 小程序自定义 API 常见问题

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

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

所以,注册自定义 API 前,一定要保证小程序已经初始化成功了。

2. 在 FinClip FIDE 中如何 mock 使用自定义 API

在 FIDE 中,有 mock 功能可以方便开发者在开发的途中 mock 模拟自定义 API 的返回结果。如下图:

在 mock 中定义 API 接口字段及返回结果(需要注意的是,这里的 JSON 数据包的返回结果需要的是双引号"")然后在小程序根目录下。

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

module.exports = {
  extApi: [{
    name: 'kkshy',
  }]
}

最后就是小程序中的调用

ft.kkshy({
      success: function(res) {
        console.log("success");
        console.log(res);
      },
      fail: function(res) {
        console.log("fail");
        console.log(res);
      }
    });

3. 使用 Flutter 接入的话,自定义 API 是否支持通过 Success 方法接收 Flutter 的回调数据

答案是支持的。

typedef ExtensionApiHandler = Future Function(dynamic params)

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

4. 在自定义接口的 invoke() 方法中跳转到宿主 App 的其它页面,做完一系列操作之后,按系统返回键想返回小程序,结果却返回到了宿主 App 中启动小程序的页面,为什么?

原因:

跳转到宿主App其它页面这一步,是通过宿主App中的Context实例来启动Activity的,并且没有把Activity压入新的任务栈中。

Android小程序SDK是多进程架构的,小程序和宿主App处于不同进程中,所处的任务栈自然也是不同的。小程序跳转到宿主App的页面,新打开的页面是添加到宿主App原有的任务栈中的,当从页面返回时,执行的逻辑是在原生App中原有的任务栈中弹出页面,因此会看到原生App的页面被逐个关闭,最后返回到原生应用启动小程序的页面,并没有返回小程序。

解决方案共有 2 种:

方案 1(推荐):

通过 ICallback 的 startActivity 或 startActivityForResult 来跳转到宿主 App 的其它页面。

这是推荐的方案,因为这样做是在小程序所在的任务栈打开新宿主 App 的 Activity 的,Activity 的入栈出栈都是在同一个任务栈中完成的,没有任务栈切换的过程。

更重要的一个原因是:如果需要通过 startActivityForResult 来启动 Activity 并在页面返回时获取到回传的数据,只有使用这种方案,自定义接口的 onActivityResult 才会执行,才能拿到返回的数据。

此方案使用示例:

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

方案 2(不推荐):

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

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

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

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

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

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

module.exports = {
  // ...
  copy: {
    patterns: [
      { from: 'FinChatConf.js', to: 'dist/FinChatConf.js' } // 指定需要 copy 的文件
    ]
  }
}
具体可参考 taro 文档> http://taro-docs.jd.com/taro/docs/config-detail#copy

FinClip 小程序自定义 API 示例

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

本期教程我们讨论了如何在自有小程序中引入自定义 API,后续我们也会不定时更新 FinClip 相关的内容,敬请期待。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

0

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广