欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net

项目基于 RN 0.72.90 开发
在这里插入图片描述

📋 前言

在移动应用开发中,传感器数据获取是一项重要功能,特别是在运动健康、游戏交互、增强现实等场景中。react-native-sensors 是一个功能强大的传感器库,提供了加速度计、陀螺仪、磁力计、气压计等多种传感器的访问能力,支持 RxJS 风格的数据流处理,是获取设备传感器数据的理想选择。

🎯 库简介

基本信息

  • 库名称: react-native-sensors
  • 版本信息: 7.2.1 支持 RN 0.72 版本
  • 官方仓库: https://github.com/react-native-sensors/react-native-sensors
  • 鸿蒙仓库: https://atomgit.com/openharmony-sig/rntpc_react-native-sensors
  • 主要功能:
    • 📱 加速度计 (Accelerometer)
    • 🔄 陀螺仪 (Gyroscope)
    • 🧭 磁力计 (Magnetometer)
    • 🌡️ 气压计 (Barometer)
    • 🧭 方向传感器 (Orientation)
    • ⬇️ 重力传感器 (Gravity)
    • 📱 跨平台支持(iOS、Android、HarmonyOS)

为什么需要传感器库?

特性 原生方案 react-native-sensors
跨平台一致性 ⚠️ 需分别开发 ✅ 统一 API
数据流处理 ⚠️ 手动实现 ✅ RxJS 支持
传感器类型 ⚠️ 需封装 ✅ 开箱即用
数据过滤 ⚠️ 手动实现 ✅ 内置过滤
HarmonyOS 支持 ⚠️ 需适配 ✅ 完善适配

核心功能

功能 说明 HarmonyOS 支持
accelerometer 加速度计
gyroscope 陀螺仪
magnetometer 磁力计
barometer 气压计 ✅ (我的手机好像不支持)
orientation 方向传感器
gravity 重力传感器
setUpdateIntervalForType 设置更新频率
setLogLevelForType 设置日志级别

兼容性验证

在以下环境验证通过:

  • RNOH: 0.72.90; SDK: HarmonyOS-6.0.0 IDE: DevEco Studio 6.0.2; ROM: 6.0.0

📦 安装步骤

1. 安装依赖

# RN 0.72 版本
npm install @react-native-ohos/react-native-sensors@7.2.2-rc.2

# 或者使用 yarn
yarn add @react-native-ohos/react-native-sensors

2. 验证安装

安装完成后,检查 package.json 文件:

{
  "dependencies": {
    "@react-native-ohos/react-native-sensors": "^7.2.2-rc.2"
  }
}

3. 配置类型定义(TypeScript 项目)

如果遇到类型错误,需要在项目中添加类型定义文件。在 src/types 目录下创建 react-native-sensors.d.ts 文件:

declare module "react-native-sensors" {
  export interface SensorData {
    x: number;
    y: number;
    z: number;
    timestamp: string;
  }

  export interface BarometerData {
    pressure: number;
  }

  export interface OrientationData {
    qx: number;
    qy: number;
    qz: number;
    qw: number;
    pitch: number;
    roll: number;
    yaw: number;
    timestamp: string;
  }

  export interface Observable<T> {
    subscribe: (
      callback: (data: T) => void,
      error?: (error: any) => void
    ) => { unsubscribe: () => void };
    pipe?: (...operators: any[]) => Observable<T>;
  }

  export const accelerometer: Observable<SensorData>;
  export const gyroscope: Observable<SensorData>;
  export const magnetometer: Observable<SensorData>;
  export const barometer: Observable<BarometerData>;
  export const orientation: Observable<OrientationData>;
  export const gravity: Observable<SensorData>;

  export enum SensorTypes {
    accelerometer = "accelerometer",
    gyroscope = "gyroscope",
    magnetometer = "magnetometer",
    barometer = "barometer",
    orientation = "orientation",
    gravity = "gravity",
  }

  export function setUpdateIntervalForType(
    type: SensorTypes | string,
    interval: number
  ): void;

  export function setLogLevelForType(
    type: SensorTypes | string,
    level: number
  ): void;
}

⚠️ 重要:库 bug 修复

react-native-sensors 库本身存在 bug,原生端(HarmonyOS)发送的事件名称是 accelerometerClickgyroscopeClick 等,但 JS 端监听的事件名称是 AccelerometerGyroscope 等,两者不一致导致无法收到数据。

需要修改 node_modules/@react-native-ohos/react-native-sensors/src/sensors.js 文件中的 listenerKeys 映射:

