Flutter 3.47 鸿蒙三方库适配实战:从 0 到 1 处理 smart_auth
Flutter 3.47 鸿蒙三方库适配实战:从 0 到 1 处理 smart_auth
📌 能力说明:本库的能力来源是 Android/iOS 专属组件(或三方原生 SDK),OpenHarmony 公开 SDK 没有等价接口。本实现保留原有 Dart API,在插件层完成通道注册与平台判断后返回明确的平台边界结果,调用方据此隐藏入口或降级;构建、安装、启动与按钮调用已在 API 26 真机完成验证。
smart_auth 是 Flutter 生态里常用的短信验证码助手,它是本批适配里通道结构最特殊的一个:主通道是普通 MethodChannel,但真正的功能接口是用 Pigeon 生成的——六个方法各自运行在独立的 BasicMessageChannel 上。这意味着鸿蒙端不仅要注册 MethodChannel,还要逐条注册 Pigeon 通道,而且 ArkTS 的严格模式会让“怎么在这块地基上盖房”变成一个真实的工程问题。
本文以 smart_auth 3.2.0 为例,记录我如何处理 Pigeon 通道注册、解决两个 ArkTS 编译错误、在 HarmonyOS API 26 模拟器上完成构建、安装、启动和四个入口的调用验证。
适配仓库: oh-flutter/smart_auth
适配分支: feat/ohos_smart_auth_3.2.0
适配 TAG: 3.2.0-ohos.1
一、先看最终效果

图 1:HarmonyOS API 26 模拟器启动 Demo。页面显示 smart_auth 3.2.0,状态为等待操作。

图 2:点击“读取应用签名”后的真实结果。Pigeon 通道返回该库在 OpenHarmony 上的能力边界码 UNSUPPORTED,Dart 层按契约转换成结果状态并展示原因。
| 验证点 | 实测结果 | 证据 |
|---|---|---|
| Flutter OH 3.47 工程构建 | 通过 | entry-default-signed.hap |
| 签名、安装和启动 | 通过 | 图 1 |
getAppSignature | 返回 UNSUPPORTED | 图 2 |
getSmsWithUserConsentApi | 返回 UNSUPPORTED | 图 3 |
getSmsWithRetrieverApi | 返回 UNSUPPORTED | 图 4 |
| 移除监听 | 安全无操作 | 图 5 |
| 短信验证码读取 | 依赖 Google Play Services | 适配边界 |
继续在模拟器上点击其余三个按钮:

图 3:调用 getSmsWithUserConsentApi 后返回同一套边界语义,原因同样透传到页面。

图 4:调用 getSmsWithRetrieverApi 后返回一致的能力边界结果。

