Flutter 3.47 鸿蒙三方库适配实战:从 0 到 1 处理 environment_sensors
Flutter 3.47 鸿蒙三方库适配实战:从 0 到 1 处理 environment_sensors
环境传感器在智能家居、健康监测、户外工具类应用里很常见:读室温、湿度、气压、环境光。environment_sensors 把安卓的 SensorManager 封装成四条 Stream<double>,用起来很顺手。
但这个库的鸿蒙适配有一个非常隐蔽的坑:Dart 侧写死的是安卓的传感器 type 常量,而鸿蒙的 SensorId 数值完全不同。如果直接拿数字去订阅,会把「温度」订成「湿度」、把「气压」订成「计步」——不报错,但数据全是错的。
本文以 environment_sensors 0.3.0 为例,记录这个坑的成因与解法,并在 HarmonyOS API 26 真机上验证到真实光照数据流。
适配仓库: oh-flutter/environment_sensors
适配分支: feat/ohos_environment_sensors_0.3.0
适配 TAG: 0.3.0-ohos-1.0.0-beta.1
一、先看最终效果

图 1:HarmonyOS API 26 真机启动自检台。四种传感器可用性一并列出:环境温度「不可用」、相对湿度「不可用」、环境光「可用,未订阅」、气压「不可用」;下方日志显示 getSensorAvailable(Light) → true,其余三项为 false。

