You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中WebView的canGoBack始终返回false问题咨询

WebView canGoBack()始终返回false的解决方案

问题场景

在APP中使用ViewPager+TabLayout实现标签页,其中一个标签页包含BasketRootFragment,该Fragment内部嵌套WebViewFragment。当WebView打开非指定域名的链接时,在shouldOverrideUrl中返回true并手动调用loadUrl加载新链接,但后续调用binding.webview.canGoBack()始终返回false,无法触发页面回退。

相关代码

BasketRootFragment实现

class BasketRootFragment : Fragment() {

    private lateinit var basketFrag: WebViewFragment
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_basket_root, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    }

    override fun setMenuVisibility(menuVisible: Boolean) {
        super.setMenuVisibility(menuVisible)
        if(menuVisible) {
            if(::basketFrag.isInitialized.not()){
                childFragmentManager.commit(allowStateLoss = true) {
                    val urlString = RemoteConfigRepository.getString(RemoteKey.url_basket).addBaseUrl()
                    val basketTabTitle = RemoteConfigRepository.getString(RemoteKey.trans_tab_basket)
                    basketFrag = WebViewFragment.forBasket(Triple(Screen.BASKET, basketTabTitle, urlString))
                    replace(R.id.fragment_container_view, basketFrag, WebViewFragment.TAG)
                    addToBackStack(WebViewFragment.TAG)
                }
            }
        }
    }

    fun goBackInWeb(): Boolean = basketFrag.goBackInWeb()
    fun canGoBackInWeb(): Boolean = basketFrag.canGoBackInWeb()
    fun reload(restCaller: RestCaller) = basketFrag.reload(restCaller)
}

shouldOverrideUrl处理逻辑

private fun shouldOverrideUrl(webView: WebView?, url: String): Boolean {
if(isBasketFragment() && url.isBasketUrl().not()){
    webView?.loadUrl(url)
    return true
}
   return false
}

回退调用代码

if(binding.webview.canGoBack()) { // 始终返回false
    binding.webview.goBack()
}

核心原因

当在shouldOverrideUrl中返回true时,WebView会认为你已经完全处理了该链接的跳转逻辑,不会将当前页面加入到WebView的历史栈中。此时手动调用loadUrl加载新页面,历史栈中只会存在新页面,因此canGoBack()始终返回false。

修复方案

方案1:让WebView自行处理外部链接跳转(推荐)

修改shouldOverrideUrl的逻辑,对于非指定域名的链接,直接返回false,让WebView自行处理跳转,这样WebView会自动维护历史栈:

private fun shouldOverrideUrl(webView: WebView?, url: String): Boolean {
    if(isBasketFragment() && url.isBasketUrl().not()){
        // 返回false,让WebView自行处理跳转,自动维护历史栈
        return false
    }
    // 其他需要拦截处理的场景返回true
    return true
}

方案2:手动维护历史栈(特殊场景使用)

如果因业务需求必须手动调用loadUrl,可以在加载新页面之前,手动将当前页面的状态保存到历史栈中(不推荐,容易出现栈异常):

private fun shouldOverrideUrl(webView: WebView?, url: String): Boolean {
    if(isBasketFragment() && url.isBasketUrl().not()){
        webView?.let {
            // 手动保存当前页面状态到历史栈
            it.saveState(Bundle())
            it.loadUrl(url)
        }
        return true
    }
    return false
}

额外检查项

  1. 确保WebViewFragment正确保存/恢复状态:
    在WebViewFragment中添加状态保存逻辑,避免Fragment重建时丢失WebView历史:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    savedInstanceState?.let {
        binding.webview.restoreState(it)
    }
}

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    binding.webview.saveState(outState)
}
  1. 确认goBackInWeb()方法实现正确:
fun goBackInWeb(): Boolean {
    return if (binding.webview.canGoBack()) {
        binding.webview.goBack()
        true
    } else {
        false
    }
}

内容的提问来源于stack exchange,提问作者Taimoor Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 12:07:51