iOS(安卓/客户端)与JS交互方案设计

iOS(安卓/客户端)与JS交互方案设计

对于有热更新需求的App 应用,使用前端技术写业务代码是一个应用比较广泛的技术方向。随之而来的就是如何使JS与原生的交互简单且规范。
我们想要达到的目的:

① 交互方法的统一,实现标准化。
② JS 调用原生简单无感,结果通过 block 回调给JS。
③ 客户端接收JS交互方法简单无感,只需要专注业务代码实现。

1. 实现方案探索

常用的 JS 交互方案有三种:
① 拦截自定义的超链接协议请求,通过解析超链接,实现指定交互方法。
② 通过JSCore 实现,客户端向JS注入OC类。
③ 通过window.webkit.messageHandlers.xxx.postMessage(params); 实现。

我们最终选用了第③种方式实现。
第一种方式不够灵活,不仅要自定义schme,参数也需要进行GET请求拼接,复杂的交互也难以实现。
第二种方式虽然可以,但是会暴露原生的类给JS,暴露类名并不是我们想要的。
所以我们选用了第三种通过方式实现。

2. 交互的统一化和标准化

2.1 JS统一化交互

统一化和标准化,在JS端的体现,我们想要将所有与原生交互的实现,由一个统一的方法输出,且前端(JS)无需关注iOS或安卓系统。
这样避免交互方法的杂乱无章。
前端查阅代码,见到这样的方法调用,一眼就可以看出来是与前端交互,且交互的具体行为。
前端只要想到交互,就想到调用这样的方法实现实现即可。
这样就大大减轻了前端的交互成本。
例如定义一个统一的交互方法:

KYJSBridge_call(xxx1, xxx2, callback)

JS需要由原生实现的功能,都由该方法实现。
第一个参数(xxx1): 是需要原生实现的功能名称。
第二个参数(xxx2): 是处理该功能需要的参数。
第三个参数(callback): 处理结果原生通过block 返回给JS。
比如前端想要原生实现一个拍照并压缩到指定大小的功能,前端与原生约定功能名称为takePhoto(这里成为JSApi,后面会用),压缩参数为{'photoSize':'500'}
那么前端直接调用:

KYJSBridge_call('takePhoto', {'photoSize':'500'}, function (result) {
    var iamgeBase64String = result.iamgeBase64String;
});

这就是我们想要的前端的统一化和标准化的东西。

2.2 原生统一化交互

既然前端实现了这样的统一化,那么按照这个思路,原生提供的交互也要有一个统一的规范,于是,我们定义原生的交互接口规范,所有给前端提供的交互接口,都是遵循这样的方法实现。如下:

typedef void (^KYJsApiResponseCallbackBlock)(id responseData);
@protocol KYJsApiHandlerProtocol <NSObject>
@optional
/// JsApi 统一处理函数
/// @param data js 传递过来的参数
/// @param context 当前上下文
/// @param callback 处理结果给 js 回调,回调用一次即失效
- (void)jsApiHandler:(NSDictionary *)data context:(KYJsContext *)context callback:(KYJsApiResponseCallbackBlock __nullable)callback;
@end

查阅代码时,只要是遵循该接口规范的实现,我们就能知道这是提供给JS端的。
但是,如果所有接口都是一样的名字,我们又该如何区分JS要原生实现的是什么功能呢?
这里就要进入一个查表机制,也就是前面提高的JSApi 与对应实现的类在原生注册到一个表中,根据前端传过来的JSApi,查表找到具体实现的类。因为原生的接口方法是统一的,因此找到实现也就不难了。这一些列操作都是在框架内部完成的。
客户端只需要遵守协议,并实现协议。同时把约定的JSApi与实现类注册到表中即可。
这也就达到了客户端提供接口的统一性和规范性。

3. CallBack 实现

原生的处理结果如何通过callback 给到JS。
这其实就是 原生调用JS闭包的一个过程,但是我们又如何找到对应交互的JS闭包?
那就保存JS闭包代码。
在JS调用桥接方法KYJSBridge_call 的时候,就需要将该闭包保存起来,待原生完成相关处理后,再找到该闭包去执行。
保存的时候,可以利用时间戳(至少要精确到毫秒级),生成一个唯一的Key值,将闭包保存,同时该Key值要传递给原生,待原生完成任务后,再将该Key和结果传递给JS,JS通过Key找到闭包,并调用闭包执行。
这样的整个过程,都是在框架内部实现,前端和原生都是无感知的。

4. 上下文的设计

有很多上下文的环境参数,比如 WebView 容器控制器,有时候也是需要在交互中用到的,我们引入了 Context 上下文的设计理念,将一些参数保存的上下文中,供原生交互接口使用,同时也便于扩展,又不影响现有代码的正常使用。

5. 扩展

在该交互方案的基础上,封装私有的交互方法,同时单独维护私有的JSApi注册表。
比如前端网络请求,原则上都要通过原生去发出,并把结果给到JS。
以及导航栏的相关设置操作。
同时,该框架中也应用到了自定义导航栏和自定义的Web容器。

5. 代码

如果您有兴趣,欢迎下载阅读

说明: 源代码已做脱敏处理。
源代码仅做技术分享,但基本功能可用。
细节业务处理,需要您自己补充。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值