适配仓库: https://atomgit.com/oh-flutter/device_screen_brightness
适配分支:
feat/ohos_device_screen_brightness_2.0.0受测提交:
3a842e4982e788a494c5034aac932d1c2b779946
一、最终效果与适配目标
阅读器、视频播放器和夜间工具经常需要临时调节当前页面亮度。device_screen_brightness 2.0.0 已把读取、写入、增减、变化监听和能力查询整理成统一 Dart API,但上游没有 OHOS 实现。本次适配保持这些公共接口不变,在 OHOS 侧补上"应用窗口亮度"和"系统亮度"两种模式。
我优先验证不需要特殊权限的 BrightnessMode.app:进入页面时读取当前亮度,拖动滑块后回读实际值,监听流同步更新,离开页面或插件解绑时恢复原窗口值。系统模式也完成了读取和拒绝权限路径,但普通应用没有 MANAGE_SETTINGS 授权,所以没有把"系统亮度写入成功"写成真机结论。

图 1:CHZ-AL00 / HarmonyOS 7.0.0.105 上读取到应用窗口继承的初始亮度,系统自动亮度保持开启。

图 2:在应用模式拖动滑块后,页面数值、窗口回读和事件记录同步变化。

图 3:后一轮独立测试中将窗口恢复为 -1,即重新跟随系统亮度;该图的 19% 与图 1、图 2 不是同一次连续回环。
| 验证点 | 实测结果 | 证据 |
|---|---|---|
| 应用亮度读取与写入 | 0 到 100 的整数值可读取,写入后独立窗口属性回读一致 | 图 1、图 2、图 8 |
| 亮度变化流 | 订阅时先发当前值,后续变化去重投递 | 图 2、图 8 |
| 页面退出与插件解绑 | 原窗口亮度 -1 得到恢复 |
图 3、图 8 |
| 系统写入权限 | 未授权时明确返回 permission_denied |
图 8 |
| 自动化与构建 | 44 项功能测试、静态分析和 HAP 构建通过 | 图 6、图 7 |
二、成果速览
| 项目 | 内容 |
|---|---|
| 上游基线 | TAG v2.0.0,提交 d0aa9305d73cff8f9e0f7b65f6586c3380b7af94,MIT |
| 适配分支 | feat/ohos_device_screen_brightness_2.0.0 |
| 适配提交 | 3a842e4982e788a494c5034aac932d1c2b779946 |
| 新增 OHOS 能力 | 应用/系统亮度读取、写入、增减、事件、能力与权限查询、窗口恢复 |
| 保持不变的接口 | DeviceScreenBrightness、BrightnessMode、原 MethodChannel/EventChannel |
| 自动化验证 | 24 项 Dart、2 项 Widget、18 项 ArkTS,共 44 项 |
| 真机结论 | 应用模式 14 项检查通过;系统授权写入、外部系统变化和其他机型未验证 |
2026 年 9 月 11 日适配前,我重新核对了发布版本、上游 HEAD、三方库清单以及目标组织同名仓库,没有发现可直接使用的 OHOS 实现。这个结论只对应当时核查范围,不把它扩大成全网结论。
三、实测环境
| 组件 | 实测版本 |
|---|---|
| Flutter OH | 3.41.10-ohos-1.0.1 |
| Dart | 3.11.5 |
| DevEco Studio | 26.0.0 Release |
| HarmonyOS SDK | API 26;示例 compatibleSdkVersion 为 18 |
| 真机 | CHZ-AL00,HarmonyOS 7.0.0.105 |
| 插件 | device_screen_brightness 2.0.0 |
环境搭建直接参考 Flutter OH 环境搭建指南。截至 2026 年 9 月 12 日,版本号最大的 Flutter OH 标签 3.44.9+ohos-0.0.1-canary1 仍是预览版;本文使用完成构建和真机回归的正式稳定版 3.41.10-ohos-1.0.1,不把预览版本写成受测环境。
四、同步上游并建立适配分支
上游 2.0.0 已完成平台通道化,适合作为稳定基线。我保留上游 Git 历史与 MIT 许可证,将代码同步到 AtomGit 后,从 v2.0.0 创建统一命名分支:
shell
git clone https://atomgit.com/oh-flutter/device_screen_brightness.git
cd device_screen_brightness
git switch -c feat/ohos_device_screen_brightness_2.0.0 v2.0.0
flutter create --template=plugin --platforms=ohos --no-pub .
模板只负责生成 ohos/ 与 example/ohos/ 骨架。随后必须把插件类、通道名称和示例代码改回本库真实契约,不能保留模板的 getPlatformVersion。

