ios如何调用html5摇一摇功能_ios调用html5摇一摇法【技巧】

不能——iOS Safari 必须通过用户可信手势(如 touchstart)调用 DeviceMotionEvent.requestPermission() 后才能监听 devicemotion,且 WKWebView 中需原生配合,摇一摇检测需基于 accelerationIncludingGravity 的向量模长变化率双阈值判定。

iOS Safari 能否直接触发 DeviceMotion 事件?

不能——除非用户完成一次「可信的用户手势」(如点击、触摸、键盘输入)。这是 iOS 13+ 的硬性限制,不是 bug,是 Safari 的安全策略。直接在 window.onloadsetTimeout 里监听 d

eviceorientationdevicemotion,iOS 会静默拒绝启用传感器,event.acceleration.x 等字段始终为 null

必须用「用户点击」解锁传感器权限

只有在用户主动触发的事件回调中,才能首次调用 DeviceMotionEvent.requestPermission()(iOS 13+)或直接开始监听(iOS 12 及更早需手动唤醒)。否则摇一摇永远没响应。

  • 必须绑定在 buttondiv 等可点击元素的 onclickontouchstart 上(推荐后者,避免点击延迟)
  • 调用后需显式等待 Promise resolve,再启动监听:
    document.getElementById('shake-btn').ontouchstart = async () => {
      try {
        await DeviceMotionEvent.requestPermission();
        window.addEventListener('devicemotion', handleShake);
      } catch (e) {
        console.warn('Permission denied:', e);
      }
    };
  • ⚠️ 注意:Safari 不支持在 iframe 中请求权限(尤其跨域 iframe),必须在顶层页面执行

如何可靠检测「摇一摇」动作?

别依赖单次加速度峰值——iOS 设备休眠时传感器数据抖动大,且不同机型 baseline 不同。应计算加速度向量模长变化率,并设双阈值过滤噪声。

  • event.accelerationIncludingGravity(非 acceleration),它包含重力分量,更稳定
  • 每帧计算合加速度:const acc = Math.sqrt(x*x + y*y + z*z)
  • 只在连续 3 帧内 acc > 25(单位 m/s²)且与前一稳定值差值 > 12 时才判定为有效摇动
  • 摇动后需重置参考基线,避免连续误触发

WKWebView 中无法调用 requestPermission 怎么办?

WKWebView 默认禁用传感器 API,即使网页里写了 requestPermission 也会抛 SecurityError。必须由原生层显式开启:

  • iOS 14.5+:在 WKWebViewConfiguration 中设置 mediaTypesRequiringUserActionForPlayback = [] 不够,还需 configuration.preferences.setValue(true, forKey: "allowAirPlayForMediaPlayback") ——但这不解决传感器问题
  • 真正解法:原生注入 WKScriptMessageHandler,当 JS 触发「准备摇一摇」时,OC/Swift 调用 [self.webView evaluateJavaScript:@"..." completionHandler:nil] 并提前配置好 configuration.usesWebProcessPool = NO(不推荐)或改用 SFSafariViewController
  • 更实际的方案:放弃 WKWebView 内摇一摇,改用原生 CMMotionManager 检测,JS 通过 webkit.messageHandlers.xxx.postMessage() 接收事件
iOS 的摇一摇不是“写个监听就完事”,它卡在权限链、上下文、WebView 隔离三层关卡上。最易忽略的是:**用户第一次触摸后,必须等 Promise 完成才能加监听;而第二次及以后的摇动,不需要重复请求权限——但很多人每次摇都重试 requestPermission,导致频繁报错**。