// 修改前(错误)
const listenerKeys = new Map([
  ["accelerometer", "Accelerometer"],   // ❌ 与原生端不匹配
  ["gyroscope", "Gyroscope"],           // ❌ 与原生端不匹配
  ["magnetometer", "Magnetometer"],     // ❌ 与原生端不匹配
  ["barometer", "Barometer"],           // ❌ 与原生端不匹配
  ["orientation", "Orientation"],        // ❌ 与原生端不匹配
  ["gravity", "gravityClick"],          // ✅ 本来就匹配
]);

// 修改后(正确)
const listenerKeys = new Map([
  ["accelerometer", "accelerometerClick"],
  ["gyroscope", "gyroscopeClick"],
  ["magnetometer", "magnetometerClick"],
  ["barometer", "barometerClick"],
  ["orientation", "orientationClick"],
  ["gravity", "gravityClick"],
]);

🔧 HarmonyOS 平台配置 ⭐

1. 引入原生端代码

打开 harmony/entry/oh-package.json5,添加以下依赖:

"dependencies": {
  "@react-native-ohos/react-native-sensors": "file:../../node_modules/@react-native-ohos/react-native-sensors/harmony/sensors.har"
}

点击右上角的 sync 按钮,或者在终端执行:

cd entry
ohpm install

2. 配置 CMakeLists

打开 entry/src/main/cpp/CMakeLists.txt,添加:

set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")

# RNOH_BEGIN: manual_package_linking_1
add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-sensors/src/main/cpp" ./sensors)
# RNOH_END: manual_package_linking_1

# RNOH_BEGIN: manual_package_linking_2
target_link_libraries(rnoh_app PUBLIC rnoh_sensors)
# RNOH_END: manual_package_linking_2

3. 引入 SensorsPackage

打开 entry/src/main/cpp/PackageProvider.cpp,添加:

#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
+ #include "SensorsPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
      std::make_shared<RNOHGeneratedPackage>(ctx),
      + std::make_shared<SensorsPackage>(ctx)
    };
}

打开 entry/src/main/ets/RNPackagesFactory.ts,添加:

+ import { SensorsPackage } from '@react-native-ohos/react-native-sensors/harmony/sensors/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new SamplePackage(ctx),
   +  new SensorsPackage(ctx)
  ];
}

4. 配置权限

entry/src/main/module.json5 中添加传感器权限:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.ACCELEROMETER",
      },
      {
        "name": "ohos.permission.GYROSCOPE",
      }
    ]
  }
}

📖 API 详解

accelerometer - 加速度计

获取设备的加速度数据,包括 x、y、z 三个轴的加速度值。

类型Observable<{x: number, y: number, z: number, timestamp: string}>

使用场景

  • 摇一摇功能
  • 计步器
  • 运动检测
  • 设备倾斜检测
import { accelerometer } from "react-native-sensors";

const subscription = accelerometer.subscribe(({ x, y, z, timestamp }) => {
  console.log("加速度数据", { x, y, z, timestamp });
});

subscription.unsubscribe();

gyroscope - 陀螺仪

获取设备的角速度数据,包括 x、y、z 三个轴的旋转速度。

类型Observable<{x: number, y: number, z: number, timestamp: string}>

使用场景

  • 设备旋转检测
  • 游戏控制
  • VR/AR 应用
  • 姿态估计
import { gyroscope } from "react-native-sensors";

const subscription = gyroscope.subscribe(({ x, y, z, timestamp }) => {
  console.log("陀螺仪数据", { x, y, z, timestamp });
});

magnetometer - 磁力计

获取设备的磁场数据,包括 x、y、z 三个轴的磁场强度。

类型Observable<{x: number, y: number, z: number, timestamp: string}>

使用场景

  • 电子罗盘
  • 金属检测
  • 方向导航
  • 地磁定位
import { magnetometer } from "react-native-sensors";

const subscription = magnetometer.subscribe(({ x, y, z, timestamp }) => {
  console.log("磁力计数据", { x, y, z, timestamp });
});

barometer - 气压计(我在我的手机上测试不支持)

获取设备的气压数据。

类型Observable<{pressure: number}>

使用场景

  • 海拔测量
  • 天气预测
  • 室内定位
  • 楼层检测
import { barometer } from "react-native-sensors";

const subscription = barometer.subscribe(({ pressure }) => {
  console.log("气压数据", { pressure });
});

orientation - 方向传感器

获取设备的方向数据,包括四元数和欧拉角。

类型Observable<{qx: number, qy: number, qz: number, qw: number, pitch: number, roll: number, yaw: number, timestamp: string}>

