Flutter 3.47 鸿蒙三方库适配实战:从 0 到 1 处理 otp_autofill
短信验证码自动填充是移动端登录流程里的高频优化点。otp_autofill 的实现完全建立在 Android 的两套系统机制上:SMS Retriever API(后台静默读取格式化短信)和 User Consent API(弹窗征求用户同意后读取)。它还会组合 otp_surfstudio 通道提供电话号提示和签名获取。把这条库带到鸿蒙时,适配的边界从第一步就确定了:SMS Retriever 是 Google Play Services 的组件,鸿蒙没有等价机制。
本文以 otp_autofill 4.1.0 为例,记录我如何在鸿蒙端注册双通道、把 Android 专属方法映射为明确的 UNSUPPORTED 语义,并在 HarmonyOS API 26 模拟器上完成构建、安装、启动和三个入口的调用验证。
适配仓库: oh-flutter/otp_autofill
适配分支: feat/ohos_otp_autofill_4.1.0
适配 TAG: 4.1.0-ohos.1
一、先看最终效果
图 1:HarmonyOS API 26 模拟器启动 Demo。页面显示插件返回的 OpenHarmony 3.47.4,状态为等待操作。
图 2:点击“读取应用签名”后的真实结果。ArkTS 返回 UNSUPPORTED,Dart 层捕获后展示错误。
| 验证点 | 实测结果 | 证据 |
|---|---|---|
| Flutter OH 3.47 工程构建 | 通过 | entry-default-signed.hap |
| 签名、安装和启动 | 通过 | 图 1 |
getPlatformVersion | 返回 OpenHarmony 3.47.4 | 图 1 |
getAppSignature | 返回 UNSUPPORTED | 图 2 |
startListenRetriever | 返回 UNSUPPORTED | 图 3 |
stopListenForCode | 安全无操作 | 图 4 |
| 短信自动填充 | 依赖 Google Play Services | 适配边界 |
继续在模拟器上点击其余两个按钮:
图 3:调用 startListenRetriever 后返回同一套 UNSUPPORTED 语义。
图 4:调用 stopListenForCode 安全完成,清理路径完整。
二、这个库原来是怎么工作的
otp_autofill 的 Dart 层分两半:OTPInteractor 直接使用名为 otp_surfstudio 的 MethodChannel;插件注册部分使用 otp_autofill 通道。
Dart OTPInteractor
-> MethodChannel('otp_surfstudio') # getAppSignature / startListenRetriever 等
-> Android SMS Retriever / User Consent
Dart 插件平台接口
-> MethodChannel('otp_autofill') # getPlatformVersion
读源码时有个重要细节:OTPInteractor 的每个 Android 专属方法都先做平台判断,非 Android 平台直接抛 UnsupportedPlatform:
Future<String?> getAppSignature() async {
if (_platform.isAndroid) {
return _channel.invokeMethod<String>(getAppSignatureMethod);
} else {
throw UnsupportedPlatform();
}
}
这个设计对我们很有用:它意味着鸿蒙端不需要在 ArkTS 层拦截这些方法——Dart 层自己就会先拦住。那为什么还要在 ArkTS 里注册 otp_surfstudio 通道并实现同样的错误分支?两个原因:一是 iOS 平台上 startListenUserConsent 这类流式方法不走平台判断,会直接打到通道;二是随着上游代码演进,平台判断可能被重构,通道层有兜底更稳。
stopListenForCode 是唯一一个不带平台判断的方法,它在所有平台都会走通道,所以鸿蒙端把它做成安全无操作。
三、实际环境
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 的签名、安装与启动链路和真机一致。
| 目标库 | otp_autofill 4.1.0 |
四、确认上游版本并同步到 AtomGit
上游包地址是 GitHub surfstudio/flutter-otp-autofill,版本 4.1.0 使用 Apache License 2.0。适配前我在 AtomGit 目标组织中搜索了同名库,没有找到可以直接使用的 OHOS 实现。
仓库初始适配提交为 7ae862f,完成后分支最新提交为 1165d0a。
git clone https://atomgit.com/oh-flutter/otp_autofill.git
cd otp_autofill
git switch feat/ohos_otp_autofill_4.1.0
git log --oneline -5
五、创建适配分支并检查工程结构
git switch -c feat/ohos_otp_autofill_4.1.0
关键目录如下:
otp_autofill/
├── lib/
│ ├── src/otp_interactor.dart # OTPSurfstudio 通道与平台判断
│ ├── src/otp_text_edit_controller.dart # OTP 输入控制器
│ └── otp_autofill_platform_interface.dart
├── ohos/
│ ├── index.ets # OHOS 插件导出入口
│ └── src/main/ets/components/plugin/
│ └── OtpAutofillPlugin.ets # 双通道 MethodChannel 实现
├── example/lib/main.dart # 上机验证 Demo
├── pubspec.yaml # 声明 ohos 平台
└── README.OpenHarmony_CN.md # 鸿蒙适配说明
六、适配过程:双通道注册与三组语义
OHOS 插件同时注册 otp_autofill 和 otp_surfstudio 两条通道:
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.channel?.setMethodCallHandler(null);
this.channel = new MethodChannel(binding.getBinaryMessenger(), 'otp_autofill');
this.channel.setMethodCallHandler(this);
this.interactorChannel?.setMethodCallHandler(null);
this.interactorChannel = new MethodChannel(binding.getBinaryMessenger(), 'otp_surfstudio');
this.interactorChannel.setMethodCallHandler(this);
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
this.channel?.setMethodCallHandler(null);
this.channel = null;
this.interactorChannel?.setMethodCallHandler(null);
this.interactorChannel = null;
}
方法映射分三组:
| Dart 方法 | 通道 | OHOS 本次策略 |
|---|---|---|
getPlatformVersion | otp_autofill | 返回 OpenHarmony 3.47.4 |
getTelephoneHint / startListenUserConsent / startListenRetriever / getAppSignature | otp_surfstudio | 返回 UNSUPPORTED 错误 |
stopListenForCode | otp_surfstudio | 安全无操作 |
onMethodCall(call: MethodCall, result: MethodResult): void {
switch (call.method) {
case 'getPlatformVersion':
result.success('OpenHarmony 3.47.4');
return;
case 'getTelephoneHint':
case 'startListenUserConsent':
case 'startListenRetriever':
case 'getAppSignature':
result.error(
'UNSUPPORTED',
'SMS Retriever and User Consent APIs are not available on OpenHarmony.',
null,
);
return;
case 'stopListenForCode':
result.success(null);
return;
default:
result.notImplemented();
}
}
这四个方法共用一个错误分支是刻意的:它们的能力来源是同一套 Android 机制,能力不存在时用同一条消息说明原因,业务侧只需要匹配一次 UNSUPPORTED 就能覆盖全部入口。
示例工程方面,上游示例使用 SampleStrategy 和 OTPTextEditController 做完整演示;我在改造时保留 OTPTextEditController 的核心用法(它内部会调用 startListenUserConsent),把页面收敛成三个按钮:签名、Retriever 监听、停止监听。示例的 dev_dependencies 里还补上了缺失的 flutter_test 声明,让 flutter analyze 干净通过。
七、构建配置与签名
示例工程的目标 SDK 对齐到 26,AppScope/app.json5 统一成 com.example.flutter_oh_demo,与 DevEco 调试签名对应。
{
"name": "default",
"compatibleSdkVersion": "26.0.0",
"targetSdkVersion": "26.0.0",
"runtimeOS": "HarmonyOS"
}
八、通过 AtomGit 引入适配版
dependencies:
otp_autofill:
git:
url: https://atomgit.com/oh-flutter/otp_autofill.git
ref: 4.1.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 至图 4:签名与 Retriever 监听返回 UNSUPPORTED,停止监听安全完成。
十、适配结果和当前边界
| 层次 | 已完成内容 | 尚未完成内容 |
|---|---|---|
| Dart API | 保留 OTPInteractor 与控制器 | 无 |
| MethodChannel | otp_autofill 与 otp_surfstudio 双注册 | 无 |
| OHOS 插件 | 注册、版本查询、四方法错误语义、安全停止 | 真实验证码读取 |
| 示例工程 | 三按钮验证页,补齐 flutter_test 依赖 | 上游完整演示 |
| 文档 | README.OpenHarmony_CN.md、CHANGELOG | 无 |
鸿蒙侧如果要实现验证码填充,替代路径可能是系统级的验证码建议能力(例如输入法或系统组件提供的短信验证码填充),而不是复刻 SMS Retriever。当前实现保证契约稳定:应用在鸿蒙上启动正常,所有 Android 专属调用给出可识别的 UNSUPPORTED,清理调用不中断。
十一、FAQ
Q1:为什么 Dart 已经做了平台判断,还要注册两个通道?
- 现象:
OTPInteractor在非 Android 平台抛UnsupportedPlatform,看起来鸿蒙端不需要任何实现。 - 原因: 上游只有部分方法带平台判断,且平台判断可能随版本变化;通道层兜底更稳。
- 解决方法: 注册
otp_surfstudio与otp_autofill,并在通道层实现同语义的UNSUPPORTED。 - 验证结果: 图 2 与图 3 显示错误从 ArkTS 经通道到达 Dart 页面。
Q2:stopListenForCode 为什么可以直接返回成功?
- 现象: 没有启动监听,停止监听也不报错。
- 原因: 它是唯一无平台判断的方法,出现在
dispose等清理路径里。 - 解决方法: 安全无操作保证清理链不中断。
- 验证结果: 图 4 显示调用完成。
Q3:为什么示例要去掉 SampleStrategy?
- 现象: 示例从带策略类的完整演示收敛成三个按钮。
- 原因: 策略类只在真实收到短信时有意义,鸿蒙端收不到短信,保留它会造成误导。
- 解决方法: 用最小验证面覆盖通道与错误语义。
- 验证结果: analyze 与 signed HAP 构建均通过。
十二、总结
这次适配为 otp_autofill 4.1.0 补齐了 OHOS 插件注册(双通道),把 Android 专属入口映射为统一的 UNSUPPORTED 语义,保留 stopListenForCode 的安全无操作。Demo 通过 Flutter OH 3.47.4 构建成签名 HAP,在 HarmonyOS API 26 模拟器上完成安装、启动和调用验证。
当前成果是“契约完整、语义诚实”的适配基线。适配代码和说明都在 AtomGit 适配分支,复现时建议锁定 4.1.0-ohos.1 TAG。
十三、参考资料和仓库地址
- 适配仓库主页
- 适配分支
- 适配 TAG
- 最终提交 1165d0a
- ArkTS 双通道实现
- Dart OTPInteractor
- 鸿蒙适配说明
- pub.dev 包页面
- pub.dev 4.1.0 版本页
- 上游 GitHub 仓库
- Flutter 官方插件与平台通道文档
- Flutter OH 鸿蒙 SDK 仓库
- HarmonyOS 开发者官方文档
欢迎加入CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter
更多推荐


所有评论(0)