双击退出必须在app.vue中实现,通过onbackpress监听并用this.lastbacktime跨页记录时间戳,仅首页(栈底)触发plus.runtime.quit(),需条件编译且ios/h5需降级处理。

onBackPress 必须写在 App.vue 里才能全局生效
双击退出是跨页面行为,不能只在某个页面组件里声明 onBackPress。一旦用户从首页跳到二级页,页面级的监听就彻底失效——你写的逻辑只在当前页起作用,切页即丢失。
正确做法是把整个双击判断逻辑下沉到 App.vue 的生命周期中。这里才是整个 App 的入口级上下文,this.lastBackTime 才能稳定挂载、跨页复用。
-
onBackPress在组件中声明完全无效,只在App.vue或pages/xxx.vue中生效 - 必须配合
options.from === 'backbutton'过滤,否则会误拦uni.navigateBack()等 JS 调用 - 不要在
onLaunch里直接注册plus.key.addEventListener,它依赖plusready,且仅限 App-PLUS 平台
时间戳判断必须在函数入口立刻 return true
这是最常踩的坑:不立即 return true,系统就会先执行默认返回(比如跳上一页),弹窗都来不及显示。
正确顺序是:取当前时间 → 判断间隔 → 满足双击条件则调 plus.runtime.quit() 并 return true;不满足则弹 toast 并 return true。不能把 return true 写在 uni.showModal 的 success 回调里。
- 变量
this.lastBackTime必须挂载在App.vue实例上(如data中),不能是局部变量 - 阈值设为
2000是经验值,太短易误触,太长体验拖沓 - 清零必须用
setTimeout(() => { this.lastBackTime = 0; }, 2000),箭头函数确保this绑定正确
非首页要禁用双击退出逻辑
如果用户在表单页、详情页等子页按两次返回键,你不该直接退出 App,而应允许正常后退。否则体验断裂,用户无法完成操作。
用 getCurrentPages().length === 1 判断是否在栈底(即首页),只有这时才触发退出逻辑。其他页面一律放行默认返回行为。
- tabbar 页面可能无法被
uni.navigateBack()正确退栈,此时可 fallback 到plus.runtime.quit() - iOS 上
plus.runtime.quit()静默失败,审核也禁止强制退出,需降级提示“请手动关闭” - H5 完全不触发
onBackPress,双击逻辑天然无效,别浪费精力适配
plus.runtime.quit() 必须用条件编译包裹
plus.runtime.quit() 只在 App-PLUS 环境下有效,H5 和小程序里调用会直接报错。必须用 // #ifdef APP-PLUS 包裹,否则编译阶段就失败。
鸿蒙平台也不能直接用这个 API,得通过 UTS 插件调 context.terminateSelf(),否则白屏或无响应。
- 别在业务页重复绑定监听,避免多次调用
plus.runtime.quit()导致异常退出 - WebView 场景下,物理返回键默认关闭 web-view,需额外用原生实例的
canBack和back方法干预 - 真正容易被忽略的是:刷新 H5 页面后,
history.back()和getCurrentPages()行为不一致,这不是 bug,而是浏览器历史栈与 uni-app 页面栈天然隔离











