uni-app摇一摇需用加速度变化率(jerk)判定而非单轴绝对值,必须调用uni.startaccelerometer()启动监听,缓存3–5帧计算差值平方和连续超阈值才触发,并在onhide/onunload中配对注销回调与停止传感器。

uni-app 的摇一摇功能在 App 端不能靠 Math.abs(res.x) > 30 这种单轴粗暴判断——真机上几乎必误判或漏判,尤其华为/小米省电模式、iOS 首次未交互、Android 后台采样被限等场景下,原始加速度值根本不可信。
uni.onAccelerometerChange 监听没反应?先确认是否真正启动了
很多人调了 uni.getAccelerometerFrequency 就以为传感器“开了”,其实它只是设置采集频率,不触发任何数据。真正要让监听生效,必须显式调用 uni.startAccelerometer(),否则 uni.onAccelerometerChange 永远收不到数据。
- 必须按顺序执行:
uni.startAccelerometer()→uni.onAccelerometerChange(callback) -
uni.getAccelerometerFrequency是异步接口,要用success回调确认是否设置成功(iOS 最高支持 100Hz,Android 多为 50Hz;设太高会静默降级) - H5 端完全不支持该系列 API,模拟器无效,真机调试必须用 iOS 或 Android 设备
- App 端首次调用需用户有交互(如点击按钮),iOS WKWebView 下若页面刚加载就启动,可能因未触发 JSBridge 导致无数据
为什么直接比加速度绝对值会误触发?关键在 jerk(加速度变化率)
走路、放手机、按屏幕、甚至呼吸都可能让某轴瞬时超阈值。摇一摇的本质不是“动得大”,而是“动得快且方向突变”——即 jerk。只看 res.x、res.y、res.z 的瞬时值,等于把地震仪当节拍器用。
- 缓存最近 3–5 帧的加速度值(建议用
Array.push()+.slice(-5)控制长度) - 每帧计算与前一帧的差值平方和:
dx*dx + dy*dy + dz*dz(避免开方损耗性能) - 仅当该差值平方和连续 2–3 帧 > 15–25(实测推荐起始值 20)才记为一次有效抖动
- 累计 2–3 次抖动后触发摇一摇,而非单次超阈值就响应
页面跳转后还在触发回调?这是内存泄漏,不是功能残留
uni.onAccelerometerChange 是全局监听,一旦注册不手动取消,页面 onUnload 或 onHide 后仍会执行回调——轻则报 Cannot read property 'xxx' of null,重则持续耗电、干扰其他页面逻辑。
- 必须在
onHide或onUnload中调用uni.offAccelerometerChange(handle),且传入的回调函数引用要一致 - 推荐封装成可注销句柄:
const handle = res => { /* 处理逻辑 */ };→uni.onAccelerometerChange(handle)→uni.offAccelerometerChange(handle) - 对应地,若用了
uni.startAccelerometer(),退出前务必配对调用uni.stopAccelerometer() - 避免在
App.vue的onLaunch全局启动,优先在具体页面的onShow启动、onHide停止
华为/小米省电模式下数据断续或延迟高?这不是 Bug,是系统级限制
Android 8.0+ 对后台传感器访问收紧,不同厂商 ROM 实现差异极大:华为/小米部分机型在省电模式下会强制将加速度采样频率降至 5Hz 甚至暂停;部分机型还要求 manifest.json 中开启 "usingComponents": true(虽非权限必需,但某些 ROM 会连带校验)。
- 不要依赖固定频率,用
uni.getAccelerometerFrequency设置后,以实际收到的数据帧间隔为准 - 加 fallback 提示:“请关闭省电模式以保障摇一摇体验”,并在 UI 层提供手动触发入口(如按钮)作为备用路径
- 实测发现:iOS 在后台约 30 秒后自动停采,Android 后台行为更不可控,因此摇一摇逻辑应严格限定在前台活跃页面
- 防抖窗口至少设为 800ms,一次判定后清空缓存并暂停监听,避免连续抖动被误计为多次
真正难的不是写几行监听代码,而是理解加速度数据在真实设备上的“不靠谱”——它受系统策略、硬件差异、电源管理层层干预。所谓“稳定”,是靠缓存、差分、连续帧判定、及时注销、fallback 提示这一整套组合拳撑起来的,不是某个阈值调对了就万事大吉。











