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 }
额外检查项
- 确保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) }
- 确认
goBackInWeb()方法实现正确:
fun goBackInWeb(): Boolean { return if (binding.webview.canGoBack()) { binding.webview.goBack() true } else { false } }
内容的提问来源于stack exchange,提问作者Taimoor Khan
相关产品推荐
相关产品推荐