使用场景

  • 屏幕旋转
  • 方向指示
  • 姿态控制
  • 导航应用
import { orientation } from "react-native-sensors";

const subscription = orientation.subscribe(({ pitch, roll, yaw, timestamp }) => {
  console.log("方向数据", { pitch, roll, yaw, timestamp });
});

gravity - 重力传感器

获取设备的重力数据,不包括线性加速度。

类型Observable<{x: number, y: number, z: number, timestamp: string}>

使用场景

  • 重力感应
  • 屏幕旋转
  • 设备姿态
  • 游戏控制
import { gravity } from "react-native-sensors";

const subscription = gravity.subscribe(({ x, y, z, timestamp }) => {
  console.log("重力数据", { x, y, z, timestamp });
});

setUpdateIntervalForType - 设置更新频率

设置传感器的数据更新频率。

类型(type: SensorTypes, interval: number) => void

参数

  • type: 传感器类型
  • interval: 更新间隔(毫秒)
import { setUpdateIntervalForType, SensorTypes } from "react-native-sensors";

setUpdateIntervalForType(SensorTypes.accelerometer, 100);
setUpdateIntervalForType(SensorTypes.gyroscope, 50);

📋 完整示例

在这里插入图片描述

import React, { useState, useEffect } from "react";
import {
  View,
  Text,
  StyleSheet,
  ScrollView,
  TouchableOpacity,
  SafeAreaView,
  StatusBar,
  Alert,
} from "react-native";
import {
  accelerometer,
  gyroscope,
  magnetometer,
  barometer,
  orientation,
  gravity,
  setUpdateIntervalForType,
  SensorTypes,
} from "react-native-sensors";

type SensorData = {
  x?: number;
  y?: number;
  z?: number;
  pressure?: number;
  pitch?: number;
  roll?: number;
  yaw?: number;
  timestamp?: string;
};

type SensorType = "accelerometer" | "gyroscope" | "magnetometer" | "barometer" | "orientation" | "gravity";