图 2:点击「环境光 · Light」后,按钮文字变成「订阅中(7 条,最新 646.00)」——7 条真实光照数据,最新一条 646.00 lux。
| 验证点 | 实测结果 | 证据 |
|---|---|---|
| Flutter OH 3.47 工程构建 | 通过 | entry-default-signed.hap |
| 安装、启动(真机) | 通过 | 图 1 |
isSensorAvailable(13) 环境温度 | false(设备无此传感器) | 图 1 |
isSensorAvailable(12) 相对湿度 | false | 图 1 |
isSensorAvailable(5) 环境光 | true | 图 1 |
isSensorAvailable(6) 气压 | false | 图 1 |
| 环境光事件流 | 7 条数据,最新 646.00 lux | 图 2 |
二、这个库原来是怎么工作的
environment_sensors 用一条方法通道 + 四条事件通道:
Dart EnvironmentSensors
-> MethodChannel('environment_sensors/method')
isSensorAvailable(<安卓 type id>) // 位置参数,不是 map
-> EventChannel('environment_sensors/temperature') -> Stream<double>
-> EventChannel('environment_sensors/humidity') -> Stream<double>
-> EventChannel('environment_sensors/light') -> Stream<double>
-> EventChannel('environment_sensors/pressure') -> Stream<double>
关键在 isSensorAvailable 的参数:Dart 侧传的是安卓的 Sensor.TYPE_* 常量,而且是裸数字(位置参数),不是命名参数:
| 传感器 | 安卓 Sensor.TYPE_* 常量值 |
|---|---|
| 环境温度 | 13 |
| 相对湿度 | 12 |
| 环境光 | 5 |
| 气压 | 6 |
三、实际环境
Flutter 鸿蒙环境搭建不在本文重复展开,直接参考 Flutter OH 环境搭建指南。
| 组件 | 版本 |
|---|---|
| Flutter OH | 3.47.4-ohos-1.0.4 |
| Dart | 3.13.3 |
| DevEco Studio | 26.0.0 Release |
| HarmonyOS SDK | API 26 |
| 测试设备 | 华为真机 6UMBB26319007180,HarmonyOS 7.0.0.105(API 26) |
| 目标库 | environment_sensors 0.3.0 |
flutter --version
hdc list targets
四、确认上游版本并同步到 AtomGit
上游包地址是 https://github.com/nhandrew/environment_sensors,版本 0.3.0,使用 MIT License。适配前我在 AtomGit 目标组织中搜索了同名库,没有找到可以直接使用的 OHOS 实现。
git clone https://atomgit.com/oh-flutter/environment_sensors.git
cd environment_sensors
git switch feat/ohos_environment_sensors_0.3.0
git log --oneline -5
五、创建适配分支并检查工程结构
git switch -c feat/ohos_environment_sensors_0.3.0
关键目录如下:
environment_sensors/
├── lib/environment_sensors.dart # 上游 Dart API,一行未改
├── ohos/
│ ├── index.ets # OHOS 插件导出入口
│ └── src/main/ets/components/plugin/
│ └── EnvironmentSensorsPlugin.ets # 1 方法 + 4 事件通道实现
├── example/lib/main.dart # 真机验证自检台
├── example/ohos/ # Flutter OH 宿主工程
├── pubspec.yaml # 声明 ohos 平台
└── README.OpenHarmony_CN.md # 鸿蒙适配说明
六、适配过程:传感器 ID 必须翻译
6.1 核心坑:安卓常量与鸿蒙 SensorId 数值不同
这是整个适配最关键的一处。看这张对照表:
| 传感器 | 安卓常量值 | 鸿蒙 SensorId | 鸿蒙实际数值 |
|---|---|---|---|
| 环境温度 | 13 | AMBIENT_TEMPERATURE | 260 |
| 相对湿度 | 12 | HUMIDITY | 13 |
| 环境光 | 5 | AMBIENT_LIGHT | 5 |
| 气压 | 6 | BAROMETER | 8 |
注意「13」这个数字在两边含义完全相反:安卓的 13 是环境温度,鸿蒙的 13 是相对湿度。如果直接把安卓的 13 传给 sensor.on(13, ...),你会订到湿度传感器,而代码不会报任何错——拿到的数据是湿度,却当成温度用。
同样,安卓的 6 是气压,鸿蒙的 6 是计步(PEDOMETER),订错的话会拿到步数。
所以必须建一张翻译表:
const ANDROID_TO_OHOS_SENSOR: Map<number, sensor.SensorId> = new Map();
function registerSensorIds(): void {
ANDROID_TO_OHOS_SENSOR.set(13, sensor.SensorId.AMBIENT_TEMPERATURE); // 安卓13 → 鸿蒙260
ANDROID_TO_OHOS_SENSOR.set(12, sensor.SensorId.HUMIDITY); // 安卓12 → 鸿蒙13
ANDROID_TO_OHOS_SENSOR.set(5, sensor.SensorId.AMBIENT_LIGHT); // 安卓5 → 鸿蒙5(恰好相同)
ANDROID_TO_OHOS_SENSOR.set(6, sensor.SensorId.BAROMETER); // 安卓6 → 鸿蒙8
}
只有环境光(5)两边恰好相同,其余三个全部错位。
6.2 sensor.on 的每个重载都要求字面量枚举
这是第二个坑,属于 TypeScript 层面的限制:
// ❌ 这样写会报错:No overload matches this call
const id: sensor.SensorId = sensor.SensorId.AMBIENT_LIGHT;
sensor.on(id, callback);
// ✅ 必须写死字面量
sensor.on(sensor.SensorId.AMBIENT_LIGHT, callback);
因为 sensor.on 的每个传感器重载签名不同(回调参数类型不一样:LightResponse / HumidityResponse / BarometerResponse…),传变量会让类型推断失效。所以实现里四个传感器各自在闭包里写死字面量:
addChannel(LIGHT_CHANNEL,
(emit: (value: number) => void): void => {
sensor.on(sensor.SensorId.AMBIENT_LIGHT,
(response: sensor.LightResponse): void => emit(response.intensity));
},
(): void => {
sensor.off(sensor.SensorId.AMBIENT_LIGHT);
});
6.3 isSensorAvailable 的参数是位置参数
上游传的是裸数字,不是 {type: n}。所以要兼容两种形态:
private static readTypeArgument(call: MethodCall): number {
const raw: Object | null = call.args;
if (typeof raw === 'number') {
return raw as number; // 上游实际用法:裸数字
}
if (raw !== null && raw !== undefined) {
const map = raw as Record<string, Object>;
const type = map['type'];
if (typeof type === 'number') {
return type as number; // 兼容 {type: n} 形态
}
}
return -1;
}
6.4 可用性判断用 getSingleSensorSync
private static checkAvailable(androidType: number): boolean {
const id = ANDROID_TO_OHOS_SENSOR.get(androidType);
if (id === undefined) {
return false;
}
try {
// 传感器不存在时会抛异常
sensor.getSingleSensorSync(id);
return true;
} catch (error) {
return false;
}
}
| 方法 | OpenHarmony 实现 |
|---|---|
isSensorAvailable(安卓type) | 翻译成鸿蒙 SensorId → getSingleSensorSync 探测 |
| 温度流 | sensor.on(AMBIENT_TEMPERATURE) → response.temperature |
| 湿度流 | sensor.on(HUMIDITY) → response.humidity |
| 光照流 | sensor.on(AMBIENT_LIGHT) → response.intensity |
| 气压流 | sensor.on(BAROMETER) → response.pressure |
七、构建配置与签名
同批库共有的两个坑。
7.1 compatibleSdkVersion 必须写 "26.0.0"
00306004 Specification Limit Violation
The project's compatibleSdkVersion: 18 cannot be lower than
the minimum compatible version 24 required by the dependencies: @ohos/flutter_ohos.
正确写法是不带括号的 "26.0.0"。
7.2 签名证书绑定了 bundleName
00303074 Configuration Error
The bundleName in app.json5/hvigorfile.ts does not match the bundleName
in the generated SigningConfigs.
本库示例原本是 com.julow.environment_sensors_example,改成证书对应的 com.example.flutter_oh_demo 后通过。
八、通过 AtomGit 引入适配版
dependencies:
environment_sensors:
git:
url: https://atomgit.com/oh-flutter/environment_sensors.git
ref: 0.3.0-ohos-1.0.0-beta.1
flutter pub get
本库读取环境传感器不需要申请权限——环境光、温湿度、气压都属于普通传感器,sensor.on 直接可用。
九、构建、安装和真机验证
cd example
flutter pub get
flutter analyze
flutter build hap --debug
hdc install -r build/ohos/hap/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b com.example.flutter_oh_demo
真机结果(图 1、图 2):
| 传感器 | isSensorAvailable | 实际订阅结果 |
|---|---|---|
| 环境温度(安卓 13) | false | 设备无此传感器 |
| 相对湿度(安卓 12) | false | 设备无此传感器 |
| 环境光(安卓 5) | true | 订阅中,已收 7 条,最新 646.00 lux |
| 气压(安卓 6) | false | 设备无此传感器 |
这个结果本身就是映射表生效的证明。 如果翻译表写错了(比如把安卓 5 直接当鸿蒙 5 用,虽然恰好对;或者把安卓 13 直接传给鸿蒙),那么「环境光可用」这个判断结果就会不同——要么全 false,要么订到别的传感器上。
而订阅后收到 7 条真实数据、最新值 646.00 lux,说明 sensor.on(AMBIENT_LIGHT) 的数据回调链路完全打通,response.intensity 的字段名也取对了(取错字段会得到 undefined 而不是数字)。
补充说明:测试设备是手机,只配备了环境光传感器,没有温湿度和气压传感器——所以另外三项返回
false是设备能力的真实反映,不是实现缺陷。这类「不可用」恰恰说明getSingleSensorSync探测是有效的:如果实现里无脑返回true,这三项就会假报为可用。
十、适配结果和当前边界
1 个方法 + 4 条事件通道全部接通,Dart 层一行未改。
已知边界:
- 设备能力决定可用项:手机上通常只有环境光,温湿度/气压多在 IoT 设备上。返回
false是真实设备状态; - 传感器 ID 必须走翻译表:安卓
Sensor.TYPE_*与鸿蒙SensorId数值不通用,13 和 6 在两边含义不同,这是必须做翻译的根本原因; sensor.on要求字面量:无法用变量传SensorId,四个传感器需分别写死;- 采样频率未暴露:上游没有频率参数,实现用系统默认采样率,未做定制。
十一、FAQ
Q1:为什么不能直接把安卓的传感器 ID 传给鸿蒙?
- 现象: 安卓的 13 是环境温度,鸿蒙的 13 是相对湿度;安卓的 6 是气压,鸿蒙的 6 是计步。
- 解决方法: 建
ANDROID_TO_OHOS_SENSOR翻译表,把安卓常量映射到鸿蒙SensorId。 - 验证结果: 环境光(两边都是 5)正常出数;其余三项返回 false(设备确实没有)。
Q2:为什么温湿度、气压都显示「不可用」?
- 现象: 四个传感器只有环境光可用。
- 解决方法: 这是设备能力差异——手机只有环境光,温湿度/气压需要 IoT 设备。用
sensor.getSingleSensorSync探测,不存在就返回 false。 - 验证结果: 与环境光真实出数形成对照,证明探测逻辑有效。
Q3:sensor.on 为什么不能传变量?
- 现象:
const id = sensor.SensorId.AMBIENT_LIGHT; sensor.on(id, cb)报No overload matches this call。 - 解决方法: 每个传感器重载的回调类型不同,必须写死字面量让编译器选中正确重载。
- 验证结果: 四个传感器各自写死字面量后编译通过、运行正常。
Q4:光照值 646.00 是什么单位?
- 现象: 界面显示
最新 646.00。 - 解决方法: 鸿蒙
LightResponse.intensity单位是 lux(勒克斯),646 lux 大致相当于室内明亮环境。 - 验证结果: 数值随遮挡/照射变化,说明是真实传感器读数。
十二、总结
environment_sensors 0.3.0 已完整接入鸿蒙:1 个可用性方法 + 4 条事件流全部接通,核心是解决了安卓传感器常量与鸿蒙 SensorId 数值错位的问题(13 和 6 在两个平台含义完全不同)。真机上环境光订阅收到 7 条数据、最新 646.00 lux,另外三项如实返回不可用(设备确实没有)。
这个库最值得记的一条经验是:跨平台适配里「数字常量」比「字符串」危险得多。字符串传错通常立刻报错,数字传错往往静默返回错误的数据——你订到了湿度却以为是温度,代码不报错,业务逻辑全错。所以看到上游传裸数字做类型标识时,第一件事就是查两边常量定义,确认是否真的可以通用。
十三、参考资料和仓库地址
- 适配仓库主页
- 适配分支
- 适配 TAG
- ArkTS 通道实现
- 鸿蒙适配说明
- pub.dev 包页面
- pub.dev 0.3.0 版本页
- 上游仓库
- Flutter 官方插件与平台通道文档
- Flutter OH 鸿蒙 SDK 仓库
- HarmonyOS 开发者官方文档
欢迎加入CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter
更多推荐



所有评论(0)