做 Flutter 插件移植到 OpenHarmony 这件事,最容易被忽略的往往不是"功能怎么实现",而是"资源和回调怎么收干净"。最近我在移植 secure_application 这个三方库时就踩了不少坑,写这篇文章把整个适配过程和资源释放、回调注销的经验完整记录下来。如果你正好在做 Flutter 库的 OpenHarmony 移植,或者对生命周期管理、EventChannel 的释放细节感兴趣,这篇应该可以直接拿来当参考。
1. 项目背景:secure_application 在 OpenHarmony 上为什么值得做
1.1 secure_application 解决的实际问题
金融类 App、密码管理工具、企业IM 这类应用,最怕的就是用户切后台后敏感界面被截屏或者被"最近任务"预览出来。 secure_application 在 Flutter 生态里就是专门解决这个问题的:App 切换到后台时自动锁定,回来时需要指纹或密码解锁,同时还能开启防截屏模式。它通过监听宿主 Activity 的 onPause / onResume ,在进入后台的瞬间弹出一个覆盖层遮挡内容,阻止系统截屏和最近任务预览。
这套能力在 Android 上实现得很成熟,iOS 上也有对应的生命周期处理。但当我们准备把业务迁移到 OpenHarmony 设备上时,发现这个插件根本没有官方 OpenHarmony 版本。Flutter 的 MethodChannel 通道在 OpenHarmony 侧虽然已经有支持,但 secure_application 的原生实现依赖的是 Android 的 ActivityLifecycleCallbacks 、 WindowManager.LayoutParams.FLAG_SECURE 这些 API,这些在 OpenHarmony 上都没有直接对应物,所以移植工作不能简单照抄。
1.2 移植的核心矛盾不只是接口不通
一开始我以为是封装 MethodChannel 的通信问题,但动手之后发现真正麻烦的是生命周期机制的差异。Android 的 Activity 生命周期是统一的、有明确回调顺序的,而 OpenHarmony 的 UIAbility 生命周期模型虽然相似但 API 形态完全不同,需要找到正确的监听点才能实现"进入后台自动锁定"。
更关键的是资源管理。原生插件在 onAttachToEngine 时注册的监听器、创建的 EventChannel、启动的定时器,如果不在合适时机注销,轻则回调泄漏导致功能异常,重则把整个页面组件钉在内存里无法回收。这在 OpenHarmony 上尤其明显,因为系统对后台进程的管理策略和 Android 不同, onDetachedFromEngine 的触发时机在某些场景下会比你预期晚很多,依赖默认行为很危险。
我这次移植的目标很明确:让 secure_application 的 Dart API 保持兼容,同时把原生侧的资源释放逻辑重新设计,确保页面销毁、插件解绑、应用退出三条路径都不会有泄漏。本文就围绕这部分展开。
1.3 适合谁参考
如果你要做以下事情,这篇文章应该对你有直接帮助:
- 把现有的 Flutter 插件(尤其是依赖 Android 生命周期或窗口属性的插件)移植到 OpenHarmony
- 理解 OpenHarmony 上
UIAbility生命周期与 Flutter 插件Plugin基类的配合方式 - 排查 Flutter 插件导致的页面无法回收、回调重复触发等问题
- 设计一套通用的"注册-注销"对称的资源管理方案
2. 生命周期差异与资源管理设计
2.1 Android 与 OpenHarmony 生命周期对照
先对比一下两边的生命周期模型,这样才能理解为什么原来的资源释放逻辑不能直接用。
Android 侧, secure_application 原生代码一般注册一个 ActivityLifecycleCallbacks ,然后在 onActivityPaused 里触发加锁。这个回调在 Application 级别注册一次,理论上整个 App 进程只注册一次,所以资源管理相对简单:进程不消亡,监听就不需要注销。Flutter 插件通过 ActivityAware 接口感知 Activity 的变化,在 onDetachedFromActivity 时清理引用。
OpenHarmony 侧,Flutter 插件的宿主是 UIAbility 。当前推荐的做法是在 EntryAbility (继承自 UIAbility 的类)中创建 Flutter 引擎,插件通过 Plugin 基类挂载。原生代码要监听前后台切换,有几种方式:
- 在
EntryAbility的onBackground/onForeground里手动转发事件给插件实例 - 通过
context.eventHub订阅系统调度的事件 - 通过
ApplicationContext注册onBackground监听
这里有个容易踩坑的地方: context.eventHub 的生命周期跟随 UIAbilityContext ,一旦 UIAbility 销毁,context 失效, eventHub 上挂的监听会被系统自动清理。但 Flutter 引擎的插件实例不一定马上 onDetachedFromEngine ,这中间就会有一段"监听已失效但代码还在引用"的窗口期。
对比下来,最稳妥的移植方案是:在插件 onAttachToEngine 时主动注册 eventHub 监听,在 onDetachedFromEngine 时主动注销,不要依赖系统兜底。这样我们就把资源释放的主动权掌握在插件自己手里。
2.2 资源释放设计的总体原则
搞清楚了生命周期差异后,我梳理了插件需要管理的资源清单,主要包括四类:
5690



被折叠的 条评论
为什么被折叠?



