原生端,android的代码:
webView.setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); showPd(); if (newProgress == 100) { webView.loadUrl("javascript:loginCallback(" + "’" + GsonUtil.creatSipmleGson().toJson(LoginUserManager.getInstance()) + "’" + ")"); L.e("logininfo",GsonUtil.creatSipmleGson().toJson(LoginUserManager.getInstance())); hidePd(); } } }); |
Reactjs中H5的页面中:
。。。 export default class App extends Component { 。。。 constructor(props) { console.log("App constructor"); super(props); autoBind(this); this.loginCallback = this.loginCallback.bind(this); } componentWillMount() { console.log("App componentWillMount"); console.log(window); console.log(window.userInfoDict); window.loginCallback = this.loginCallback; } //Native(iOS/Android):loginCallback(String userInfoJsonStr); loginCallback(userInfoJsonStr){ console.log(`loginCallback: userInfoJsonStr=${userInfoJsonStr}`); alert(userInfoJsonStr); // let userInfoDict = Object(userInfoJsonStr); let userInfoDict = JSON.parse(userInfoJsonStr); console.log(userInfoDict); // alert(userInfoDict); console.log(typeof(userInfoDict)); //object console.log(userInfoDict.currentCowfarmId); console.log(userInfoDict.cowfarmList); console.log(typeof(userInfoDict.cowfarmList)); //object window.userInfoDict = userInfoDict; console.log(window.userInfoDict); // alert(window.userInfoDict); } |
可以实现基本的效果:
当原生Android端登录完毕后,判断H5中浏览器内容加载完毕,然后调用loginCallback,把用户信息的json字符串传递到H5端
但是有个问题:
之后,每次(比如通过Prect-router中的route(“/xx”)去)页面切换时,都会导致此处的触发回调
所以希望去解决此问题。
只实现:
原生端能判断webview第一次加载完毕才调用回调函数
之后webview中页面切换时,不要调用。
看了android代码,感觉:onProgressChanged不像是 webviewLoadCompleted
之类的含义,而是进度有变化时就调用。
搜:
WebChromeClient onProgressChanged
503596 – Multiple callbacks from onProgressChanged with 100% in WebView – chromium – Monorail
“Note that there is a separate callback `onPageFinished` which is really indicating that the page’s resources have finished loading. `onProgressChanged` is intended to be used to update loading progress bar. ”
这样的解释才对。
Issue 1080143003: Move DidStartLoading, DidStopLoading, DidChangeLoadProgress to RFHI. – Code Review
onPageFinished
DidStopLoading
WebViewClient与WebChromeClient的区别 – 泡在网上的日子
android – Display webview with dialog progress and webchrome client – Stack Overflow
Android WebView WebChromeClient : inaccurate progress value in onProgressChanged() – Stack Overflow
WebChromeClient | Android Developers
竟然只有:
onProgressChanged
没有:
onPageFinished
DidStopLoading
之类的。
WebView之加载网页时增加进度提示 – 飘杨…… – 博客园
好像只能通过:
if(newProgress >= 100){
去判断页面加载完毕了?
webchromeclient on page finished
Android Webview: Detect when rendering is finished – Stack Overflow
WebChromeClient用onProgressChanged且:
if (progress == 100) {
// do something
}
WebViewClient用onPageFinished
android – How to listen for a WebView finishing loading a URL? – Stack Overflow
有多个页面(iframe?)的话,会有多个:onPageFinished(和onPageStarted)
-》那如果换用onPageFinished 貌似和onProgressChanged progress >= 100 也没啥区别了,都是导致多次调用啊。
android – Are WebViewClient and WebChromeClient mutually exclusive? – Stack Overflow
WebChromeClient | Android Developers
WebView的几个常见功能使用 – 一片纯净的热土 – CSDN博客
貌似真的是没有好的解决办法:
暂时只能靠ReactJS中H5去手动判断是否第一次调用了。。。
也想到了:
如果让android端去加上判断,只有当加载了首页 然后onProgressChanged中progress是100,才调用
-》但是也是会存在,如果移动端H5中,有其他情况,比如刷新,退出后再登录等,去加载首页,还是会多次调用,还是需要H5端去做限制,还是无法完全避免H5端不需要额外特殊判断
WebChromeClient onProgressChanged progress 100 multiple call
Android WebView WebChromeClient : inaccurate progress value in onProgressChanged() – 推Code
就是用我上面想到的办法:
判断是否加载的是:某个页面,比如主页
如果不是,则不去调用
Android Splash screen while loading webview – Recalll
【总结】
感觉Android中,不论是用
(1)WebChromeClient用onProgressChanged
且加上判断:
if (progress == 100) {
// do something
}
(2)WebViewClient用onPageFinished
结果都是:
会调用多次
即使android端加了判断,是某个页面的url(比如首页”/“),但是也还是无法完全避免多次加载,比如,刷新页面了之类的。
所以,干脆还是放在H5页面中去加上判断吧:
export default class App extends Component { state = { curUrl : "/" }; constructor(props) { 。。。 window.hasCallLoginCallback = false; } //Native(iOS/Android):loginCallback(String userInfoJsonStr); loginCallback(userInfoJsonStr){ if (window.hasCallLoginCallback) { return; } window.hasCallLoginCallback = true; 。。。 let userInfoDict = JSON.parse(userInfoJsonStr); 。。。 window.userInfoDict = userInfoDict; 。。。 } |
然后其他地方,比如退出登录处,再去重置该变量:
onConfirmLogout(){ 。。。 //clear this to make sure following loginCallback will be called in app.js window.hasCallLoginCallback = false; this.logout(); } |
即可基本实现:
只调用一次loginCallback,别处不会再次触发。且,退出登录后,重新登录进去后,还是要正常的继续调用一次loginCallback的。