一聚教程网:一个值得你收藏的教程网站

热门教程

如何在uni-app实留在App端获取手机当前陀螺仪实时运动数据

时间:2026-06-24 09:50:02 编辑:袖梨 来源:一聚教程网

uni.startGyroscope在App端未实现,需通过Android Native.js或iOS原生插件获取原始陀螺仪角速度(rad/s);uni.onDeviceMotionChange返回的是延迟高、精度低的姿态角(°),非原始传感器数据。

uni-app 官方 API 在 App 端根本没实现 uni.startGyroscope,调用它不会报错、也不会触发回调——它就是个空函数。真要拿到陀螺仪的角速度(x/y/z rad/s),必须绕过官方封装,走原生通路。

为什么 uni.onDeviceMotionChange 不是你要的陀螺仪数据

这个 API 返回的是设备姿态角(alpha/beta/gamma),本质是浏览器级融合算法输出,不是原始陀螺仪传感器数据。它:

  • 延迟高(通常 30–60ms)、更新不稳,不适合体感游戏或 AR 精准追踪
  • 在部分 Android 平板和低端 iOS 设备上直接返回 undefined 或恒定值
  • 单位是度(°),无法做积分求角位移;而真实陀螺仪输出是角速率(rad/s),可积分、可滤波、可与加速度计做互补滤波
  • 依赖 WebView 的 DeviceMotionEvent,iOS Safari 自 14.5 起默认禁用,需用户手动授权(requestPermission),但 uni-app 无法透出该调用入口

Android 端用 Native.js 拿到原始 TYPE_GYROSCOPE 数据

Native.js 是最快验证路径,无需打包原生插件,适合调试和中小项目。关键点:

  • 必须等 plus.ready 触发后才能调用,onLoad 阶段 plus.android 还未就绪
  • 安卓 12+ 强制要求动态申请 BODY_SENSORS 权限,仅 ACCESS_FINE_LOCATION 不够
  • 先查设备是否支持:sensorManager.getDefaultSensor(3) 返回 null 就代表无硬件(常见于千元机、部分平板)
  • 注册监听器时,频率参数用 plus.android.implements 实现 SensorEventListener,别硬写字符串;推荐用 SENSOR_DELAY_GAME(约 20ms 间隔)

示例片段(简化版):

const main = plus.android.runtimeMainActivity();const Context = plus.android.importClass('android.content.Context');const SensorManager = plus.android.importClass('android.hardware.SensorManager');const sensorManager = main.getSystemService(Context.SENSOR_SERVICE);const gyro = sensorManager.getDefaultSensor(3); // TYPE_GYROSCOPE = 3if (!gyro) {  uni.showToast({ title: '设备不支持陀螺仪', icon: 'none' });  return;}const listener = plus.android.implements('android.hardware.SensorEventListener', {  onSensorChanged: function(event) {    const values = event.plusGetAttribute('values');    console.log('gyro raw:', values[0].toFixed(3), values[1].toFixed(3), values[2].toFixed(3)); // rad/s  },  onAccuracyChanged: function() {}});sensorManager.registerListener(listener, gyro, SensorManager.SENSOR_DELAY_GAME);

iOS 端必须用原生插件,Native.js 行不通

iOS 的 CMMotionManager 不允许 JS 直接反射调用,Native.js 在 iOS 上对传感器类完全不可用。你只能:

  • 新建 nativePlugins/gyro 插件目录,按 uni-app 插件规范导出 start() / stop() / onGyroscopeChange()
  • Info.plist 中必须添加 NSMotionUsageDescription 字符串,否则 CMMotionManager 初始化失败且无提示
  • 插件内部用 startGyroUpdates 启动,数据单位为 rad/s,注意线程:回调在后台线程,需用 dispatch_async 切回主线程再发 JS 事件
  • 不要试图在插件里做复杂滤波——JS 层处理更灵活;原生层只负责低延迟采集和转发

容易被忽略的三个硬伤

即使代码全对,以下问题仍会卡住你:

  • Android 后台限制:App 进入后台后,registerListener 会被系统静默取消,且多数厂商 ROM 不允许后台持续采样——必须在 onHide 主动 unregisterListener,并在 onShow 重建
  • 数据漂移:陀螺仪零偏随温度变化,静止时每秒偏移 0.01–0.05 rad/s,不做在线校准(如滑动窗口均值减法)会导致角度积分严重发散
  • 多页面共用风险:如果多个页面都初始化了监听器但没各自清理,unregisterListener 只能注销最后一次注册的实例,其余监听器继续跑,耗电且数据混乱

热门栏目