自定义 API,顾名思义为开发者为满足自身需求而自己创建的一个 API。那么自己创建的这个 API 能起到什么效果和作用呢。
如果小程序里需要调用一些宿主 App 提供的能力,而 FinClip SDK 未实现或无法实现时,就可以注册一些自定义 API。然后小程序里就可以像调用其他 API 一样调用注册的 API 了。
简单来说这个自定义 API 能起到小程序或者 H5 与原生 App 的交互作用。
注册自定义 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);
}
});
小程序里加载的 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)
});
自定义 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<IApi>(CustomApi1(), CustomApi2(), CustomApi3())
FinAppClient.extensionApiManager.registerApis(apis)
Java
单个注册
FinAppClient.INSTANCE.getExtensionApiManager().registerApi(new CustomApi(this));
批量注册
List<IApi> 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)
}
})
小程序里加载的 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<IApi>(WebApi1(), WebApi2(), WebApi3())
FinAppClient.extensionWebApiManager.registerApis(apis)
Java
单个注册
FinAppClient.INSTANCE.getExtensionWebApiManager().registerApi(new WebApi(this));
批量注册
List<IApi> 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)
});
在注册自定义 API 时,会判断当前的小程序 SDK 是否初始化成功了。如果没有初始化成功,那么注册自定义 API 就不会成功。
所以,注册自定义 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);
}
});
答案是支持的。
typedef ExtensionApiHandler = Future Function(dynamic params)
自定义的方法返回的结果会返回给小程序
原因:
跳转到宿主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 不会被调用,因此不推荐。
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
自定义 API 相关示例代码可见:https://github.com/finogeeks/auth_demo_android
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。