Flutter 鸿蒙实战:用 wakelock_plus 三方库给阅读页加上屏幕常亮
AI工具 码道 推荐: 华为云码道
阅读页有个小问题:用户一直在看,却不一定会点屏幕。读得稍微久一点,屏幕就暗了,还得再点一下。
这次选了 wakelock_plus,做一个叫 LeafRead 的小 Demo。功能很简单,点“开始阅读”保持屏幕常亮,点“结束阅读”恢复系统休眠。开始和结束阅读调用开启、关闭接口,阅读设置里的常亮开关和刷新按钮用到另外两个接口。
LeafRead 的完整源码已经放到 atomgit,文章里的阅读页面、常亮设置和测试代码都在这里:
项目仓库:https://atomgit.com/lqjmac/leafread
常亮功能用的是 AtomGit 上 CPF-Flutter 维护的鸿蒙版本,仓库链接统一放在文末。接入代码不多,这次花时间核对的主要是依赖:仓库里新旧版本的目录不同,主包和平台接口包也要配套。下面把实际跑通的配置和过程记下来。
环境和设备
还没搭好 Flutter 鸿蒙环境的话,可以先看《Flutter OHOS 开发环境搭建指南》,链接见文末。
我这边用的环境如下,测试日期是 2026 年 9 月 8 日。
| 项目 | 版本 |
|---|---|
| Flutter | 3.44.9+ohos-0.0.1-canary1,revision 4f1a4267af |
| Dart | 3.12.2 |
| DevEco Studio / Hvigor | 26.0.0.821 / 6.26.4 |
| 编译 SDK / 最低兼容 API | 26 / 18 |
| 手机 | HUAWEI Mate 60 Pro,型号 ALN-AL00 |
| 手机系统上报 | OpenHarmony-6.1.1.120,API 24 |
手机版本可以用下面的命令查看。这里记录的是设备实际输出,和电脑上安装的编译 SDK 分开看。
hdc shell param get const.ohos.fullname
hdc shell param get const.ohos.apiversion
先把依赖选对
这次用的是 wakelock_plus 1.4.0,固定到提交 2ae26ad8c8b6d24f23cc03550fe30095916f39ba。测试时,br_v1.4.0_ohos_dev 和 br_3.41_dev 都指向这个提交。下面的配置可以直接放进应用的 pubspec.yaml:
dependencies:
flutter:
sdk: flutter
wakelock_plus:
git:
url: https://atomgit.com/CPF-Flutter/fluttertpc_wakelock_plus.git
ref: 2ae26ad8c8b6d24f23cc03550fe30095916f39ba
path: wakelock_plus
dependency_overrides:
wakelock_plus_platform_interface:
git:
url: https://atomgit.com/CPF-Flutter/fluttertpc_wakelock_plus.git
ref: 2ae26ad8c8b6d24f23cc03550fe30095916f39ba
path: wakelock_plus_platform_interface
执行:
flutter pub get
这里有两处容易配错。
一处是 path。旧 README 里能看到 wakelock_plus_ohos 和 path: wakelock_plus/ohos,但这个提交已经把鸿蒙支持放进主包了,应该用上面的 wakelock_plus。此时 ohos 目录里放的是原生模块。
另一处是 dependency_overrides。一开始只加主包,Pub 自动解析到了 pub.dev 的平台接口包。继续比对源码发现,两边的消息格式对不上:这个鸿蒙实现返回布尔字段列表,同仓库的 Dart 接口按这个结构解码,而 pub.dev 解析到的版本期待消息对象。
主包和平台接口包要配套。 这次把两者指向同一个 AtomGit 提交,已经通过协议测试和真机调用。
pubspec.lock保留在 Demo 中,以后升级依赖时一起检查这两个包。
四个接口就够用了
wakelock_plus 的功能很集中:开启常亮、关闭常亮、传入布尔值设置状态,以及查询当前状态。除了阅读页,菜谱、运动指导这类“看得多、点得少”的页面也能用到。
鸿蒙端底层调用的是窗口 API:
const windowClass = await window.getLastWindow(this.context);
await windowClass.setWindowKeepScreenOn(true);
const enabled = windowClass.getWindowProperties().isKeepScreenOn;
它控制当前应用窗口的常亮,不会永久修改手机的全局休眠时间,也不能拿来做后台保活。
Dart 端先导入:
import 'package:wakelock_plus/wakelock_plus.dart';
开始和结束阅读,分别调用 enable()、disable():
// 开始阅读
await WakelockPlus.enable();
final afterStart = await WakelockPlus.enabled;
// 结束阅读
await WakelockPlus.disable();
final afterStop = await WakelockPlus.enabled;
这两个方法返回的都是 Future<void>。Demo 每次操作后都会再读一次 enabled,再把结果显示到页面上。这样遇到调用失败或状态没变化时,页面能反映出来。
如果需要用一个开关控制,可以调用 toggle():
await WakelockPlus.toggle(enable: true); // 开启
await WakelockPlus.toggle(enable: false); // 关闭
这个名字容易让人理解成“取反”。实际上传进去的是目标值:true 就是开,false 就是关,适合接到 Switch.onChanged。
只想看看现在开没开,读取 enabled 即可:
final bool isEnabled = await WakelockPlus.enabled;
它是异步 getter,不带括号,也不会改变常亮状态。
接到阅读页上
LeafRead 直接以阅读正文为主,内置了朱自清《荷塘月色》的节选。底部提供开始、结束阅读,右上角的阅读设置里可以调字号、开关常亮和刷新状态。
这是新版开启常亮后的样子。底部的“屏幕常亮已开启”来自实际状态查询;具体的接口名和布尔返回值放在代码里说明。

