uni.startAccelerometer必须由用户手势触发,iOS和部分Android机型否则无数据;需显式按钮启动、及时监听、动态计算jerk、H5改用devicemotion、页面离开时必须stop。

uni.startAccelerometer 必须由用户手势触发,否则 iOS 和部分 Android 机型无数据
iOS WKWebView 从 12.2 起强制要求:加速度传感器必须由用户点击、触摸等手势首次激活,onLoad 或 onShow 自动调用 uni.startAccelerometer 会静默失败,uni.onAccelerometerChange 根本收不到任何数据。Android 部分华为/小米机型在省电模式下也会直接拒绝启动。
实操建议:
- 页面上必须放一个显式按钮,比如「开启摇一摇」,
@click中调用uni.startAccelerometer - 调用后立即监听
uni.onAccelerometerChange,别等下个生命周期 - 首次成功后,后续页面跳转再返回,仍需重新触发——不能靠缓存状态“自动恢复”
- 加个 fallback 提示:
uni.showToast({ title: '请关闭省电模式', icon: 'none' }),尤其在fail回调里判断是否为权限/省电导致
别直接比对 x/y/z 绝对值,jerk(加速度变化率)才是关键指标
单看 Math.abs(res.x) > 15 这类写法,在走路、放手机、按屏幕时极易误判;躺着摇或侧握手机又容易漏判。真正反映“摇”的是加速度在短时间内的剧烈突变,也就是 jerk = Δa / Δt。
实操建议:
- 缓存最近 2–3 帧的
res.x、res.y、res.z值,计算每帧的差值平方和:(dx² + dy² + dz²) - 连续 2 帧该值都 > 20(单位 m/s²²),才记为一次有效抖动
- 阈值不要硬编码:华为/小米省电模式下频率可能被压到 5Hz,可动态降级为 12–15
- 避免用
accelerationIncludingGravity—— 它含重力偏移,干扰 jerk 计算;优先用原始res.x等字段
H5 端完全不支持 uni.getAccelerometerFrequency 和 uni.onAccelerometerChange
uni.getAccelerometerFrequency、uni.startAccelerometer、uni.onAccelerometerChange 在 H5 环境下全部无效,连 success 回调都不会触发。这不是 bug,是规范限制——浏览器出于隐私考虑,默认禁用传感器 API,且需显式授权 + 用户手势激活。
实操建议:
- H5 必须改用标准 Web API:
window.addEventListener('devicemotion', handler) - 但前提是 WebView 已启用传感器透传:Cordova 需装
cordova-plugin-device-motion,Capacitor 需先调用Permissions.requestPermission('accelerometer') - 微信内嵌 H5?基本不可行——微信内置浏览器长期屏蔽
devicemotion,别浪费时间调试 - 真机调试务必用 iOS/Android 设备,模拟器和 Chrome DevTools 的 sensor 模拟器行为与真机差异极大
页面离开时必须手动 stop,否则 Android 8.0+ 后台会被系统强杀
在 App.vue 的 onLaunch 或页面 created 里全局启动加速度监听,Android 8.0+ 和多数国产 ROM 会静默拒绝,甚至触发 ANR。更危险的是:页面 onHide 或 onUnload 不调用 uni.stopAccelerometer,传感器持续运行会导致后台进程被系统回收,下次进页面监听直接失效。
实操建议:
- 只在当前页
onShow启动:uni.startAccelerometer({ success: () => { /* 开始监听 */ } }) - 在
onHide和onUnload两个钩子里都调用uni.stopAccelerometer() - 加防抖:一次摇一摇判定后,清空历史缓存,并主动停用监听 800ms,避免连续触发
- 别依赖
destroyed——App 端页面可能被复用,destroyed不一定触发
真机兼容性比逻辑更重要:同一套代码在 iPhone 15 和华为 Mate 60 上,传感器频率、省电策略、首次激活机制全都不一样。别迷信“设了阈值就万事大吉”,得把 fallback、提示、手动开关、降级策略全写进主流程里。


