const App: React.FC = () => {
  const [activeSensor, setActiveSensor] = useState<SensorType>("accelerometer");
  const [sensorData, setSensorData] = useState<SensorData>({});
  const [isListening, setIsListening] = useState(false);
  const [subscription, setSubscription] = useState<any>(null);

  useEffect(() => {
    return () => {
      if (subscription) {
        subscription.unsubscribe();
      }
    };
  }, [subscription]);

  const startListening = () => {
    if (subscription) {
      subscription.unsubscribe();
    }

    setUpdateIntervalForType(SensorTypes[activeSensor], 100);

    let newSubscription: any;

    switch (activeSensor) {
      case "accelerometer":
        newSubscription = accelerometer.subscribe((data) => {
          setSensorData(data);
        });
        break;
      case "gyroscope":
        newSubscription = gyroscope.subscribe((data) => {
          setSensorData(data);
        });
        break;
      case "magnetometer":
        newSubscription = magnetometer.subscribe((data) => {
          setSensorData(data);
        });
        break;
      case "barometer":
        newSubscription = barometer.subscribe((data) => {
          setSensorData(data);
        });
        break;
      case "orientation":
        newSubscription = orientation.subscribe((data) => {
          setSensorData({
            pitch: data.pitch,
            roll: data.roll,
            yaw: data.yaw,
            timestamp: data.timestamp,
          });
        });
        break;
      case "gravity":
        newSubscription = gravity.subscribe((data) => {
          setSensorData(data);
        });
        break;
    }

    setSubscription(newSubscription);
    setIsListening(true);
  };

  const stopListening = () => {
    if (subscription) {
      subscription.unsubscribe();
      setSubscription(null);
    }
    setIsListening(false);
    setSensorData({});
  };

  const handleSensorChange = (sensor: SensorType) => {
    if (isListening) {
      stopListening();
    }
    setActiveSensor(sensor);
    setSensorData({});
  };

  const renderSensorButton = (type: SensorType, label: string) => (
    <TouchableOpacity
      key={type}
      style={[
        styles.sensorButton,
        activeSensor === type && styles.sensorButtonActive,
      ]}
      onPress={() => handleSensorChange(type)}
    >
      <Text
        style={[
          styles.sensorButtonText,
          activeSensor === type && styles.sensorButtonTextActive,
        ]}
      >
        {label}
      </Text>
    </TouchableOpacity>
  );

  const renderDataValue = (label: string, value?: number) => {
    if (value === undefined) return null;
    return (
      <View style={styles.dataRow}>
        <Text style={styles.dataLabel}>{label}</Text>
        <Text style={styles.dataValue}>{value.toFixed(4)}</Text>
      </View>
    );
  };

  const getSensorDescription = () => {
    switch (activeSensor) {
      case "accelerometer":
        return "测量设备的线性加速度(包括重力),单位:m/s²";
      case "gyroscope":
        return "测量设备的角速度,单位:rad/s";
      case "magnetometer":
        return "测量设备周围的磁场强度,单位:μT";
      case "barometer":
        return "测量大气压力,单位:hPa";
      case "orientation":
        return "测量设备的方向角度,单位:度";
      case "gravity":
        return "测量重力加速度(不包括线性加速度),单位:m/s²";
    }
  };

  return (
    <SafeAreaView style={styles.container}>
      <StatusBar barStyle="dark-content" backgroundColor="#FFFFFF" />
      <View style={styles.header}>
        <Text style={styles.headerTitle}>传感器示例</Text>
        <TouchableOpacity
          style={[styles.controlButton, isListening && styles.stopButton]}
          onPress={isListening ? stopListening : startListening}
        >
          <Text style={styles.controlButtonText}>
            {isListening ? "停止" : "开始"}
          </Text>
        </TouchableOpacity>
      </View>

      <View style={styles.sensorList}>
        {renderSensorButton("accelerometer", "加速度计")}
        {renderSensorButton("gyroscope", "陀螺仪")}
        {renderSensorButton("magnetometer", "磁力计")}
        {renderSensorButton("barometer", "气压计")}
        {renderSensorButton("orientation", "方向")}
        {renderSensorButton("gravity", "重力")}
      </View>

      <ScrollView style={styles.content}>
        <View style={styles.infoCard}>
          <Text style={styles.infoTitle}>当前传感器</Text>
          <Text style={styles.infoValue}>
            {activeSensor === "accelerometer" && "加速度计"}
            {activeSensor === "gyroscope" && "陀螺仪"}
            {activeSensor === "magnetometer" && "磁力计"}
            {activeSensor === "barometer" && "气压计"}
            {activeSensor === "orientation" && "方向传感器"}
            {activeSensor === "gravity" && "重力传感器"}
          </Text>
          <Text style={styles.infoDescription}>{getSensorDescription()}</Text>
        </View>

        <View style={styles.dataCard}>
          <Text style={styles.dataTitle}>实时数据</Text>
          {!isListening && (
            <Text style={styles.noDataText}>点击"开始"按钮获取传感器数据</Text>
          )}
          {isListening && Object.keys(sensorData).length === 0 && (
            <Text style={styles.noDataText}>正在获取数据...</Text>
          )}
          {isListening && Object.keys(sensorData).length > 0 && (
            <>
              {renderDataValue("X 轴", sensorData.x)}
              {renderDataValue("Y 轴", sensorData.y)}
              {renderDataValue("Z 轴", sensorData.z)}
              {renderDataValue("气压", sensorData.pressure)}
              {renderDataValue("俯仰角 (Pitch)", sensorData.pitch)}
              {renderDataValue("翻滚角 (Roll)", sensorData.roll)}
              {renderDataValue("偏航角 (Yaw)", sensorData.yaw)}
              {sensorData.timestamp && (
                <View style={styles.dataRow}>
                  <Text style={styles.dataLabel}>时间戳</Text>
                  <Text style={styles.dataValue}>{sensorData.timestamp}</Text>
                </View>
              )}
            </>
          )}
        </View>

        <View style={styles.tipsCard}>
          <Text style={styles.tipsTitle}>使用提示</Text>
          <Text style={styles.tipsText}>• 加速度计:可用于摇一摇、计步等功能</Text>
          <Text style={styles.tipsText}>• 陀螺仪:可用于游戏控制、VR/AR 应用</Text>
          <Text style={styles.tipsText}>• 磁力计:可用于电子罗盘、方向导航</Text>
          <Text style={styles.tipsText}>• 气压计:可用于海拔测量、楼层检测</Text>
          <Text style={styles.tipsText}>• 方向传感器:可用于屏幕旋转、姿态控制</Text>
          <Text style={styles.tipsText}>• 重力传感器:可用于重力感应、游戏控制</Text>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#F5F5F5",
  },
  header: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-between",
    padding: 16,
    backgroundColor: "#FFFFFF",
    borderBottomWidth: 1,
    borderBottomColor: "#E5E5EA",
  },
  headerTitle: {
    fontSize: 20,
    fontWeight: "700",
    color: "#333333",
  },
  controlButton: {
    backgroundColor: "#007AFF",
    paddingHorizontal: 20,
    paddingVertical: 10,
    borderRadius: 8,
  },
  stopButton: {
    backgroundColor: "#FF3B30",
  },
  controlButtonText: {
    color: "#FFFFFF",
    fontSize: 16,
    fontWeight: "600",
  },
  sensorList: {
    flexDirection: "row",
    flexWrap: "wrap",
    backgroundColor: "#FFFFFF",
    paddingHorizontal: 16,
    paddingVertical: 12,
    gap: 8,
  },
  sensorButton: {
    paddingHorizontal: 16,
    paddingVertical: 8,
    backgroundColor: "#F0F0F0",
    borderRadius: 20,
  },
  sensorButtonActive: {
    backgroundColor: "#007AFF",
  },
  sensorButtonText: {
    fontSize: 14,
    color: "#666666",
    fontWeight: "500",
  },
  sensorButtonTextActive: {
    color: "#FFFFFF",
  },
  content: {
    flex: 1,
    padding: 16,
  },
  infoCard: {
    backgroundColor: "#FFFFFF",
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
  },
  infoTitle: {
    fontSize: 14,
    color: "#999999",
    marginBottom: 8,
  },
  infoValue: {
    fontSize: 24,
    fontWeight: "700",
    color: "#333333",
    marginBottom: 8,
  },
  infoDescription: {
    fontSize: 14,
    color: "#666666",
    lineHeight: 20,
  },
  dataCard: {
    backgroundColor: "#FFFFFF",
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
  },
  dataTitle: {
    fontSize: 18,
    fontWeight: "600",
    color: "#333333",
    marginBottom: 16,
  },
  noDataText: {
    fontSize: 14,
    color: "#999999",
    textAlign: "center",
    paddingVertical: 20,
  },
  dataRow: {
    flexDirection: "row",
    justifyContent: "space-between",
    alignItems: "center",
    paddingVertical: 12,
    borderBottomWidth: 1,
    borderBottomColor: "#F0F0F0",
  },
  dataLabel: {
    fontSize: 16,
    color: "#666666",
  },
  dataValue: {
    fontSize: 16,
    fontWeight: "600",
    color: "#007AFF",
    fontFamily: "monospace",
  },
  tipsCard: {
    backgroundColor: "#FFFFFF",
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
  },
  tipsTitle: {
    fontSize: 18,
    fontWeight: "600",
    color: "#333333",
    marginBottom: 12,
  },
  tipsText: {
    fontSize: 14,
    color: "#666666",
    lineHeight: 22,
    marginBottom: 4,
  },
});

