必须先调用 uni.startaccelerometer() 才能触发 uni.onaccelerometerchange 回调,ios 需配置「运动与健身」权限,android 宜在 onshow 或用户交互后启动;抖动判定应基于加速度突变(jerk),缓存4帧计算差值平方和,连续2帧超阈值15–25且累计3次才触发;须用同一函数引用配对注册/注销,页面 onhide/onunload 时调用 uni.offaccelerometerchange 防内存泄漏。

必须调用 uni.startAccelerometer() 启动,否则 uni.onAccelerometerChange 永远不会触发回调——这不是可选项,是硬性前置条件。
为什么 uni.onAccelerometerChange 完全没反应?
真机调试时监听函数一动不动,90% 是卡在启动环节:
-
uni.startAccelerometer()根本没调用,只写了uni.onAccelerometerChange—— 这就像装了监听器却没开麦克风 - iOS 真机未在
manifest.json → App SDK 配置中勾选「运动与健身」权限,会静默失败,无任何错误提示 - Android 在
onLaunch或页面刚加载时就调uni.startAccelerometer(),部分系统(MIUI/HarmonyOS)会拦截;应改在onShow或用户点击按钮后触发
怎么写判定逻辑才不误触、不漏判?
单看 Math.abs(res.x) > 30 这类写法,在 iPhone 15 Pro 和华为 Mate 60 上实测误触率超 70%。真实摇一摇是加速度突变(jerk),不是“动得大”,而是“动得快且方向突变”:
- 缓存最近 4 帧的
x/y/z,用acc = Math.sqrt(x*x + y*y + z*z)算合加速度模长 - 每帧计算与前一帧的差值平方和:
dx*dx + dy*dy + dz*dz(避免开方,省性能) - 仅当该值连续 2 帧 > 20 才记为一次有效抖动;累计 3 次抖动再触发,防毛刺
- 阈值不是固定值:不同机型建议起始设为 15–25,真机调试微调
页面跳走或切后台后还在响?这是内存泄漏
uni.onAccelerometerChange 是全局注册,不手动注销会在后台持续执行,轻则报 Cannot read property 'play' of null,重则耗电发热:
- 必须在
onHide或onUnload中配对调用:uni.offAccelerometerChange(handle) - 回调函数必须是同一引用,推荐写法:
const handle = res => { /* ... */ };→uni.onAccelerometerChange(handle)→uni.offAccelerometerChange(handle) - 别依赖
setTimeout清理定时器——摇动持续时间不可控,固定锁定期(如 1500ms)比动态重置更稳
最容易被忽略的是:iOS WKWebView 下,页面刚加载就调 uni.startAccelerometer() 可能因 JSBridge 未就绪而静默失败;必须等用户有交互(比如点个按钮)后再启动,否则整条链路就断了。