图 4:AtomGit origin、适配分支、完整 HEAD 和干净工作区的实际核验。
五、先固定原有 API 契约
公共 API 使用 0 到 100 的整数刻度,调用者不需要理解 OHOS 窗口值的 0 到 1 或系统设置值的 0 到 255:
dart
final int current = await DeviceScreenBrightness.getBrightness(
mode: BrightnessMode.app,
);
final int applied = await DeviceScreenBrightness.setBrightness(
65,
mode: BrightnessMode.app,
);
final Stream<int> changes = DeviceScreenBrightness.streamBrightness(
mode: BrightnessMode.app,
);
方法通道保持 dev.arcas.device_screen_brightness/methods,事件通道保持 dev.arcas.device_screen_brightness/events。OHOS 端只增加平台实现,不改 Android、iOS、桌面端原生源码。Dart 分发额外识别 Platform.operatingSystem == 'ohos',否则 app 模式事件会被错误当作 system 过滤。
六、OHOS 端的窗口与系统两条路径
pubspec.yaml 注册 DeviceScreenBrightnessPlugin。应用模式通过当前 UIAbility 的主窗口读写,系统模式通过 Settings 读取 0 到 255 的系统值:
typescript
if (mode === 'app') {
const raw = this.readWindow(session).getWindowProperties().brightness;
if (raw >= 0 && raw <= 1) return Math.round(raw * 100);
}
const raw = settings.getValueSync(
session.ability.context,
settings.display.SCREEN_BRIGHTNESS_STATUS,
'',
);
return Math.round(Number(raw) / 255 * 100);
窗口属性为 -1 时表示继承系统值,因此读取应用亮度时会回退到系统设置。第一次写应用亮度前,插件保存窗口 ID 和原值;解绑时只有当前窗口值仍等于插件最后写入值才恢复,避免覆盖宿主其他组件后来设置的新亮度。原生浮点回读可能是 0.699999988079071,比较时必须容忍 float32 精度,而不能只写 value === 0.7。
系统模式写入前检查 ohos.permission.MANAGE_SETTINGS。该权限不能由普通运行时弹窗授予,requestPermission() 在无授权时会抛出稳定的 PermissionDeniedException,而不是假装请求成功。应用窗口模式不需要这个权限,也不会主动关闭系统自动亮度。
事件层在 Dart 存在订阅者时每 250 ms 读取两种模式并去重;取消最后一个订阅后停止轮询。写操作放进串行队列,避免连续加减与恢复操作交叉。

图 5:窗口/系统模式分发、单位换算、权限检查和写后回读的受测实现。
七、交付文件与自动化验证
适配分支新增 OHOS HAR、独立示例、双语 OHOS 文档、Dart/Widget 测试、生产 ArkTS mock 测试与真机探测入口。上游源码、许可证和其他平台实现保持不变;签名材料、local.properties、依赖缓存与 HAP 不提交。
shell
flutter pub get
flutter analyze
flutter test
node --test ohos/test/device_screen_brightness_plugin.test.cjs
cd example
flutter test
flutter build hap --debug --no-codesign
24 项 Dart、2 项 Widget 和 18 项 ArkTS 测试全部通过。覆盖范围包括参数边界、单位映射、写后回读、权限拒绝、事件去重、取消与重订阅、并发顺序、写入中解绑、窗口切换及原值恢复。

图 6:静态检查和 44 项自动化功能测试的真实结果汇总。

图 7:无签名 HAP 的实际大小、SHA-256 与受测代码提交。
八、固定提交接入并做真机回环
当前没有 OHOS 稳定 TAG,因此 Demo 用完整 SHA 锁定:
yaml
dependencies:
device_screen_brightness:
git:
url: https://atomgit.com/oh-flutter/device_screen_brightness.git
ref: 3a842e4982e788a494c5034aac932d1c2b779946
执行 flutter pub get 后,应在 pubspec.lock 中确认 resolved-ref 与上面 SHA 一致。最终真机探测共 14 项通过:能力查询、应用亮度读取、写入、增减、事件、非法值、系统权限拒绝、独立窗口回读,以及从 Engine 移除插件后的原值恢复。最终窗口回到 -1,系统自动亮度仍为 1。

图 8:真机检查成功项与未覆盖边界同时保留,没有把权限拒绝包装成成功写入。
需要特别说明,图 1、图 2 记录的是一轮 45% -> 65% 操作;图 3 是下一天系统环境为 19% 时拍摄的恢复页。两组图都是真实结果,但不能拼成一次连续的 45 -> 65 -> 19 回环。
应用内补拍:连续事件与真实回读

图 9:再次把应用窗口调到 45% 后,页面同时展示窗口回读、系统自动亮度和连续亮度事件。
九、FAQ
Q1:为什么应用模式初次读取到系统亮度
- 现象: 窗口属性为
-1,页面仍能显示一个 0 到 100 的亮度值。 - 原因:
-1表示窗口没有独立覆盖,实际亮度继承系统设置。 - 解决方法: 应用模式读取遇到
-1时回退读取系统亮度;恢复时写回-1。 - 验证结果: 真机退出页面后窗口回读为
-1,页面重新跟随系统亮度。
Q2:系统模式为什么一直报 permission_denied
- 现象:
setBrightness(..., mode: BrightnessMode.system)被拒绝。 - 原因: OHOS 全局亮度写入要求
MANAGE_SETTINGS,普通应用不能通过运行时对话框获得。 - 解决方法: 普通业务优先使用
BrightnessMode.app;只有具备相应系统授权的宿主才启用系统模式。 - 验证结果: 自动化和真机均确认拒绝错误稳定返回,没有误改系统自动亮度。
Q3:为什么恢复比较不能严格等于 0.7
- 现象: ArkTS 写入 0.7,真实窗口回读
0.699999988079071。 - 原因: 原生窗口属性使用浮点表示,存在正常精度差。
- 解决方法: 用小容差判断当前值是否仍是插件写入值,再决定是否恢复。
- 验证结果: 修复后 18 项原生回归和最终 14 项真机检查通过。
十、总结
这次适配保留了 device_screen_brightness 的完整 Dart API,在 OHOS 端补上应用/系统模式、事件监听、能力与权限查询,并把窗口恢复作为生命周期的一部分处理。44 项自动化、HAP 构建和 API 26 真机应用模式回环均已通过。
当前证据不包含系统授权后的全局写入、外部设置页变化、长期轮询和其他设备。业务接入时应默认显式选择 BrightnessMode.app,并继续锁定受测提交,等正式 OHOS TAG 发布后再升级。
十一、参考链接
欢迎加入CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter