Android开发问题记录-webview goBack键失效

在Android 4.4以上系统中,自定义WebView遇到goBack()回退功能失效的问题,表现为大约率无法正常回退。经过版本复查、找不同、验证改动等步骤,发现问题与`android:targetSdkVersion`提升到23有关。进一步测试发现,当`targetSdkVersion`小于18时,回退功能正常。问题最终定位在WebChromeClient中onProgressChanged的js注入处理,去掉该处理后功能恢复。解决办法是在js注入时针对KitKat及以上版本使用`evaluateJavascript`,其余版本使用`loadUrl`。然而,为何仅在特定情况下`loadUrl`影响历史栈,以及为何仅在onProgressChanged中使用会有问题,仍然是未解之谜。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现象

    在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();
        }

做回退功能,发现不能正常回退。(此问题并非每次都出现,而是大概率出现。)


定位问题:

  1. 版本复查:由于属于版本迭代开发,此问题在新版本中被发现,先排查老版本是否存在此问题。结果:老版本不复现;下一步:找新老版本的不同。
  2. 找不同:对比新老版本不同。结果:webview相关没有相关改动,怀疑与系统版本相关;下一步:从怀疑点入手进行改动的验证。新老版本的AndroidManifest.xml中的android:targetSdkVersion不同,由17升为23。(由此牵出android:targetSdkVersion的含义及作用,后面的文章中会总结)
  3. 验证改动:将现有新版本的android:targetSdkVersion改为17,。结果:新版本的goBack功能正常;下一步:验证此字段的临界值。
  4. 进一步验证此参数:通过测试,当android:targetSdkVersion的版本小于登录18时,goBack均正常;下一步:矛头转向19webview。(写到这里大家可能就想到了,Android4.4之后webview的改动,由Webkit引擎换为Chrome,此改动在后续文章中总结)
  5. 19webview的验证:着重验证19及以上的webview,通过写最简demo(即只有webivew加载,其余均不做设置)。结果:最简webview可用;下一步:查看自定义webview基本webview的不同点,对可疑点进行一一验证
  6. 对比自定义webview与最简webview的使用:对于各种设置及js注入进行验证。结果:WebChromeClient中onProgressChanged的js注入处理去掉,功能恢复正常(此js注入方法并非只出现在此方法中,在onPageStarted、onPageFinished中均存在);下一步:js注入的方法入手(loadUrl("javascript:"))
  7. js注入:对比去掉此处的js注入与加上js注入的情况
  8. 查看webview历史栈:调用WebView.copyBackForwardList()得到历史栈及当前url的index等相关信息
  9. 对比历史栈信息:结合抓包工具及log信息,发现栈内信息存在两种情况,一种,符合预期;另一种,跟预期不同(此对比并非用同一个url来做的处理,由于URL中的内部实现会有不同,所以出现的现象也有差别)
  10. 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);
    }

仍存在的疑惑:

  1. 为什么在19及以上的系统,运用loadUrl的方式,会影响历史栈?
  2. 为什么只有在onProgressChanged中用loadUrl注入会存在问题?(在onPageStarted、onPageFinished等方法中,运用此方法均为正常)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值