按钮接好后,还需要处理用户直接切走应用的情况。Demo 监听了应用生命周期:
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused) {
unawaited(controller.releaseForBackground());
} else if (state == AppLifecycleState.resumed) {
unawaited(controller.refresh());
}
}
releaseForBackground() 内部调用 disable(),返回前台时重新查询状态。这里没有自动恢复常亮,用户继续阅读时再点一次“开始阅读”。页面销毁时也会释放。
另外,控制器把这些操作放进同一个队列。原因是 enable() 和 disable() 都是异步的,如果刚点开启就切到后台,需要让释放操作排在开启之后,避免执行顺序反过来。按钮在调用期间也会暂时禁用。
这部分代码在 lib/wakelock_controller.dart,页面和生命周期代码在 lib/main.dart。如果把它搬到多页面应用里,还要考虑路由切换:应用内部跳到其他页面不一定触发 paused,可以用 RouteAware 处理阅读页被覆盖的情况。
下载源码,签名后装到手机
可以直接把 LeafRead 拉下来运行,依赖已经写进工程:
git clone https://atomgit.com/lqjmac/leafread.git
cd leafread
flutter pub get
下面的命令都在 leafread 工程根目录执行。仓库没有放本机签名配置,首次打开前先复制模板:
cp ohos/build-profile.template.json5 ohos/build-profile.json5
然后完成调试签名:
- 用 DevEco Studio 打开
ohos目录。 - 进入 File → Project Structure → Signing Configs。
- 勾选 Automatically generate signature,给当前工程和手机生成签名,再点 Apply/OK。
Demo 的包名是 com.example.ugc.reading_wakelock_demo。
签名完成后构建、安装:
flutter build hap --release
hdc list targets
hdc -t <设备ID> install -r build/ohos/hap/entry-default-signed.hap
hdc -t <设备ID> shell aa start \
-a EntryAbility -b com.example.ugc.reading_wakelock_demo
我电脑上有两套 Hvigor,这次明确使用了 DevEco Studio 自带的版本:
PATH=/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin:$PATH \
DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk \
flutter build hap --release
这是 macOS 上的安装路径,换一台电脑需要相应调整。这次用 release 包独立运行;平时调页面,需要热重载的话可以用 flutter run -d <设备ID>。
手机上实际试了什么
签名后的 HAP 约 21.8 MB。这次检查的结果:
-
flutter analyze:静态分析通过。 -
flutter test:8 项测试通过。 - 签名 HAP:已在鸿蒙手机上安装、启动。
在手机上逐项操作后的结果如下:
| 操作 | 结果 |
|---|---|
点“开始阅读”,调用 enable() | 查询为 true |
点“结束阅读”,调用 disable() | 查询为 false |
在阅读设置中打开常亮开关,调用 toggle(enable: true) | 查询为 true |
在阅读设置中关闭常亮开关,调用 toggle(enable: false) | 查询为 false |
在开启、关闭状态下点击“刷新状态”,查询 enabled | 分别返回 true、false,状态没有改变 |
| 开启后按 Home,再回到 Demo | 查询为 false,后台释放生效 |
不过,只看页面上的 true 还不够,还得试试放着不碰会不会熄屏。
此前在同一台手机上,我临时把熄屏超时设成 10 秒,分两次各等待 20 秒。开启常亮时不碰手机,20 秒后系统仍是 AWAKE;关闭常亮再等 20 秒,系统进入了 SLEEP。测试结束后恢复了原来的休眠配置。
系统状态通过这条命令读取:
hdc shell hidumper -s PowerManagerService -a '-s'
原始记录保存在 docs/evidence/idle-comparison.json。这次做的是短时功能对照,没有测长时间使用的耗电量。
FAQ:接入时遇到的问题
找不到包,或者提示 Dart SDK 版本不兼容
先看拉的是哪个分支,再核对包名和 path。仓库中还保留着旧版工程,直接用 master 或照搬旧 README,可能拿到面向旧 Dart 的配置。本文的依赖写法对应前面固定的提交。
查询 enabled 时出现类型转换或解码错误
先检查 pubspec.lock 中平台接口包的来源。主包来自鸿蒙仓库、平台接口却来自 pub.dev 时,需要核对两端消息格式。本文用同一 Git 提交里的两个包解决了配套问题。
修改后重新执行 flutter pub get,再构建、安装 HAP。涉及原生依赖的变化,不能只做热重载。
构建出来的是 unsigned.hap
这次第一次构建就停在签名环节,工具提示用 DevEco Studio 配置调试签名。按前面的步骤完成后,重新构建即可得到 signed.hap。如果换了手机,还要检查调试 Profile 是否包含新设备。
签名文件留在本机就好,不要随源码上传。Demo 已忽略本机的 ohos/build-profile.json5,另附了一份无签名模板。
偶发找不到 PlatformChannelWorker.ets
最后一次增量构建出现过这个错误:
Could not resolve entry module ... PlatformChannelWorker.ets
报错路径在 Flutter HAR 的依赖展开目录里。检查时文件已经存在,再跑同一条构建命令就通过了。这次没有定位到确定根因;如果反复出现,可以先等 IDE 同步结束,再检查 oh_modules 中的文件和依赖来源,保留日志继续排查。
关闭常亮后,屏幕为什么没有马上灭?
disable() 只是恢复系统休眠规则。调用后还要等系统超时,不会立刻关屏。前面的 10 秒超时对照,就是为了验证这一步。
需要申请权限吗?
这个鸿蒙实现使用窗口的 setWindowKeepScreenOn,不需要弹出运行时权限申请。工程模板中的 ohos.permission.INTERNET 可用于 Flutter 调试,和开启常亮不是一回事。
发现库的问题,怎么反馈
1. 提交 Issue,说明问题和复现步骤
从文末链接进入 wakelock_plus 鸿蒙版本仓库,打开 Issues 页面,先搜索有没有相同的问题。如果没有,点击右上角的 新建 Issue,填写问题标题和复现信息。

