Flutter for OpenHarmony 扫一扫实战:从功能接入到踩坑修复全记录
这篇文章记录了我在一个 Flutter + OpenHarmony 项目中落地“扫一扫”功能的完整过程。hvigoruser_grant权限缺少reasonusedScene页面输入交互异常:弹层无法交互,随后出现崩溃最终方案是:先打通 Flutter 侧流程并提供降级路径,再按 OpenHarmony 规范补齐权限,最后用“无 controller 输入”规避平台兼容问题。先闭环再完善:先让用户
关键词:Flutter、OpenHarmony、MethodChannel、权限配置、扫码、问题排查
摘要
这篇文章记录了我在一个 Flutter + OpenHarmony 项目中落地“扫一扫”功能的完整过程。
不仅包含功能实现思路,还重点复盘了两个典型问题:
hvigor构建失败:user_grant权限缺少reason/usedScene- 页面输入交互异常:弹层无法交互,随后出现
TextEditingController disposed崩溃
最终方案是:先打通 Flutter 侧流程并提供降级路径,再按 OpenHarmony 规范补齐权限,最后用“无 controller 输入”规避平台兼容问题。
一、需求与目标
项目首页已有“扫一扫”按钮,但没有实际行为。
目标是实现一个“可上线联调”的版本:
- 点击“扫一扫”进入扫码流程
- 支持扫码结果展示与复制
- 原生扫码能力未接入时也能可用(降级输入)
- 保证 OpenHarmony 构建通过、页面交互稳定
二、实现策略:先闭环,再增强
我采用的是渐进式实现,而不是一开始就把所有端能力做满:
- 先打通入口与页面流转(用户可操作)
- 用
MethodChannel预留原生扫码接口(后续可无缝补齐) - 原生未接入时自动降级到手动输入(保障功能可用)
- 针对平台报错和交互问题逐个修复
这套策略的核心是:先确保业务流程可跑通,再处理平台细节与兼容性。
三、核心实现
1)首页接入扫一扫入口
在首页快捷功能区,把“扫一扫”按钮改为页面跳转:
- 文件:
lib/pages/home/home_page.dart - 行为:点击后
Navigator.push到ScanPage
_buildActionButton(
label: '扫一扫',
icon: Icons.qr_code_scanner,
onPressed: () => Navigator.of(
context,
).push(MaterialPageRoute(builder: (_) => const ScanPage())),
),
2)新增扫码页:统一处理扫码与降级
新增页面:
- 文件:
lib/pages/scan/scan_page.dart
页面能力包括:
- 调用
MethodChannel('app.scan/qr')的scan方法 - 拿到结果后展示在页面中
- 支持“一键复制结果”
- 如果抛出
MissingPluginException(原生未实现),自动进入手动输入流程
static const MethodChannel _scanChannel = MethodChannel('app.scan/qr');
......
Future<void> _startScan() async {
if (_isScanning) {
return;
}
setState(() {
_isScanning = true;
});
try {
final dynamic value = await _scanChannel.invokeMethod<dynamic>('scan');
final String scanned = (value ?? '').toString().trim();
if (!mounted) {
return;
}
if (scanned.isEmpty) {
_showMessage('未识别到有效内容');
} else {
setState(() {
_result = scanned;
});
}
} on MissingPluginException {
if (mounted) {
setState(() {
_isScanning = false;
});
}
await _fallbackManualScan();
return;
} on PlatformException catch (e) {
if (!mounted) {
return;
}
_showMessage('扫码失败: ${e.message ?? e.code}');
} finally {
if (mounted && _isScanning) {
setState(() {
_isScanning = false;
});
}
}
}
这样做的好处是:Flutter 侧功能完整,原生能力可后续增量接入。](https://i-blog.csdnimg.cn/direct/ec81f9c14ab94aed90ae4e51efa4c87a.png)
四、关键问题复盘
问题 1:hvigor 构建失败(00303218 Configuration Error)
现象
构建报错指出:
The reason and usedScene attributes are mandatory for user_grant permissions.
根因
我最初只添加了:
ohos.permission.CAMERA
但 OpenHarmony 对 user_grant 权限要求更严格,必须同时提供:
reasonusedScene
修复
在 module.json5 中补齐完整结构:
{
"name": "ohos.permission.CAMERA",
"reason": "$string:camera_permission_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
并在多语言资源中新增 camera_permission_reason:
ohos/entry/src/main/resources/base/element/string.jsonohos/entry/src/main/resources/zh_CN/element/string.jsonohos/entry/src/main/resources/en_US/element/string.json
问题 2:手动输入弹窗出现后无法交互
现象
降级路径使用 AlertDialog + TextField,弹窗出现后“看起来卡死,无法交互”。
第一轮修复
将弹窗输入改为独立页面输入(Navigator.push),规避弹层交互兼容问题。
问题 3:TextEditingController was used after being disposed
现象
改成独立页面后,又出现崩溃:
A TextEditingController was used after being disposed.
根因分析
在当前 Harmony 适配环境中,输入组件生命周期与 controller 回收时机存在兼容风险,导致 controller 在销毁后仍被引用。
最终修复
移除 TextEditingController,改为:
TextField.onChanged保存字符串状态- 点击“确定”直接提交字符串
这是一个“降复杂度换稳定性”的方案,实测有效规避该类崩溃。
五、最终效果
当前版本已经达到“可用且稳定”的阶段:
- 首页可进入扫一扫流程
- 原生扫码接口已预留(MethodChannel)
- 未接原生时可用手动输入完成流程
- 扫码结果可展示、可复制
- OpenHarmony 权限配置规范,构建错误已修复
- 输入交互和 controller disposed 问题已解决
六、这次实践的经验总结
- 先闭环再完善:先让用户能用,再做端能力增强
- 读懂平台约束:OpenHarmony 权限不仅是
name,user_grant要求完整结构 - 遇到弹层问题先页面化:弹窗异常时,独立页面通常更稳
- 输入崩溃优先降复杂度:必要时不要执着 controller,
onChanged足够解决问题 - 每次改动都做最小验证:格式化 + 局部 analyze,快速发现回归
七、后续可继续优化
- 接入 OpenHarmony 原生摄像头扫码实现,打通
app.scan/qr - 增加扫码类型识别(URL、纯文本、Wi-Fi、联系人等)
- 补充扫码历史记录与去重策略
- 完善权限拒绝时的引导与重试链路
结尾
如果你也在做 Flutter + OpenHarmony 适配,欢迎交流你遇到的权限或输入兼容问题。我可以再写一篇:如何把 MethodChannel 原生扫码能力完整接到 OHOS 侧(含端到端代码结构)。
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)