export default App;

⚠️ 注意事项

权限要求

使用传感器功能需要在 module.json5 中配置相应权限:

传感器 所需权限
加速度计 ohos.permission.ACCELEROMETER
陀螺仪 ohos.permission.GYROSCOPE
磁力计 无需特殊权限
气压计 无需特殊权限
方向传感器 无需特殊权限
重力传感器 无需特殊权限

使用建议

  1. 及时取消订阅: 传感器数据是持续流式的,在不使用时应及时调用 unsubscribe() 取消订阅,避免资源浪费
  2. 合理设置更新频率: 根据实际需求设置合适的更新频率,过高的频率会增加耗电
  3. 数据过滤: 使用 RxJS 的 pipefilter 对数据进行过滤,减少无效数据处理
  4. 错误处理: 添加错误处理逻辑,处理传感器不可用的情况

常见问题

Q: 传感器数据为 0 或不变化?

A: 检查是否正确配置了权限,部分传感器需要在 module.json5 中声明权限才能正常工作。

Q: 应用耗电严重?

A: 检查是否在不使用时及时取消了传感器订阅,建议在组件卸载时取消订阅。

Q: 数据更新频率不符合预期?

A: 使用 setUpdateIntervalForType 设置更新频率,但实际频率可能因设备性能而异。

Q: 某些传感器不可用?

A: 部分设备可能不支持某些传感器,建议在使用前检查传感器是否可用。

性能优化

  1. 按需订阅: 只在需要时订阅传感器数据
  2. 降低频率: 根据实际需求降低更新频率
  3. 数据过滤: 使用 RxJS 操作符过滤数据
  4. 及时清理: 组件卸载时取消所有订阅

📚 参考资源

  • 官方文档: https://github.com/react-native-sensors/react-native-sensors
  • 鸿蒙适配仓库: https://atomgit.com/openharmony-sig/rntpc_react-native-sensors
  • 问题反馈: https://github.com/react-native-oh-library/react-native-sensors/issues

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