亚洲必赢76net-亚洲必赢登录-亚洲必赢手机入口
做最好的网站

亚洲必赢76netAndroid混合开发之Bridge

日期:2019-11-19编辑作者:计算机

  电商或者内容类APP中,H5通常都会占据一席之地,Native跟H5通信会必不可少,比如某些场景H5通知native去分享,native通知H5局部刷新等,Android本身也提供这样的接口,比如addJavaInterface、loadUrl(java:…),而需要支持的能力也要是双工的。

  实现这种机制的方式并不唯一,但使用不当经常会引入很多问题,比如:H5同Native需要一个中间js文件,实现简单的通信协议,这个js文件有的产品做法是让前端自己加载,有的做法是客户端注入,也就是通过loadUrl(java:…)注入。采用客户端注入这种方式就多少有问题,因为没有一个很合适的时机既保证注入成功,又保证注入及时。如果在onPageStarted时注入,很多手机会注入失败,如果onPageFinished时注入,又太迟,导致很多功能打折扣。再比如:有些人通过prompt方式实现H5通知Native,而prompt是一个可能产生问题的同步方法,一旦无法返回,整个js环境就会挂掉,导致所有H5页面都无法打开,下面简单说下两种实现,一是通过addJavaInterface,另一种就是通过prompt。

  经测试,其实是可以通知到Native的,不过有一点需要注意callNative是这JavaBridge这个线程中执行的,虽然不提清楚它跟JS线程的关系,但JS会阻塞等待callNative函数执行完毕再往下走,所以 @JavaInterface注解的方法里面最好也不要做耗时操作,最好利用Handler封装一下,让每个任务自己处理,耗时的话就开线程自己处理。

  如果前端通知Native时需要回调怎么办?可以抽离到一个中间的js,为每个任务设置一个ID,暂存回调函数,等到Native处理结束后,先走这个中间的js,找到对应的js回调函数执行即可,

  以上js代码完成回调的暂存、通知native执行,native那边会收到js消息,同时里面包含着id,等到native执行完毕后,将执行结果与消息id通知到这个中间层js,找到对应的回调函数执行即可,如下:

  这样就完成H5通知Native,同时Native将结果回传给H5,并完成回调这样一条通路。Native通知H5,这条路怎么办?流程大概类似,同样可以基于一个消息ID完成回调,不过更加灵活,因为Native通知前端的接口不太好统一,具体使用自己把握。

  如果混淆了,@JavaInterface注解的方法可能就没了,结果是,JS就没办法知己调用对应的方法,导致通信失败。

  4.2以后,WebView会禁止JS调用没有添加@JavaInterface方法, 解决了安全漏洞,而且很少APP兼容到4.2以前,安全问题可以忽略。

  JavaInterface注入的方法被js调用时,可以看做是一个同步调用,虽然两者位于不同线程,但是应该存在一个等待通知的机制来保证,所以Native中被回调的方法里尽量不要处理耗时操作,否则js会阻塞等待较长时间,如下图

  在js调用window.alert,window.confirm,window.prompt时,会调用WebChromeClient对应方法,可以此为入口,作为消息传递通道,考虑到开发习惯,一般不会选择alert跟confirm,通常会选promopt作为入口,在App中就是onJsPrompt作为jsbridge的调用入口。由于onJsPrompt是在UI线程执行,所以尽量不要做耗时操作,可以借助Handler灵活处理。对于回调的处理跟上面的addJavaInterface的方式一样即可,采用消息ID方式做暂存区分,区别就是这里采用

  同之前JavaBridge线程类似,这里prompt的js线程必须要等待UI线程中onJsPrompt返回才会唤醒,可以认为是个同步阻塞调用(应该是通过线程等待来做的)。

  如果在onJsPrompt睡眠10s,js的prompt函数一定会阻塞等待10s才返回,这个设计就要求我们不能在onJsPrompt中做耗时操作,systrace中可以验证。

  从表现上来看,onJsPrompt必须执行完毕,prompt函数才会返回,否则js线程会一直阻塞在这里。实际使用中确实会发生这种情况,尤其是APP中有很多线程的场景下,怀疑是这么一种场景:

  第二部 :UI线程被调度,恰好销毁了Webview,调用了 (webview的detroy),detroy之后,导致 onJsPrompt不会被回调,prompt一直等着,js线程就一直阻塞,导致所有webview打不开,一旦出现可能需要杀进程才能解决。

  第二部 :UI线程被调度,恰好销毁了Webview,调用了 (webview的detroy),detroy之后,导致 onJsPrompt不会被回调,prompt一直等着,js线程就一直阻塞,导致所有webview打不开,一旦出现可能需要杀进程才能解决。

  如果不主动destroy webview,可以很大程度避免这个问题,具体Chrome的实现如何,还没分析过,这里只是根据现象推测如此。而WebView.addJavaInterface并不会有这个问题,无论是否主动destroy Webview,都不会上述问题,可能chrome对addJavaInterface这种方式做了额外处理,在自己销毁的时候,主动唤起JS线程,但是onJsPrompt所在的UI线程显然没处理这种场景。

  通过@JavaInterface的方法中不要同步处理耗时操作,需要返回值的方法需要阻塞调用(尽量减少)

  通过@JavaInterface的方法中不要同步处理耗时操作,需要返回值的方法需要阻塞调用(尽量减少)

本文由亚洲必赢76netAndroid混合开发之Bridge发布,转载请注明来源:亚洲必赢76netAndroid混合开发之Bridge