图 1:进入 Issues 页面,点击“新建 Issue”反馈问题。
拿这次发现的依赖配套问题来说,报告时可以把“只引入主包”的配置贴出来,再附上 pubspec.lock 中实际解析的平台接口版本。说明调用 enabled 时预期得到布尔值、实际遇到什么错误,以及换成同仓库接口包后是否正常。Flutter 版本、设备系统、提交号和关键日志也一起带上,维护者会比较容易复现。
2. Fork 项目,在自己的仓库中修改
如果问题能自己修,可以点击上游仓库右上角的 Fork。在 Fork 页面确认项目名称、自己的账号和要复制的分支,再点击 创建 Fork 项目。

图 2:将上游项目 Fork 到自己的 AtomGit 账号下。截图以 master 为例,实际修改时要核对对应的适配分支。
Fork 完成后,把自己的仓库克隆到本地,并添加上游仓库。下面以补充依赖说明为例,从本文使用的 br_v1.4.0_ohos_dev 分支创建工作分支,<你的账号> 换成自己的 AtomGit 账号:
git clone https://atomgit.com/<你的账号>/fluttertpc_wakelock_plus.git
cd fluttertpc_wakelock_plus
git remote add upstream https://atomgit.com/CPF-Flutter/fluttertpc_wakelock_plus.git
git fetch upstream
git switch -c docs/ohos-dependency-pairing upstream/br_v1.4.0_ohos_dev
可以先改中文 README,把新版包名、目录和配套依赖写清楚。改好后检查差异,再推到自己的 Fork:
git diff --check
git diff
git add README.OpenHarmony_CN.md
git commit -m "docs: clarify OHOS wakelock dependency pairing"
git push -u origin docs/ohos-dependency-pairing
3. 创建 PR,把修改提交给上游
推送后回到自己的 AtomGit Fork 仓库,点击 同步源项目,选择包含修改的分支。有超前提交时,可以通过弹窗中的 创建并提交 PR 进入 PR 创建页面。

图 3:查看自己的分支与上游的提交差异,通过“创建并提交 PR”发起贡献。截图展示的是 master 分支入口,本文示例的源分支应选择 docs/ohos-dependency-pairing。
在 PR 页面核对源仓库和源分支,目标仓库选 CPF-Flutter 上游,目标分支按维护者当前要求选择。填写标题和说明,写清原来哪里配不对、改了什么、用哪个版本验证过;有对应 Issue 就关联上,确认差异后提交 PR。如果改的是插件代码,还要重新上机验证,尤其是开启、关闭和查询的返回结果。
相关链接
欢迎加入 CPF-Flutter 鸿蒙社区,社区入口、环境搭建指南和三方库链接统一放在这里:
更多推荐


所有评论(0)