现象:
在Android4.4及以上的系统中,使用自定义的webview打开连接,在页面中再点击进入二级或三级页面,通过
if (this.mWebView.canGoBack()) {
this.mWebView.goBack();
mActionBar.setCloseOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
GlobalUtils.hideKeyboard(getActivity());
finish();
}
});
} else {
super.onBackPressed();
}
做回退功能,发现不能正常回退。(此问题并非每次都出现,而是大概率出现。)
定位问题:
- 版本复查:由于属于版本迭代开发,此问题在新版本中被发现,先排查老版本是否存在此问题。结果:老版本不复现;下一步:找新老版本的不同。
- 找不同:对比新老版本不同。结果:webview相关没有相关改动,怀疑与系统版本相关;下一步:从怀疑点入手进行改动的验证。新老版本的AndroidManifest.xml中的android:targetSdkVersion不同,由17升为23。(由此牵出android:targetSdkVersion的含义及作用,后面的文章中会总结)
- 验证改动:将现有新版本的android:targetSdkVersion改为17,。结果:新版本的goBack功能正常;下一步:验证此字段的临界值。
- 进一步验证此参数:通过测试,当android:targetSdkVersion的版本小于登录18时,goBack均正常;下一步:矛头转向19webview。(写到这里大家可能就想到了,Android4.4之后webview的改动,由Webkit引擎换为Chrome,此改动在后续文章中总结)
- 19webview的验证:着重验证19及以上的webview,通过写最简demo(即只有webivew加载,其余均不做设置)。结果:最简webview可用;下一步:查看自定义webview基本webview的不同点,对可疑点进行一一验证
- 对比自定义webview与最简webview的使用:对于各种设置及js注入进行验证。结果:WebChromeClient中onProgressChanged的js注入处理去掉,功能恢复正常(此js注入方法并非只出现在此方法中,在onPageStarted、onPageFinished中均存在);下一步:js注入的方法入手(loadUrl("javascript:"))
- js注入:对比去掉此处的js注入与加上js注入的情况
- 查看webview历史栈:调用WebView.copyBackForwardList()得到历史栈及当前url的index等相关信息
- 对比历史栈信息:结合抓包工具及log信息,发现栈内信息存在两种情况,一种,符合预期;另一种,跟预期不同(此对比并非用同一个url来做的处理,由于URL中的内部实现会有不同,所以出现的现象也有差别)
- js注入方式的不同:查看
- com.android.webview.chromium.WebViewChromium中的loadUrl其中有这么一段注释
// For backwards compatibility, apps targeting less than K will have JS URLs evaluated
// directly and any result of the evaluation will not replace the current page content.
// Matching Chrome behavior more closely; apps targetting >= K that load a JS URL will
// have the result of that URL replace the content of the current page.(翻译:为了向后兼容,target小于KitKAT的应用可直接执行js URL且执行的任何结果均不会影响当前页面的内容。为了与Chrome行为更加贴近;target大于等于KITKAT的应用加载js url时将会产生js url替换当前页面内容的结果)
结论:
在js注入时,做如下处理:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // 对于系统19及以上使用evaluateJavascript来做异步js注入
mWebView.evaluateJavascript(JAVASCRIPT_URL.substring(JAVASCRIPT_SCHEME.length()), null);
} else { // 其余的直接用loadUrl的方式处理
mWebView.loadUrl(JAVASCRIPT_URL);
}
仍存在的疑惑:
- 为什么在19及以上的系统,运用loadUrl的方式,会影响历史栈?
- 为什么只有在onProgressChanged中用loadUrl注入会存在问题?(在onPageStarted、onPageFinished等方法中,运用此方法均为正常)