https://github.com/lzyzsd/JsBridge 也算是比较悠久和使用了。
可供参考的android和IOS,以及前端的使用 https://segmentfault.com/a/1190000018208609
遇到的问题:
比如:
- 从前端在加载WebView的时候,执行了某些动作,一直得不到回应,过一会儿会瞬间刷刷刷执行多次;
- 某个初始化指令,前端是调用了,但是android端需要等很久才能生效,或者不生效。
上述类似的问题,可以研究下我这段分析。
WebView和Html加载时机的关系
这里我不做更深入的讨论。简要地解释下:
android的WebView,其实就是Chrome的内核,与我使用过CEF框架,javafx等Webkit内核其实类似。
标准浏览器,做到客户端上,WebView(不是android也会类似有)2个函数:
public void onPageStarted(xxx)
public void onPageFinished(xxx)
onLoadResource(xxx, url)
-
onLoadResource,指代的是,跳转新url,或者内部中转的url,又或者加载某图片资源,视频资源之前的回调,因此我们这里在这里进行一些url跳转或者做无图浏览,或者做爬虫的时候,加速加载,那么我们可以进行一些拦截;
-
onPageStarted, 指代的是,开始加载url,每一次有一个新的url需要打开都会执行,那么,它可能会有多次执行;
-
onPageFinished,指代的是,其实对应的是,网页所有的资源,DOM全部准备好了才回调。而这个回调,可能是很难完成的,比如JS有些无法加载,某些资源需要下载很久很慢;
JSBridge代码分析
从上述,可以看出,jsbridge的框架中,需要等待onPageFinished以后,才会干2个事情:
第一,加载js代码,初始化jsbridge,通知ready:
执行WebViewJavascriptBridge.js的代码,主要是通知’WebViewJavascriptBridgeReady"。
而前端JS代码中:
document.addEventListener(
‘WebViewJavascriptBridgeReady’,
function () {
registerAppEvent()
isInitBridgeEvent = true
},
false
)
进行了注册,监听,等待着native的通知ready。
第二,执行JS的排队中的指令队列:
我们可以看到android jsbridge库代码中,做了一个startupMessage的队列,用来存储前端发下来的执行,等待onFinish才将它统一执行和干活。
解决方案
看到这里,那么,针对前面的2个问题就迎刃而解了。
在BridgeWebViewClient里面:
private var isLoadedBridgeJs = false
mBinding.webView.webViewClient = object : BridgeWebViewClient(mBinding.webView) {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
lifecycleScope.launch {
delay(500)
if (!isLoadedBridgeJs) { //父类执行了js的逻辑,则这里不再需要处理
isLoadedBridgeJs = true
//**warn** jsbridge的代码逻辑: onPageFinished才进行初始化逻辑;
// 而Finished的时机可能非常晚(网页的dom资源需要加载完成才算数)!
// 而started则很快。
//常规不能这样调用,这里因为父类BridgeWebViewClient 的finish只做了JS和处理排队事务,才能这样调用。不理清楚逻辑,不得任意修改。
super.onPageFinished(view, url)
}
}
///xxxx
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
isLoadedBridgeJs = true //父类执行了js的逻辑,则这里不再需要处理
//xxxx
}
}
}
这里是通过delay一段时间,来裸调用父类的onPageFinished。因为父类的onPageFinished函数里面的干的活,很纯粹,才这样写。
否则还是尽量去继承或者下载库代码来改造。
并且从JS代码可以看出,多次执行并不影响。 if (window.WebViewJavascriptBridge) { return; }有做拦截。
同时,delay(500)的时间,最好是大一点没有关系,建议300-800ms。
因为默认情况,onPageFinished会比较快回调(没有大资源和错误JS,资源的情况下)。
那么,我们的代码通过isLoadedBridgeJs来控制,就不会执行。而是库自行执行了。
如果,500ms,还没有finished来,我们先执行一次,初始化好JSBridge,同时执行一下js端的初始化任务。
等到真正的finished来了以后,再次执行默认的,并没什么影响。
具体的版本具体分析参考。
目前的代码参考的是jsbridge1.0.4。
据我来看1.0.5也照样会有这样的问题。