You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS端Safari/Chrome中devicemotion事件无法正常工作的问题求助

iOS Safari/Chrome中devicemotion事件无法触发的解决方案

问题原因

iOS 13+ 对设备运动类事件(包括devicemotion)增加了严格的权限限制:

  • 必须通过用户主动交互(比如点击、触摸)触发权限请求
  • 事件监听必须在权限授予后才能正常注册
  • iOS上的Chrome基于WebKit内核,继承了相同的权限规则

你的代码在onMount中直接绑定事件,但此时没有经过用户交互,iOS会默认阻止事件触发。

修复步骤

  1. 添加用户交互入口(比如一个"开始检测"按钮)
  2. 点击时调用DeviceMotionEvent.requestPermission()获取权限
  3. 权限授予后再注册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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 16:34:57