Android#JSBridge踩坑问题记录

最新公司新启动了一个项目,大致架构就是,原生客户端相当于一个壳,通过WebView嵌套着含有主要内容的H5,客户端对数据进行管理,如数据缓存或数据接口请求,然后将数据处理好传给前端,而前端要做的就是将数据以各种方式显示出来,有点MVP中V层和M层的意思。

由于整个项目涉及到大量和H5的交互逻辑,所以很自然的,我们使用上了JSBridge。很不幸,在用的过程中我们发现了不少问题,也踩了很多坑。所以在这里总结一下,希望可以帮助到遇到这些问题的人。

1、异步问题

在native和前端在互相调用事件的过程中需保证双方的注册时机以及生命周期,即调用方在调用的时候需保证注册方已经注册好。道理很简单,没有注册好,何谈调用。所以在某些异步事件情况下,应该保证数据管理方是调用者,接收数据端是注册方。因为异步数据何时下载/请求好,只有数据管理方知道,也就能确定合适的调用时机,而注册方要做的是—尽量早的注册在,在我们这次项目里,native app就是调用方,而前端是注册方。

例如,在webview初始化的时候,客户端调用前端的方法时应保证前端的事件已经全部注册好的情况下,即webview加载完成的时候。

//webview加载完毕
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
   //传递数据给前端
  webView.callHandler("setData", json, new CallBackFunction() {
      @Override
      public void onCallBack(String data) {
      }
  });
}
2、严格模式下的数据问题

前端在严格模式下调用natvie方法并传过来的数据json串可能会在每个字段和数据带上 " " ",或“ / ”,这样我们在解析成实体bean对象的时候会报解析错误而闪退。

所以稳妥起见,native在使用前端传过来的数据的第一步要做的就是过滤(需根据数据本身定好过滤规则):

webView.registerHandler("getData", new BridgeHandler() {
   @Override
    public void handler(String data, CallBackFunction function) {
         data.replace("\"", "").replace("\\", "");
    }
 });
3、子线程无法调用问题

native调前端的方法(callHandler)在子线程调不到,换句话说就是,本地调前端的方法时需保证在主线程。

即 runOnMainThread() 或使用RxJava的
.observeOn(AndroidSchedulers.mainThread())
来调度线程。

4、无法收到回调

native调前端的方法,前端会回传给native一个回调告诉native是否有调到这个方法,即onCallBack方法。但如果想要在这个方法的内部进行一些逻辑处理,它可能会让你失望,因为这个回调有些不稳定,所以有时我们根本不知道前端到底有没有调到我们的方法,总之,不是万不得已就不要在原生回调里写上逻辑处理。如果一定需要:

解决办法是本地再注册一个方法,当native调到前端的方法的时候,和前端协商好让前端立马再调一下native的一个方法,native的方法被调到即说明 natvie已经成功调到前端的方法,而不要使用方法本身的回调。

webView.callHandler("test", "", new CallBackFunction() {
   @Override
   public void onCallBack(String data) {
      LogUtil.i("test");
   }

});
webView.registerHandler("testBack", new BridgeHandler() {
   @Override
   public void handler(String data, CallBackFunction function) {
     LogUtil.i("testBack");
  }
});

和前端协商好,当我们调用“test”方法的时候,让前端调用我们注册的“testBack”,当testBack被调用的时候,我们就认为test方法有被前端调用,这样就可以规避onCallBack的不稳定的问题。

5、不要通过Gradle远程依赖,尽量使用module本地依赖

最重要的一条,不要通过gradle远程依赖JsBridge,不要通过gradle远程依赖JsBridge,不要通过gradle远程依赖JsBridge,重要的事情说三遍

implementation'com.github.lzyzsd:jsbridge:1.0.4'

这会导致callHandler的方法在某些场景下的调用不稳定,即有时候可以调到有时候调不到。

webView.callHandler("test", "", new CallBackFunction() {
  @Override
  public void onCallBack(String data) {

  }

});

解决办法有两点:
解决方案一: 将库下载到本地直接以module的形式依赖。

没了。。。
这样解决了call前端方法不稳定的问题,甚至解决了onCallBack回调不稳定的问题。
答案应该是如issue上所说。
坦白说,翻了众多issue,看到这条issue的时候我的内心是崩溃的,一直以为是native和前端的联调出了问题。

image

虽然这样貌似可以解决问题但是我们还有方案二

解决方案二: callHandler()方法在某些场景下的低概率不稳定问题影响太不好了,以至于我们在用方案一解决问题后还是不放心,于是就加上了另外一套容错机制:

Observable observable = Observable.interval(0, 1, TimeUnit.SECONDS);
//”test“方法有失败的概率 写个2秒循环的定时器重试,成功调用后退出并释放定时器(经过测试在不稳定的时候连续调用2-3次就能重试成功)。
mObserver =new DisposableObserver() {
  @Override
  public void onNext(@NonNull Long aLong) {
    webView.callHandler("test", json, new CallBackFunction() {
      @Override
      public void onCallBack(String data) {
           //使用本地module依赖的方式貌似是解决了onCallBack不稳定的问题。
           //走到这里说明调用到了,结束循环。
            dispose();
          }
      });
    }
};observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(mObserver);

以上的逻辑就是:如果第一次调用callHandler,如果1秒钟之后还没有收到回调我们会再次进行重试,知道成功为止。观察情况是,如果有出现异常,大概在重复调用第2-3次的时候可以成功,成功之后跳出并释放计时器。不过经过大量的测试,我们发现,在使用了方案一的情况下,几乎已经没有会使用到方案二的情况,不过为了容错,我们依然保留。

结语:
以上就是使用JSBridge踩过的坑,可以说不稳定的这种偶现问题实在是太头疼了,如果以后还有在使用JSBridge开发一些复杂场景的话,希望大家能基于这几条原则(问题),除了以上说的,个人还有一些反思:
一、遇到一些开源库的问题,多去翻翻issue上前人提过的问题,说不定会有意外收获,issue也没有的话再去看看源码实现。
二、遇到问题,适当的出去走走,呼吸呼吸新鲜空气,脑袋清醒的时候,发现很多问题其实不是问题。

你可能感兴趣的:(Android#JSBridge踩坑问题记录)