使用
Kotlin
// 系统返回键
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (dwebView?.canGoBack() == true) dwebView?.goBack()
else {
isEnabled = false
onBackPressedDispatcher.onBackPressed()
isEnabled = true
}
}
})
这样就可以了 ✅
但要实现"真正的回退功能",还需要注意几个关键点:
历史栈构建要点
- 必须确保历史栈能正常生成
shouldOverrideUrlLoading方法中对http/https请求要返回false,否则无法记录历史,导致canGoBack()始终为false- 遇到
target="_blank"或window.open的页面,需要在WebChromeClient.onCreateWindow中将新窗口 URL 重定向到当前 WebView,否则不会生成历史记录
返回键处理的优化建议
- 在 Activity 中,"没有历史"时直接调用
finish()即可 - 使用
dispatcher.onBackPressed()递归处理也可以,但finish()更直观
推荐实现代码
kotlin
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
val wv = dwebView
if (wv != null && wv.canGoBack()) {
wv.goBack()
} else {
// Activity 处理
finish()
// Fragment 处理
// findNavController().popBackStack() 或 parentFragmentManager.popBackStack()
}
}
})
常见问题排查
- 前端是 SPA 应用且使用了
history.replaceState(不增加历史记录)导致回退失效 - 需要与前端协调 - 拦截了
http/https请求并返回true自行处理加载 - 历史记录不会增加 - 未处理
target="_blank"- 历史记录不增加 - 错误页面/重定向导致停留在同一页面(可在
onReceivedError中跳转自定义错误页并允许后退)
Fragment 使用注意
- 使用
addCallback(viewLifecycleOwner, ...)绑定到视图生命周期,防止内存泄漏 - 没有历史记录时使用
popBackStack(),不要调用finish()
X5(TBS)内核适配
只需将类名替换为 com.tencent.smtt.sdk.*,逻辑完全一致
总结
基础框架"canGoBack → goBack;否则执行系统返回"的思路是正确的。只需处理好"同页打开链接"和"新窗口重定向到当前页"这两点,回退功能就能稳定工作。