uni.onaccelerometerchange 必须配合 uni.startaccelerometer 才能触发回调,真机不启用则完全静默;需在 onshow 启动、onhide/unload 停止,ios 需配置权限,h5 不支持;摇一摇应基于合加速度模长双阈值判断,并用状态锁防抖。

uni.onAccelerometerChange 必须配合 uni.startAccelerometer 才能工作
直接写 uni.onAccelerometerChange 监听器,但不调用 uni.startAccelerometer,真机上**完全不会触发回调**——这不是 bug,是 uni-app 的设计约束。iOS 和 Android 都要求显式启用传感器,否则系统根本不推送数据。
实操建议:
- 不要在
App.vue的onLaunch里启动,Android 8.0+ 和多数国产 ROM 会拒绝后台启用,应改在页面onShow中调用uni.startAccelerometer - 必须在
onHide或onUnload里配对调用uni.stopAccelerometer,否则可能被系统判定为异常耗电而强制终止 - iOS 真机需在
manifest.json→ App SDK 配置 → iOS 模块权限中勾选「运动与健身」,且 Info.plist 里补上NSMotionUsageDescription字符串,否则静默失败、无任何报错提示 - H5 端压根不支持该 API,别在浏览器里调试;要用
window.addEventListener('devicemotion', ...),但需确保 WebView 已透传传感器事件(如 Capacitor 需先申请accelerometer权限)
加速度模长比单轴值更可靠
用 Math.abs(res.x) > 2.0 这类单轴阈值判断摇动,误判率极高:侧握、躺姿、走路颠簸都容易触发或漏判。真实摇一摇是三维空间的线性突变,必须计算合加速度模长:Math.sqrt(x*x + y*y + z*z)。
实操建议:
- 缓存最近 3–5 帧的模长值,避免单点毛刺干扰
- 设定双条件:当前模长 > 2.0(约 2g),且与上一帧差值 > 1.8(单位 g),同时满足才视为有效起始抖动
- Android 低端机采样率低,可传参
{ interval: 'game' }提升频率(HBuilderX 3.1.22+ 支持),但 iOS 上该参数常被系统降频,实际建议用'ui'
防抖不是加 setTimeout 就完事
一次真实摇动常在 300ms 内产生多个符合条件的峰值,若只靠 setTimeout 延迟执行,仍可能连续弹窗或跳转。关键在状态锁 + 固定窗口期。
实操建议:
- 检测到有效抖动后,立即设
isShaking = true,并在 1500ms 后重置,期间所有新触发直接忽略 - 不要用
clearTimeout动态取消旧定时器——摇动持续时间不可控,固定窗口比“重置计时”更稳 - 监听回调里避免直接做重逻辑(如
uni.navigateTo或弹窗),先节流(例如 500ms 内只响应一次),再交由业务层处理
uni.onDeviceMotionChange 不适合做摇一摇
uni.onDeviceMotionChange 返回的是姿态角(alpha/beta/gamma),反映设备朝向变化,对快速小幅旋转敏感,但对线性晃动(如手掌甩动)响应极弱。实测中,左右摆手动作,它可能只触发 1–2 次,而 uni.onAccelerometerChange 能稳定捕获 5+ 个峰值。
微信、QQ 等原生 App 全部基于加速度计实现摇一摇,而非陀螺仪或磁场数据。别被名字误导——onDeviceMotionChange 不是“设备运动”的通用接口,它本质是 orientation event 的封装,和加速度突变无关。
补充一点:鸿蒙 NEXT(API 12+)已明确标注该 API “仅模拟器可用”,真机调用会直接跳过监听注册。











