Flutter 3.47 鸿蒙三方库适配实战:从 0 到 1 处理 airplane_mode_checker
Flutter 3.47 鸿蒙三方库适配实战:从 0 到 1 处理 airplane_mode_checker
飞行模式是个「用户开了就想让应用知道」的状态:离线阅读要暂停同步、下载要暂停、定位要降级。安卓用 BroadcastReceiver(ACTION_AIRPLANE_MODE_CHANGED) 监听,iOS 用 NSNotification。airplane_mode_checker 把这两套收成「一个查询方法 + 一条事件流」,本批里它和 system_settings_2 都属于「系统设置」这条能力线——只不过一个是读状态,一个是打开设置页。
本文以 airplane_mode_checker 3.3.0 为例,记录我如何保留原有 Dart API、在鸿蒙端用 settings.getValueSync + 系统公共事件接入真实状态读取与变化监听,并在 HarmonyOS API 26 真机上完成构建、安装、启动与调用验证。
适配仓库: oh-flutter/airplane_mode_checker
适配分支: feat/ohos_airplane_mode_checker_3.3.0
适配 TAG: 3.3.0-ohos-1.0.0-beta.1
一、先看最终效果

图 1:HarmonyOS API 26 真机启动自检台。页面显示「平台版本:未查询 / 单次查询:未查询 / 事件通道:未订阅」,下方三个按钮对应查版本、查状态、订阅事件。
图 2:依次点击三个按钮后的完整结果——平台版本 OpenHarmony OpenHarmony-7.0.0.105、单次查询 ON(飞行模式已开)、事件通道 订阅中(已收 1 次)· 最近事件:ON。
| 验证点 | 实测结果 | 证据 |
|---|---|---|
| Flutter OH 3.47 工程构建 | 通过 | entry-default-signed.hap |
| 安装、启动(真机) | 通过 | 图 1 |
| getPlatformVersion() | OpenHarmony OpenHarmony-7.0.0.105 | 图 2 |
| checkAirplaneMode() | on(读到系统真实状态) | 图 2 |
| 事件通道订阅 | 订阅后立即收到 1 次当前值 on | 图 2 |
二、这个库原来是怎么工作的
airplane_mode_checker 的接口面很小,但同时用了两条通道:
Dart AirplaneModeChecker
-> MethodChannel('airplane_mode_checker')
getPlatformVersion() -> String
checkAirplaneMode({defaultValue}) -> "ON" / "OFF"
-> EventChannel('airplane_mode_checker_stream')
先推一次当前值,之后每次开关变化推一次
安卓侧 checkAirplaneMode 读 Settings.Global.AIRPLANE_MODE_ON,监听走 BroadcastReceiver;iOS 侧读 AVAudioSession 之外的系统状态并监听 NSNotification。
注意 checkAirplaneMode 有个 defaultValue 参数——上游的意思是「读不到就返回调用方给的默认值」,这个语义在鸿蒙侧必须保留。
三、实际环境
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) |
| 目标库 | airplane_mode_checker 3.3.0 |
flutter --version
hdc list targets
四、确认上游版本并同步到 AtomGit
上游包地址是 https://github.com/14h4i/airplane_mode_checker,版本 3.3.0,使用 MIT License。适配前我在 AtomGit 目标组织中搜索了同名库,没有找到可以直接使用的 OHOS 实现。
git clone https://atomgit.com/oh-flutter/airplane_mode_checker.git
cd airplane_mode_checker
git switch feat/ohos_airplane_mode_checker_3.3.0
git log --oneline -5
五、创建适配分支并检查工程结构
git switch -c feat/ohos_airplane_mode_checker_3.3.0
关键目录如下:
airplane_mode_checker/
├── lib/
│ └── airplane_mode_checker_method_channel.dart # 上游通道定义,一行未改
├── ohos/
│ ├── index.ets # OHOS 插件导出入口
│ └── src/main/ets/components/plugin/
│ └── AirplaneModeCheckerPlugin.ets # 通道实现
├── example/lib/main.dart # 真机验证自检台
├── example/ohos/ # Flutter OH 宿主工程
├── pubspec.yaml # 声明 ohos 平台
└── README.OpenHarmony_CN.md # 鸿蒙适配说明
pubspec.yaml 中的关键声明是:
flutter:
plugin:
platforms:
ohos:
pluginClass: AirplaneModeCheckerPlugin
六、适配过程:两条通道 + 一个坑
6.1 同时注册方法通道和事件通道
const METHOD_CHANNEL: string = 'airplane_mode_checker';
const EVENT_CHANNEL: string = 'airplane_mode_checker_stream';
onAttachedToEngine(binding: FlutterPluginBinding): void {
const messenger = binding.getBinaryMessenger();
this.methodChannel = new MethodChannel(messenger, METHOD_CHANNEL);
this.methodChannel.setMethodCallHandler(this);
this.eventChannel = new EventChannel(messenger, EVENT_CHANNEL);
this.eventChannel.setStreamHandler(new AirplaneModeStreamHandler(
(events: EventSink, defaultValue: string): void => {
this.startListening(events, defaultValue);
},
(): void => {
this.stopListening();
}));
}
6.2 读当前状态:settings.getValueSync
鸿蒙把系统设置项收在 @kit.BasicServicesKit 的 settings 里:
const SETTING_KEY: string = settings.general.AIRPLANE_MODE_STATUS;
const SETTING_ON_VALUE: string = '1';
// 需要 Context,所以插件要实现 AbilityAware
const value: string = settings.getValueSync(
this.ability.context,
SETTING_KEY,
defaultValue // 读不到时回退到调用方给的值,与上游语义一致
);
result.success(value === SETTING_ON_VALUE ? 'ON' : 'OFF');
这里有个必须说清楚的坑:settings.general.AIRPLANE_MODE_STATUS 在 API 21 起被标记为 deprecated(SDK 声明里写着),但它的替代品 @ohos.enterprise.deviceSettings 是系统应用/企业应用接口,普通三方应用根本用不了。
所以现状是:三方应用读飞行模式,目前仍只能走这一项 deprecated 接口。我在 README 的「已知限制」里如实记了这一条,而不是假装它很干净。
6.3 监听变化:系统公共事件比轮询更接近上游语义
安卓用 BroadcastReceiver,鸿蒙对应的机制是系统公共事件:
const AIRPLANE_MODE_EVENT: string = 'usual.event.AIRPLANE_MODE';
private startListening(events: EventSink, defaultValue: string): void {
// 先推一次当前值,与上游「订阅即得到当前状态」的约定一致
events.success(this.readCurrent(defaultValue));
const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
events: [AIRPLANE_MODE_EVENT],
};
this.subscriber = commonEventManager.createSubscriberSync(subscribeInfo);
commonEventManager.subscribe(this.subscriber, (err, data) => {
if (err) {
Log.e(TAG, `subscribe failed: ${err.code} ${err.message}`);
return;
}
events.success(this.readCurrent(defaultValue));
});
}
用公共事件而不是定时轮询,有两个好处:一是实时,开关一动立刻推送;二是省电,没有轮询就有没有无谓的唤醒。
6.4 插件必须实现 AbilityAware
settings.getValueSync 需要 Context,而插件默认拿不到。所以和 system_settings_2 一样要实现 AbilityAware:
onAttachedToAbility(binding: AbilityPluginBinding): void {
this.ability = binding.getAbility();
}
| 方法 | OpenHarmony 实现 |
|---|---|
getPlatformVersion() | 返回 OpenHarmony <版本> |
checkAirplaneMode({defaultValue}) | settings.getValueSync(context, AIRPLANE_MODE_STATUS, defaultValue),'1' → ON |
airplane_mode_checker_stream | commonEventManager.subscribe('usual.event.AIRPLANE_MODE'),订阅时先推一次当前值 |
七、构建配置与签名
这一步踩的坑与 system_settings_2 完全相同,两个都值得记下来。
7.1 compatibleSdkVersion 必须写 "26.0.0"
上游示例沿用旧模板 '5.1.0(18)',构建直接失败:
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.
带括号的写法 '6.0.0(20)'、'26.0.0(26)' 都不对(后者报 00308018 Unknown Error)。正确写法是纯版本号:
{
"products": [
{
"name": "default",
"signingConfig": "default",
"compatibleSdkVersion": "26.0.0",
"targetSdkVersion": "26.0.0",
"runtimeOS": "HarmonyOS"
}
]
}
7.2 签名证书绑定了 bundleName
00303074 Configuration Error
The bundleName in app.json5/hvigorfile.ts does not match the bundleName
in the generated SigningConfigs.
调试证书按包名签发,本库示例原本是 com.u14h4i.airplane_mode_checker_example,与证书对应的 com.example.flutter_oh_demo 不一致。把 AppScope/app.json5 改成证书对应的包名即可。
八、通过 AtomGit 引入适配版
dependencies:
airplane_mode_checker:
git:
url: https://atomgit.com/oh-flutter/airplane_mode_checker.git
ref: 3.3.0-ohos-1.0.0-beta.1
flutter pub get
本库不需要任何权限声明——读取 AIRPLANE_MODE_STATUS 设置项和订阅 usual.event.AIRPLANE_MODE 公共事件都不需要申请权限。
九、构建、安装和真机验证
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
构建输出 ✓ Built build/ohos/hap/entry-default-signed.hap.,hdc 报告安装与启动成功。
真机上的操作顺序与结果:
| 操作 | 实测显示 |
|---|---|
| 启动 | 「平台版本:未查询 / 单次查询:未查询 / 事件通道:未订阅」 |
| 点「查平台版本」 | getPlatformVersion() → OpenHarmony,界面显示 OpenHarmony OpenHarmony-7.0.0.105 |
| 点「查飞行模式」 | checkAirplaneMode() → on,界面显示 ON(飞行模式已开) |
| 点「订阅 / 取消订阅」 | 开始订阅 listenAirplaneMode(),随后收到 事件 #1 → on,界面显示 订阅中(已收 1 次)· 最近事件:ON |
订阅后立刻收到一次推送这一点很关键:它证明事件通道真的建立了,而不是只挂了个空 handler。
十、适配结果和当前边界
三个能力全部接通,Dart 层一行未改:
- 平台版本查询:返回
OpenHarmony OpenHarmony-7.0.0.105(读的是设备真实版本,不是硬编码字符串); - 单次状态查询:真机返回
ON,与系统设置的飞行模式开关一致; - 事件订阅:订阅后立即推送当前值,之后每次开关变化都用系统公共事件推送。
已知边界:
AIRPLANE_MODE_STATUS是 deprecated 接口:API 21 起被标记废弃,但替代品@ohos.enterprise.deviceSettings只对系统/企业应用开放,普通三方应用目前只能继续用它;- 测试设备当时处于飞行模式:真机上验证到的是
ON,OFF分支的代码路径与ON完全对称(同一个readCurrent函数按'1'判断),但没有在同一台设备上截到OFF的画面; - 事件推送依赖系统公共事件:如果某版本系统不发布
usual.event.AIRPLANE_MODE,订阅会成功但收不到变化推送,此时单次查询仍然可用。
十一、FAQ
Q1:为什么不用轮询?
- 现象: 定时调
checkAirplaneMode也能拿到变化,但会持续唤醒应用。 - 解决方法: 用系统公共事件
usual.event.AIRPLANE_MODE,只在真正变化时推送。 - 验证结果: 订阅后立即收到一次当前值,说明通道建立正常。
Q2:defaultValue 参数是干什么的?
- 现象: 上游
checkAirplaneMode({defaultValue})带一个默认值参数。 - 解决方法:
settings.getValueSync的第三个参数就是「读不到时的返回值」,直接把defaultValue传进去,语义完全对齐。 - 验证结果: 真机上读到真实值
'1',没有走到默认值分支。
Q3:为什么必须实现 AbilityAware?
- 现象:
settings.getValueSync第一个参数是Context,插件默认拿不到。 - 解决方法: 实现
AbilityAware,在onAttachedToAbility里保存UIAbility,再用ability.context。 - 验证结果: 正常宿主下三次调用全部成功。
Q4:和 system_settings_2 是什么关系?
- 现象: 两者都跟飞行模式有关。
- 解决方法: 本库是读状态 + 监听变化;
system_settings_2是打开设置页。想引导用户自己去开,用后者;想自己判断状态,用前者。 - 验证结果: 两库在同一台设备上均可独立工作。
十二、总结
airplane_mode_checker 3.3.0 已完整接入鸿蒙:查询用 settings.getValueSync、监听用系统公共事件 usual.event.AIRPLANE_MODE,订阅时先推一次当前值以对齐上游语义。真机上读到 ON、订阅后收到 事件 #1 → on,Dart 层一行未改。
这个库最值得记的一条经验是:鸿蒙上有些「唯一可用」的接口本身是 deprecated 的。AIRPLANE_MODE_STATUS 就是典型——新接口只给系统应用,三方应用只能继续用旧的。遇到这种情况,正确做法是照用 + 在文档里写清楚,而不是因为「已废弃」就假装做不到。
十三、参考资料和仓库地址
- 适配仓库主页
- 适配分支
- 适配 TAG
- ArkTS 通道实现
- 鸿蒙适配说明
- pub.dev 包页面
- pub.dev 3.3.0 版本页
- 上游仓库
- Flutter 官方插件与平台通道文档
- Flutter OH 鸿蒙 SDK 仓库
- HarmonyOS 开发者官方文档
欢迎加入CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter
更多推荐



所有评论(0)