摘要:Android/鸿蒙用户有一个根深蒂固的习惯:按侧边/底部返回键回退页面。但在单页应用(SPA)中,如果不做特殊处理,按一次返回键就会直接关闭应用。本文介绍了如何"劫持"物理返回事件,实现"页面内回退"与"双击退出"的逻辑。
🔙 1. 用户的困惑
Web App 的路由通常是虚拟的(Hash 路由或 History API)。
当用户在游戏中进入了"设置"页面,按下手机侧边的返回手势时,他期望的是回到"游戏主页"。
但实际发生的是:应用直接退到了桌面。
这是因为 ArkWeb 默认不消费系统的 Back 事件,除非我们显式告诉它。
🔗 2. 拦截链条
我们需要构建一个拦截链:
System Back Event -> ArkUI -> ArkWeb -> Check History -> Go Back OR Exit App.
2.1 启用 Web 访问历史
首先,确保 Web 组件允许访问浏览记录。
Web({ src: this.url, controller: this.controller })
// 这一步很重要,虽然默认通常是开启的
.domStorageAccess(true)
2.2 接管系统返回 (ArkTS)
在 EntryAbility.ets 或主页面中,重写 onBackPressed 接口。
// Index.ets
@Entry
@Component
struct Index {
@State webController: WebviewController = new web_webview.WebviewController();
// 关键:拦截系统返回键
onBackPress() {
// 1. 检查 Web 是否可以回退
if (this.webController.accessBackward()) {
this.webController.backward();
return true; // 消费事件,不再传递给系统(即不退出应用)
}
// 2. 如果 Web 不能回退(在首页),执行"双击退出"逻辑
if (this.shouldExit()) {
return false; // 返回 false,交给系统处理(退出应用)
} else {
this.showToast("再按一次退出应用");
this.lastBackTime = Date.now();
return true; // 消费事件,暂不退出
}
}
private lastBackTime: number = 0;
private shouldExit(): boolean {
return Date.now() - this.lastBackTime < 2000;
}
}
🎭 3. 进阶:SPA 的特殊处理
对于 Vue/React 这种 SPA,webController.accessBackward() 往往不准确,因为 URL 可能没变(Hash 模式)或者 History Stack 被手动修改了。
更精准的做法是将返回逻辑下放给 JS 处理。
3.1 JS 监听器
Web 端提供一个 onBackPressed 钩子。
// 注册到全局
window.onNativeBack = function() {
// 检查是否有弹窗打开
if (document.querySelector('.modal.visible')) {
closeModal();
return true; // 已处理
}
// 检查路由
if (window.location.hash !== '#/home') {
window.history.back();
return true; // 已处理
}
return false; // 没法处理,请 Native 退出应用
};
3.2 Native 调用
修改 onBackPress:
onBackPress() {
// 同步调用 JS 不太现实,通常只能异步
// 但 onBackPress 需要立即返回 boolean
// 这是一个经典的死锁问题
}
死锁破解:
由于 onBackPress 必须同步返回结果,而 runJavaScript 是异步的。我们通常采用**“总是拦截”**策略。
- Native
onBackPress永远返回true(拦截)。 - Native 发送事件给 JS:
window.dispatchEvent(new Event('hardwareback'))。 - JS 判断:
- 如果能回退,JS 自己处理。
- 如果不能回退(在首页),JS 调用 Native 的
app.exit()接口。
这种"JS 主控"模式虽然复杂,但灵活性最高,能处理诸如"关闭弹窗"、"取消选中"等细粒度逻辑。
📝 4. 总结
对于简单的 H5 应用:
使用 ArkTS accessBackward() 检查 即可满足 90% 的需求。
对于复杂的 SPA 应用:
推荐 “JS 主控模式”,Native 只负责传递按键信号,由前端路由(Vue Router / React Router)来决定是后退路由、关闭 Modal 还是真正退出 App。这才是 Hybrid App 的最佳实践。
1338

被折叠的 条评论
为什么被折叠?



