Flutter 3.47 鸿蒙三方库适配实战:从 0 到 1 处理 flutter_overlay_window
跨应用悬浮窗是 Android 生态里非常有辨识度的能力:聊天应用把头像气泡浮在别的应用上层,靠的是 SYSTEM_ALERT_WINDOW 权限和 WindowManager 的 TYPE_APPLICATION_OVERLAY 窗口。flutter_overlay_window 更进一步,它用一个独立 Flutter 引擎渲染悬浮窗内容,主应用和悬浮窗之间通过消息通道互发数据。把这套机制搬到鸿蒙时,第一件事是弄清楚鸿蒙侧有没有等价的“跨应用覆盖窗口”能力。
本文以 flutter_overlay_window 1.0.0 为例,记录我如何保留它的双通道结构、在鸿蒙端如实返回权限与状态边界,并在 HarmonyOS API 26 模拟器上完成构建、安装、启动和按钮调用验证。上机结果是明确的:权限查询返回 false,悬浮窗状态返回 false,关闭操作安全完成——没有任何“悬浮窗已显示”的假象。
适配仓库: oh-flutter/flutter_overlay_window
适配分支: feat/ohos_flutter_overlay_window_1.0.0
适配 TAG: 1.0.0-ohos.1
一、先看最终效果
图 1:HarmonyOS API 26 模拟器启动 Demo。页面显示 flutter_overlay_window 1.0.0,状态为等待操作。
图 2:点击“查询悬浮窗权限”后的真实结果。isPermissionGranted 返回 false。
| 验证点 | 实测结果 | 证据 |
|---|---|---|
| Flutter OH 3.47 工程构建 | 通过 | entry-default-signed.hap |
| 签名、安装和启动 | 通过 | 图 1 |
isPermissionGranted | 返回 false | 图 2 |
showOverlay | 安全无操作,无异常 | 图 3 |
isActive | 返回 false | 图 4 |
closeOverlay | 返回完成 | 图 5 |
| 鸿蒙悬浮窗能力 | 尚未接入 | 适配边界 |
继续在模拟器上依次点击其余按钮:
图 3:调用 showOverlay 后返回完成,但不会伪造悬浮窗已显示的状态。
图 4:调用 isActive 后返回 false,与“没有活动悬浮窗”一致。
图 5:调用 closeOverlay 安全完成,没有悬浮窗时关闭动作无副作用。
二、这个库原来是怎么工作的
这条库的通道结构比其他插件复杂,值得先说清楚。它注册了三个通道:
Dart FlutterOverlayWindow
-> MethodChannel('x-slayer/overlay_channel') # 主控制面:显示、权限、关闭
-> MethodChannel('x-slayer/overlay') # 次级控制面:尺寸、位置、标志
-> BasicMessageChannel('x-slayer/overlay_messenger') # 数据平面:主应用与悬浮窗互发消息
-> Android 悬浮窗服务 / iOS 画中画
悬浮窗的内容由一个独立 Flutter 引擎渲染,宿主应用的 Dart 代码里要导出一个带 @pragma("vm:entry-point") 的 overlayMain 函数作为悬浮窗入口。主应用通过 shareData 和 overlayListener 与悬浮窗互相传递数据。
这套机制对平台的要求很具体:需要系统级“在其他应用上层显示”的权限模型,以及多引擎窗口管理能力。Android 用 SYSTEM_ALERT_WINDOW 实现;鸿蒙当前的应用模型里没有开放等价的跨应用覆盖窗口,所以这次适配的边界是“控制面契约完整、数据面保留、显示能力明确不可用”。
三、实际环境
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 |
| 测试设备 | DevEco 模拟器 Pura X View(HarmonyOS 7.0.0.105,API 26) |
本次验证使用 DevEco Studio 26.0.0 自带的 Pura X View 模拟器,系统版本与目标真机同为 HarmonyOS 7.0.0.105 / API 26;HAP 的签名、安装与启动链路和真机一致。
| 目标库 | flutter_overlay_window 1.0.0 |
四、确认上游版本并同步到 AtomGit
上游包地址是 GitHub X-SLAYER/flutter_overlay_window,版本 1.0.0 使用 MIT License。适配前我在 AtomGit 目标组织中搜索了同名库,没有找到可以直接使用的 OHOS 实现。
仓库初始适配提交为 8beafdc,完成后分支最新提交为 e494f97。
git clone https://atomgit.com/oh-flutter/flutter_overlay_window.git
cd flutter_overlay_window
git switch feat/ohos_flutter_overlay_window_1.0.0
git log --oneline -5
五、创建适配分支并检查工程结构
git switch -c feat/ohos_flutter_overlay_window_1.0.0
关键目录如下:
flutter_overlay_window/
├── lib/src/
│ ├── overlay_window.dart # 双通道 + 消息通道的全部 Dart API
│ └── overlay_config.dart # 对齐方式、标志、通知可见性等枚举
├── ohos/
│ ├── index.ets # OHOS 插件导出入口
│ └── src/main/ets/components/plugin/
│ └── FlutterOverlayWindowPlugin.ets # 双通道 MethodChannel 实现
├── example/lib/main.dart # 上机验证 Demo(含 overlayMain 入口)
├── pubspec.yaml # 声明 ohos 平台
└── README.OpenHarmony_CN.md # 鸿蒙适配说明
六、适配过程:覆盖三个通道的契约
修改前我先核对了 Dart 层实际使用的通道名和方法名,因为这条库的主控制面在 x-slayer/overlay_channel 上,而平台接口的 getPlatformVersion 声明在 flutter_overlay_window 通道上——两个都要注册,否则平台接口探测会在运行时拿不到注册。
OHOS 插件实现同时绑定两个 MethodChannel:
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.channel?.setMethodCallHandler(null);
this.channel = new MethodChannel(binding.getBinaryMessenger(), 'x-slayer/overlay_channel');
this.channel.setMethodCallHandler(this);
this.platformChannel?.setMethodCallHandler(null);
this.platformChannel = new MethodChannel(binding.getBinaryMessenger(), 'flutter_overlay_window');
this.platformChannel.setMethodCallHandler(this);
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
this.channel?.setMethodCallHandler(null);
this.channel = null;
this.platformChannel?.setMethodCallHandler(null);
this.platformChannel = null;
}
方法映射如下:
| Dart 方法 | OHOS 本次策略 |
|---|---|
getPlatformVersion | 返回 OpenHarmony 3.47.4 |
isPermissionGranted | 返回 false(没有悬浮窗权限模型) |
requestPermission | 返回 false(没有可申请的权限) |
isActive | 返回 false(没有活动悬浮窗) |
closeOverlay | 安全无操作,返回成功 |
onMethodCall(call: MethodCall, result: MethodResult): void {
switch (call.method) {
case 'getPlatformVersion':
result.success('OpenHarmony 3.47.4');
return;
case 'checkPermission':
result.success(false);
return;
case 'requestPermission':
result.success(false);
return;
case 'isOverlayActive':
result.success(false);
return;
case 'closeOverlay':
result.success(null);
return;
default:
result.notImplemented();
}
}
两组返回值的组合是刻意设计的:checkPermission 返回 false 让调用方知道“不要尝试显示悬浮窗”,requestPermission 返回 false 保证“申请-检查”流程不会死循环,closeOverlay 无害化保证退出清理代码可以直接执行。这样调用方按 Android 的正常心智写代码,在鸿蒙上自然表现为“没有悬浮窗可用”。
Demo 里保留了 overlayMain 入口函数(带 @pragma("vm:entry-point")),它是这条库在支持平台上加载悬浮窗内容的标准入口;鸿蒙端虽然暂不启用,保留它可以保证 Dart 侧结构和上游一致。
七、构建配置与签名
示例工程的目标 SDK 对齐到 26,且这是本批里依赖面最“干净”的示例:改造后我移除了旧示例中与悬浮窗演示无关的第三方依赖(头像生成、动画、Providers 等),把 demo 收敛成一个最小的四按钮验证页,保证示例在鸿蒙工具链下只依赖插件本身。
{
"name": "default",
"compatibleSdkVersion": "26.0.0",
"targetSdkVersion": "26.0.0",
"runtimeOS": "HarmonyOS"
}
Demo 的 AppScope/app.json5 统一成 com.example.flutter_oh_demo,与 DevEco 调试签名对应。
八、通过 AtomGit 引入适配版
dependencies:
flutter_overlay_window:
git:
url: https://atomgit.com/oh-flutter/flutter_overlay_window.git
ref: 1.0.0-ohos.1
九、构建、安装和设备验证
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.,随后安装启动成功。模拟器上依次点击四个按钮,分别得到图 2 至图 5:权限查询 false、显示无操作、状态 false、关闭完成。
十、适配结果和当前边界
| 层次 | 已完成内容 | 尚未完成内容 |
|---|---|---|
| Dart API | 保留全部方法、枚举和消息通道 | 无 |
| MethodChannel | 主通道与平台通道双注册 | 次级控制面(尺寸/位置)依赖显示能力 |
| OHOS 插件 | 注册、版本查询、权限与状态边界 | 真实悬浮窗显示 |
| Demo | API 26 模拟器启动和四个按钮验证 | overlayMain 内容渲染 |
| 文档 | README.OpenHarmony_CN.md、CHANGELOG | 无 |
鸿蒙当前没有等价的跨应用悬浮窗权限模型,后续如果系统开放“应用内窗口浮层”或小窗能力,可以先从“悬浮窗只在应用内显示”的降级方案开始接入,把 checkPermission 改为真实探测。当前实现保证控制面契约完整,调用方在鸿蒙上能获得一致且诚实的反馈。
十一、FAQ
Q1:为什么权限查询返回 false 而不是抛异常?
- 现象:
requestPermission和isPermissionGranted都返回false,调用不报错。 - 原因: 鸿蒙没有可申请的悬浮窗权限,返回
false是准确的状态描述。 - 解决方法: 调用方以
isPermissionGranted为准决定是否展示悬浮窗入口。 - 验证结果: 图 2 显示
false,页面状态正常。
Q2:调用 showOverlay 为什么没有报错也没有窗口?
- 现象:
showOverlay返回完成,屏幕上没有出现任何浮层。 - 原因: 鸿蒙端该方法为安全无操作,不实现真实显示。
- 解决方法: 依赖
isPermissionGranted的前置检查,避免无效调用路径。 - 验证结果: 图 3 显示调用完成后
isActive仍为false(图 4),行为自洽。
Q3:为什么示例工程移除了原有的复杂演示内容?
- 现象: 示例从聊天头像、动画演示收敛成四个按钮。
- 原因: 原示例依赖多个与悬浮窗能力无关的第三方库,鸿蒙工具链下没有对应实现。
- 解决方法: 保留最小验证面:权限、显示、状态、关闭四个入口。
- 验证结果:
flutter analyze与 signed HAP 构建均通过。
十二、总结
这次适配保留了 flutter_overlay_window 1.0.0 的双通道结构与全部控制方法,在 OHOS 侧完成注册、版本查询、权限查询、状态查询和关闭语义,并把示例工程收敛为可维护的最小验证页。Demo 通过 Flutter OH 3.47.4 构建成签名 HAP,并在 HarmonyOS API 26 模拟器上完成四个按钮的调用验证。
当前成果是“控制面完整、边界诚实”的适配基线。适配代码和说明都在 AtomGit 适配分支,复现时建议锁定 1.0.0-ohos.1 TAG。
十三、参考资料和仓库地址
- 适配仓库主页
- 适配分支
- 适配 TAG
- 最终提交 e494f97
- ArkTS MethodChannel 实现
- Dart 双通道与消息通道实现
- 鸿蒙适配说明
- pub.dev 包页面
- pub.dev 1.0.0 版本页
- 上游 GitHub 仓库
- 上游 LICENSE
- Flutter 官方插件与平台通道文档
- Flutter OH 鸿蒙 SDK 仓库
- HarmonyOS 开发者官方文档
欢迎加入CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter
更多推荐


所有评论(0)