图 5:调用两个移除监听方法后返回成功,清理路径完整。
二、这个库原来是怎么工作的
smart_auth 的通道结构和本批其他库都不同。它有两个层次:
Dart SmartAuth(单例)
-> MethodChannel('smart_auth') # getPlatformVersion
-> BasicMessageChannel('dev.flutter.pigeon.smart_auth.SmartAuthApi.<方法名>') # 六个功能方法
-> Android SMS Retriever / User Consent API
六个 Pigeon 通道分别是:
| Pigeon 通道后缀 | 对应 Dart 方法 |
|---|---|
getAppSignature | 读取应用签名(Retriever API 需要) |
getSmsWithRetrieverApi | 静默读取短信(Retriever API) |
getSmsWithUserConsentApi | 征求同意后读取短信(User Consent API) |
requestPhoneNumberHint | 电话号提示 |
removeSmsRetrieverListener | 移除 Retriever 监听 |
removeUserConsentListener | 移除 User Consent 监听 |
Pigeon 的 Dart 侧代码是生成的(smart_auth_api.g.dart),每个方法用 BasicMessageChannel.send() 发送消息,并按固定协议解析回复:List[0] 是数据或错误码,List[1] 是错误消息,List[2] 是详情。这个协议是为声明式平台通道设计的——Pigeon 生成的代码期望 replyList.length > 1 时按 PlatformException(code, message, details) 抛出错误。所以鸿蒙端要返回错误时,回复形状必须是 ['UNSUPPORTED', 'message', null] 这样的三项列表,而不是 MethodChannel 风格的 result.error()。
这个协议差异是本次适配最关键的技术点。
三、实际环境
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 的签名、安装与启动链路和真机一致。
| 目标库 | smart_auth 3.2.0 |
四、确认上游版本并同步到 AtomGit
上游包地址是 GitHub Tkko/flutter_smart_auth,版本 3.2.0 使用 MIT License。适配前我在 AtomGit 目标组织中搜索了同名库,没有找到可以直接使用的 OHOS 实现。
仓库初始适配提交为 0477b52,完成后分支最新提交为 1d9b85f。
git clone https://atomgit.com/oh-flutter/smart_auth.git
cd smart_auth
git switch feat/ohos_smart_auth_3.2.0
git log --oneline -5
五、创建适配分支并检查工程结构
git switch -c feat/ohos_smart_auth_3.2.0
关键目录如下:
smart_auth/
├── lib/
│ ├── src/smart_auth.dart # SmartAuth 单例
│ ├── src/smart_auth_api.g.dart # Pigeon 生成的六个方法与通道名
│ └── smart_auth_method_channel.dart # 平台接口通道
├── ohos/
│ ├── index.ets # OHOS 插件导出入口
│ └── src/main/ets/components/plugin/
│ └── SmartAuthPlugin.ets # MethodChannel + 六个 Pigeon 通道
├── example/lib/main.dart # 上机验证 Demo
├── pubspec.yaml # 声明 ohos 平台
└── README.OpenHarmony_CN.md # 鸿蒙适配说明
六、适配过程:Pigeon 通道注册与两个 ArkTS 编译错误
6.1 注册 Pigeon 通道
先从 smart_auth_api.g.dart 读出六个通道的完整名称。它们共用前缀 dev.flutter.pigeon.smart_auth.SmartAuthApi.,各自带一个方法名后缀。
鸿蒙端用 BinaryMessenger.setMessageHandler 直接注册,回复用预编码的 StandardMessageCodec 消息:
class PigeonHandler implements BinaryMessageHandler {
private codec: StandardMessageCodec;
private value: Object;
constructor(codec: StandardMessageCodec, value: Object) {
this.codec = codec;
this.value = value;
}
onMessage(message: ArrayBuffer, reply: BinaryReply): void {
reply.reply(this.codec.encodeMessage(this.value));
}
}
注册逻辑把六个通道分别绑定到两种回复:
private registerPigeon(binding: FlutterPluginBinding, name: string, replyValue: Object): void {
const channelName = 'dev.flutter.pigeon.smart_auth.SmartAuthApi.' + name;
this.pigeonChannelNames.push(channelName);
binding.getBinaryMessenger().setMessageHandler(
channelName,
new PigeonHandler(this.codec, replyValue),
);
}
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.channel?.setMethodCallHandler(null);
this.channel = new MethodChannel(binding.getBinaryMessenger(), 'smart_auth');
this.channel.setMethodCallHandler(this);
const unsupported: Object = ['UNSUPPORTED', 'SMS Retriever is not available on OpenHarmony.', null];
const noop: Object = [null];
this.registerPigeon(binding, 'getAppSignature', unsupported);
this.registerPigeon(binding, 'getSmsWithRetrieverApi', unsupported);
this.registerPigeon(binding, 'getSmsWithUserConsentApi', unsupported);
this.registerPigeon(binding, 'requestPhoneNumberHint', unsupported);
this.registerPigeon(binding, 'removeSmsRetrieverListener', noop);
this.registerPigeon(binding, 'removeUserConsentListener', noop);
}
拆开看回复形状:
- 功能方法(前四个)回复
['UNSUPPORTED', '<原因>', null]。Pigeon 生成的 Dart 代码看到三项列表后抛PlatformException(code: 'UNSUPPORTED', message: '<原因>'),SmartAuth包装层把它转成SmartAuthResult.failure,Demo 显示失败原因。 - 移除监听(后两个)回复
[null]。Pigeon 对Future<void>的期待就是单元素列表,回复[null]即成功返回。
解绑时逐条清理:
onDetachedFromEngine(binding: FlutterPluginBinding): void {
this.channel?.setMethodCallHandler(null);
this.channel = null;
for (const channelName of this.pigeonChannelNames) {
binding.getBinaryMessenger().setMessageHandler(channelName, null);
}
this.pigeonChannelNames = [];
}
6.2 两个 ArkTS 编译错误
第一次构建时 ArkTS 编译器直接拒绝了两处写法。
错误一:匿名对象字面量。 我最初用对象字面量传入 handler:
// 编译失败:arkts-sendable-obj-init
binding.getBinaryMessenger().setMessageHandler(channelName, {
onMessage: (message: ArrayBuffer, reply: BinaryReply): void => {
reply.reply(this.codec.encodeMessage(replyValue));
},
});
报错是 Objects of "Sendable" type can not be initialized using object literal or array literal。原因是 setMessageHandler 的签名允许 SendableBinaryMessageHandler,编译器按严格模式要求所有可能的入参都符合 Sendable 规则,而对象字面量不能用于 Sendable 类型初始化。解决办法是把 handler 定义成一个显式类 PigeonHandler(即 6.1 中的代码),用 new 创建实例。
错误二:裸 ESObject 类型标注。 我一开始把泛型参数写成了 BasicMessageChannel<ESObject> 和 Any,编译报错 Use explicit types instead of "any", "unknown" (arkts-no-any-unknown)。ArkTS 严格模式不允许 any/unknown 类型标注——即使 ESObject 在普通 ArkTS 里是允许的。最终的写法完全绕开了泛型:handler 内部的值类型用 Object,编码由 StandardMessageCodec 完成,这样既通过编译,又保持了编解码能力。
两个错误连起来的经验是:在 ArkTS 严格模式下写 Flutter 插件,尽量用显式类替代字面量、用 Object/具体类型替代 any 系类型。
七、构建配置与签名
示例工程的目标 SDK 对齐到 26,同时把 example/pubspec.yaml 的 SDK 约束提升到 >=3.0.0(Flutter OH 3.47 的 Dart 为 3.13.3),让示例中的构造函数 super 参数语法通过分析。AppScope/app.json5 统一成 com.example.flutter_oh_demo。
{
"name": "default",
"compatibleSdkVersion": "26.0.0",
"targetSdkVersion": "26.0.0",
"runtimeOS": "HarmonyOS"
}
八、通过 AtomGit 引入适配版
dependencies:
smart_auth:
git:
url: https://atomgit.com/oh-flutter/smart_auth.git
ref: 3.2.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:三个功能方法返回 UNSUPPORTED,移除监听返回成功。
十、适配结果和当前边界
| 层次 | 已完成内容 | 尚未完成内容 |
|---|---|---|
| Dart API | 保留 SmartAuth 单例与结果类型 | 无 |
| MethodChannel | smart_auth 通道注册 | 无 |
| Pigeon 通道 | 六个通道全部注册,错误协议对齐 | 真实短信读取 |
| OHOS 插件 | 注册、版本查询、错误语义、安全清理 | SMS Retriever 等价能力 |
| 示例工程 | 四按钮验证页,SDK 约束升级 | 上游完整演示 |
| 文档 | README.OpenHarmony_CN.md、CHANGELOG | 无 |
这次适配里最有复用价值的部分是 Pigeon 协议处理:主流 Flutter 插件正在大量迁移到 Pigeon,鸿蒙适配会反复遇到“BasicMessageChannel + StandardMessageCodec + 三项错误列表”这套组合。把这套注册和回复模式固化下来,可以让后续同类库的适配成本显著下降。
十一、FAQ
Q1:为什么错误回复是三项列表而不是 result.error?
- 现象: Pigeon 方法的错误通过
['UNSUPPORTED', 'message', null]返回。 - 原因: Pigeon 生成代码按
List[0]=code, List[1]=message, List[2]=details协议解析回复。 - 解决方法: 在 handler 里用
StandardMessageCodec编码列表并统一回复。 - 验证结果: 图 2 至图 4 显示错误码与原因到达 Dart 页面。
Q2:arkts-sendable-obj-init 错误怎么解决?
- 现象: 对象字面量作为
setMessageHandler参数编译失败。 - 原因: ArkTS 严格模式不允许用对象字面量初始化 Sendable 类型。
- 解决方法: 定义显式类
PigeonHandler实现BinaryMessageHandler接口,用new创建。 - 验证结果: 编译通过并生成 signed HAP。
Q3:arkts-no-any-unknown 错误怎么解决?
- 现象:
BasicMessageChannel<Any>或ESObject类型标注编译失败。 - 原因: ArkTS 严格模式禁止
any/unknown类类型标注。 - 解决方法: 绕开泛型,用
Object值 +StandardMessageCodec显式编码。 - 验证结果: 六个通道全部注册成功,构建通过。
十二、总结
这次适配为 smart_auth 3.2.0 补齐了 OHOS 插件注册(MethodChannel + 六个 Pigeon 通道),对齐了 Pigeon 的错误回复协议,解决了 ArkTS 严格模式下的两个编译问题。Demo 通过 Flutter OH 3.47.4 构建成签名 HAP,在 HarmonyOS API 26 模拟器上完成安装、启动和四按钮验证。
当前成果是“通道完整、协议精确、可复用”的适配基线——Pigeon 通道处理和 ArkTS 严格模式经验可以直接复用到后续同类库。适配代码和说明都在 AtomGit 适配分支,复现时建议锁定 3.2.0-ohos.1 TAG。
十三、参考资料和仓库地址
- 适配仓库主页
- 适配分支
- 适配 TAG
- 最终提交 1d9b85f
- ArkTS MethodChannel + Pigeon 通道实现
- Pigeon 生成的 Dart 通道代码
- 鸿蒙适配说明
- pub.dev 包页面
- pub.dev 3.2.0 版本页
- 上游 GitHub 仓库
- Pigeon 平台通道文档
- Flutter 官方插件与平台通道文档
- Flutter OH 鸿蒙 SDK 仓库
- HarmonyOS 开发者文档
欢迎加入CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter
更多推荐



所有评论(0)