iOS端Safari/Chrome中devicemotion事件无法正常工作的问题求助
iOS Safari/Chrome中devicemotion事件无法触发的解决方案
问题原因
iOS 13+ 对设备运动类事件(包括devicemotion)增加了严格的权限限制:
- 必须通过用户主动交互(比如点击、触摸)触发权限请求
- 事件监听必须在权限授予后才能正常注册
- iOS上的Chrome基于WebKit内核,继承了相同的权限规则
你的代码在onMount中直接绑定事件,但此时没有经过用户交互,iOS会默认阻止事件触发。
修复步骤
- 添加用户交互入口(比如一个"开始检测"按钮)
- 点击时调用
DeviceMotionEvent.requestPermission()获取权限 - 权限授予后再注册
devicemotion事件监听
修改后的Svelte代码
<script context="module"> // @ts-nocheck import Device from 'svelte-device-info' </script> <script> import { onMount } from "svelte"; import { browser } from '$app/environment'; let tempX = 0, tempY = 0, tempZ = 0 let distX = 0, distY = 0, distZ = 0 let avgXYZ = 0, total = 0 let startShake = false let mobile = false let ready = false let isSafari = false let permissionGranted = false function handleAcl(event) { distX = event.accelerationIncludingGravity.x - tempX distY = event.accelerationIncludingGravity.y - tempY distZ = event.accelerationIncludingGravity.z - tempZ avgXYZ = (Math.abs(distX)+Math.abs(distY)+Math.abs(distZ))/3 if (avgXYZ > 1) { total = total + avgXYZ } tempX = event.accelerationIncludingGravity.x tempY = event.accelerationIncludingGravity.y tempZ = event.accelerationIncludingGravity.z } async function requestMotionPermission() { if (browser && typeof DeviceMotionEvent.requestPermission === 'function') { const permission = await DeviceMotionEvent.requestPermission() if (permission === 'granted') { permissionGranted = true startShake = true } } else { // 非iOS环境直接开启 permissionGranted = true startShake = true } } onMount(() => { mobile = Device.isMobile ready = true if (browser) { let ua = window.navigator.userAgent.toLowerCase(); if (ua.indexOf('safari') != -1) { if (ua.indexOf('chrome') > -1) { isSafari = false } else { isSafari = true } } } }) </script> <svelte:window on:devicemotion={startShake && permissionGranted ? handleAcl : null}></svelte:window> <svelte:head> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="HandheldFriendly" content="true" /> </svelte:head> <section> {#if ready} {#if mobile} <h1>Safari Debugger</h1> <h3>Your browser is {isSafari ? 'Safari' : 'not Safari'}</h3> <br> {#if !permissionGranted} <button on:click={requestMotionPermission} style="padding: 1rem 2rem; font-size: 1.2rem; cursor: pointer;"> 允许设备运动检测 </button> {:else} <p>X: <strong>{distX.toFixed(2)}</strong></p> <p>Y: <strong>{distY.toFixed(2)}</strong></p> <p>Z: <strong>{distZ.toFixed(2)}</strong></p> <br> <p>Average: {avgXYZ.toFixed(2)}</p> <div style:width="{avgXYZ*10}px" class="bar"></div> {/if} {:else} <h1>Play this game on your mobile phone</h1> {/if} {/if} </section> <style> :global(body) { margin: 0; padding: 0; overflow: hidden; background-color: rgb(22, 18, 48); } h1 { font-size:2rem; margin: 0; font-family: monospace; text-align: center; color:whitesmoke; } h3 { font-size:1.5rem; margin: 0; font-family: monospace; text-align: center; color:whitesmoke; } p { margin: 0; font-size:1.2rem; color:whitesmoke; font-family: sans-serif; } .bar { margin-top: 2rem; background-color: orange; height:50px; } section { width:100%; height:100vh; display:flex; align-items: center; justify-content: center; flex-direction: column; gap: 1rem; } button { background-color: #4CAF50; color: white; border: none; border-radius: 4px; } </style>
关键改动说明
- 新增
permissionGranted状态跟踪权限是否授予 - 添加
requestMotionPermission函数,处理iOS权限请求逻辑 - 增加用户触发的按钮,只有点击后才请求权限并开启事件监听
- 修改
svelte:window的事件绑定条件,确保只有权限授予后才注册监听
内容的提问来源于stack exchange,提问作者louislugas
相关产品推荐
相关产品推荐

