项目上线前,我有三周时间在OpenHarmony设备上把Flutter版的扫一扫功能从零搭到可用。真到动手才发现,扫码本身不难,难的是“Flutter for OpenHarmony”这个组合里每一个环节都可能出问题:相机插件有没有适配、帧流能不能拿到、渲染会不会花屏、编译链能不能过。这篇文章就是那次Flutter for OpenHarmony扫一扫实战的完整记录,从方案选型、功能接入到踩坑修复,尽量把每一处关键选择和报错原因都讲清楚,给正在做同样功能的人留一份参考。
适合谁来读?一是Flutter开发者准备把应用迁到OpenHarmony,需要了解相机和扫码能力怎么打通;二是OpenHarmony应用开发者在做扫一扫、AR识别、视频流处理这类功能,想参考一条能落地的实现路径;三是纯粹想看看跨平台框架在OpenHarmony上到底能跑到什么程度。无论哪种,这篇文章里出现的代码、配置和报错信息,都是可以直接拿来对照的。
1. 方案选型:扫一扫在OpenHarmony上的三条路线
1.1 三条路线对比与取舍逻辑
接到需求后,我没有一上来就写代码,而是先梳理了一遍实现方案。在OpenHarmony上做扫码,本质上就三条路。
第一条路,调用系统自带的扫码能力。OpenHarmony有自己的扫码服务,可以拉起系统扫码界面或者直接接入扫一扫控件。这条路集成最快,UI是系统统一的,不需要自己处理相机预览和图像解析。但问题也很明显:页面样式基本定死,没法做业务上要求的沉浸式圆角扫码框、闪光灯切换、相册识别这些定制功能,而且在部分设备上系统扫码服务是否有完整实现,取决于厂商版本,适配起来心里没底。
第二条路,直接复用在Android上已经很成熟的Flutter扫码插件,比如mobile_scanner、flutter_zxing。这条路如果Flutter的相机抽象层能正常工作,理论上最省事。但实际一测就发现,Flutter for OpenHarmony的camera相关插件生态远没有Android那么丰富,很多插件依赖底层Android Camera2 API或者iOS AVFoundation,鸿蒙上根本没有对应实现。像mobile_scanner这种直接依赖原生相机通道的插件,要么编译不过,要么运行起来黑屏,根本拿不到帧数据。
第三条路,自己拼:用适配了OpenHarmony的相机插件拿预览流和帧数据,再配合Zxing这类解码内核做识别。这条路前期成本高,但可控性最强,页面、识别策略、性能优化都能自己做,而且不依赖特定厂商的系统扫码服务。
三条路放在一起对比,其实选哪条不是看技术多炫,而是看需求约束:
| 方案 | 集成成本 | 可定制性 | 跨端一致性 | 性能风险 | 踩坑概率 |
|---|---|---|---|---|---|
| 系统扫码能力 | 低 | 低 | 差,受设备版本影响 | 中 | 中 |
| 现有Flutter扫码插件 | 中 | 中 | 差,依赖Android/iOS通道 | 高 | 高 |
| 自研相机帧流+解码 | 高 | 高 | 高,由Flutter层统一 | 可控 | 中偏高 |
1.2 为什么最终选了“相机帧流 + 自研扫码内核”的组合
我们的目标设备是几款跑OpenHarmony的国产硬件,屏占比、扫码框样式、连续扫码逻辑都有明确要求,而且业务后续要做跨端统一,Android和OpenHarmony的扫码行为必须保持一致。在这种情况下,第一条路直接被否了,第二条路试了两天后也被否了,主要卡在mobile_scanner的OpenHarmony适配不完整,编译时可以过,但运行到相机初始化阶段就崩,日志指向平台通道未实现。
最终选择第三条路,核心原因有两个。
第一个原因是跨端一致性。既然Flutter本身已经统一业务层,那相机预览和图像帧也应该尽量在Flutter层以下做统一抽象。OpenHarmony的相机能力通过ohos_camera系统API暴露,Flutter社区有针对OpenHarmony的camera_ohos插件,它实现了和Flutter官方camera插件一致的接口,这样上层业务可以不动,只替换底层实现。
第二个原因是可调试性。帧流数据拿到手里以后,识别逻辑走什么解码库、识别区域怎么裁剪、隔几帧识别一次,这些都可以在Dart层或者通过Platform Channel自己控制。出了问题能一步步排查,而不是在系统黑盒里猜。
当然,这条路也不是没有代价。最大的代价是工作量全部压在了自己身上:相机初始化、帧流转换、解码性能调优、内存控制,每一环都要自己兜底。后面正文会详细展开这些环节的具体实现。
1.3 需要的工程基础:Flutter SDK、OpenHarmony SDK、IDE
在动手之前,先把环境说清楚。Flutter for OpenHarmony目前不是跑在官方Flutter SDK上,而是跑在OpenHarmony SIG维护的Flutter分支上。我之前是用fvm管理Flutter多版本,这个习惯帮了大忙。直接用fvm安装OpenHarmony对应的Flutter分支版本,和本地已有的Android Flutter环境互不干扰,切换项目时自动切SDK,省去了一堆环境变量折腾。
具体版本组合我是这样固定的:
- fvm 管理Flutter SDK,版本锁定为OpenHarmony SIG推荐的flutter_flutter分支对应版本
- OpenHarmony SDK使用DevEco Studio配套的SDK,API版本按设备系统版本选择
- 开发工具用DevEco Studio做OpenHarmony工程侧的调试和签名打包,写Flutter逻辑还是用VS Code
还有一点要提醒,Windows环境下如果同时装了多套工具链,务必留意Visual Studio的C++工具集是否完整。后面踩坑章节我会专门讲这个编译报错,现在就记住:Flutter for OpenHarmony在Windows上的本地构建会调用C++编译链,VS装得不全,第一批报错里就有它。
另外工程结构上,OpenHarmony的Flutter应用和Android类似,也分平台壳工程和Dart业务层。大致是:
- flutter工程是业务主体,写Dart页面和扫码逻辑
- OpenHarmony工程是壳工程,负责生成hap包,包含EntryAbility和系统权限声明
- 两者通过Flutter引擎提供的Platform Channel互通
理解了这个结构,后面很多报错就能定位清楚:是Dart层的问题,还是OpenHarmony壳工程的问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心实现:从相机权限到识别成功的完整链路
2.1 权限声明与相机预览初始化
扫一扫的第一步,是先让相机能用。在OpenHarmony上,相机权限属于敏感权限,必须在module.json5里声明,并且在运行时动态申请。
module.json5里加权限:
json5复制{
module: {
name: "entry",
type: "entry",
requestPermissions: [
{
name: "ohos.permission.CAMERA",
reason: "需要相机权限用于扫一扫识别二维码",
usedScene: {
abilities: ["EntryAbility"],
when: "inuse"
}
}
]
}
}
这里有个细节容易漏:reason字段在部分版本上必填,不填的话自动检测过不了,应用装到真机上权限弹窗也可能不出现。usedScene建议按实际情况填inuse,不要为了省事填always,审核和上架阶段对后台摄像头权限的审查会比你想的严格。
动态权限申请的话,OpenHarmony壳工程里用Ability的requestPermissionsFromUser来实现。通常情况下,Flutter侧可以在进入扫码页时通过MethodChannel通知原生侧发起申请,也可以直接在壳工程的onWindowStageCreate里处理。我这边是放在扫码页进入时触发,这样权限弹窗出现的时机和用户操作是对应的。
相机初始化我用的插件是camera_ohos。它是OpenHarmony SIG维护的camera插件实现,接口基本对齐Flutter官方camera插件。
dart复制List<CameraDescription> cameras = await availableCameras();
CameraController controller = CameraController(
cameras[0],
ResolutionPreset.medium,
enableAudio: false,
);
await controller.initialize();
这里有几个要注意的点。
第一,ResolutionPreset不要一上来就选highest。扫码识别只需要在图像里找到二维码,分辨率和解码成功率并不是绝对正比,分辨率越高,帧处理耗时越大,反而拉低识别帧率。我最后用的是medium,既能稳定识别,又不会让CPU长时间飙高。
第二,enableAudio设为false。扫一扫场景不需要录制视频,开启音频会带来不必要的麦克风权限申请和性能损耗。
第三,initialize之后要确认预览纹理是否正常。这一步在OpenHarmony上特别容易出问题,我在后面踩坑章节会专门说渲染异常的问题。
2.2 帧流采集与解码内核接入
相机初始化完成,接下来是核心环节:拿帧流,识别二维码。
Flutter官方camera插件本身不支持一帧帧取图像,但camera_ohos提供了startImageStream方法。这个方法会把预览过程中的每一帧以CameraImage对象回调出来,帧数据格式通常是YUV420。
拿到YUV帧以后,不能直接扔给Zxing去解析。Zxing需要的输入要么是RGB格式的图像数组,要么是带颜色的位图。YUV转RGB这一步逃不掉。
帧转换我写了一个简单的纯Dart转换函数,处理YUV420P到RGBA的转换:
dart复制Uint8List yuvToRgba(CameraImage image) {
final yPlane = image.planes[0];
final uPlane = image.planes[1];
final vPlane = image.planes[2];
final yBytes = yPlane.bytes;
final uBytes = uPlane.bytes;
final vBytes = vPlane.bytes;
final uvRowStride = uPlane.bytesPerRow;
final uvPixelStride = uPlane.bytesPerPixel ?? 1;
final width = image.width;
final height = image.height;
final rgba = Uint8List(width * height * 4);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int yValue = yBytes[y * image.planes[0].bytesPerRow + x];
int uvIndex = (y >> 1) * uvRowStride + (x >> 1) * uvPixelStride;
int uValue = uBytes[uvIndex] - 128;
int vValue = vBytes[uvIndex] - 128;
int r = (yValue + (int)(1.402 * vValue)).clamp(0, 255);
int g = (yValue - (int)(0.344 * uValue) - (int)(0.714 * vValue)).clamp(0, 255);
int b = (yValue + (int)(1.772 * uValue)).clamp(0, 255);
int index = (y * width + x) * 4;
rgba[index] = r;
rgba[index + 1] = g;
rgba[index + 2] = b;
rgba[index + 3] = 255;
}
}
return rgba;
}
解码内核我用的是flutter_zxing,这个插件的底层是Zxing C++实现,通过FFI方式调用,不需要走JNI,所以在OpenHarmony上也能编译通过。接入后按帧解码:
dart复制final result = BarcodeDecoder.decodeBytes(
rgba,
width: image.width,
height: image.height,
format: BarcodeFormat.qrCode | BarcodeFormat.code128,
tryHarder: true,
);
每次回调都做全图转换和解码,性能压力不小。我做了三层优化。
第一,降低识别频率。图像回调是连续的,但不需要每帧都解码。我加了一个时间闸门,每隔150毫秒取一帧做解码,既保证识别速度,又避免CPU过载。
第二,只识别画面中心区域。扫码框在屏幕中间,帧数据可以先裁剪出中心矩形再做转换和解码。YUV裁剪比RGB裁剪省内存,所以先按坐标截取YUV区域,再送入转换函数。
第三,识别成功的帧立刻停止图像流。代码如下:
dart复制if (result != null) {
controller.stopImageStream();
// 回到主线程回调业务层
_callback(result.text);
}
stopImageStream之后,预览画面可能冻住。这里需要一个视觉反馈:弹一层蒙版或者显示“识别成功”的提示,等业务处理完成后再重新启动预览。否则用户会看到画面卡住,以为是崩溃了。
2.3 识别结果解析与业务桥接
扫一扫的终点不是拿到码内容,而是把码内容送进业务流程。在扫码页这个场景里,主要有两种码:二维码和条码。
二维码通常是文本内容,会有URL、JSON或者纯数字;条码一般是商品编码。我的做法是在Dart层定义统一的结果模型,再用MethodChannel回调给OpenHarmony原生侧,让原生业务根据码类型做分发。
dart复制class ScanResultModel {
final String rawText;
final BarcodeFormat format;
final int timeCostMs;
}
为什么不一刀切在Flutter层处理所有业务?因为当时项目里扫码结果要联动原生页面的跳转、蓝牙设备的绑定操作,这些动作涉及OpenHarmony侧能力,直接Dart层做反而不方便。把识别结果回传给原生侧,由壳工程统一分发,是比较顺的架构。
业务桥接还要考虑一个高频场景:扫描成功后快速跳转再返回,扫码页重新启动。这个过程要保证相机资源不泄漏。我在dispose里统一做了资源释放:
dart复制@override
void dispose() {
_controller.stopImageStream();
_controller.dispose();
super.dispose();
}
如果资源释放不及时,页面反复进入退出后会出现摄像头被占用的提示,实际就是上一次的CameraController没有正确释放。
3. 实操过程中的关键配置与工程落地
3.1 使用fvm管理OpenHarmony专用Flutter版本
环境这块我前面提了一嘴,现在详细展开。Flutter for OpenHarmony的SDK并不是通过flutter upgrade就能拉到的,它由OpenHarmony SIG维护,和官方SDK可能存在细微的API差异。如果机器上还跑着Android Flutter项目,直接把全局Flutter换成OpenHarmony版本,Android那边大概率会崩。
fvm是解决多版本共存最顺手的工具。安装fvm后,先添加OpenHarmony的Flutter SDK来源,然后在项目根目录固定版本:
bash复制fvm add 3.7.12-ohos
fvm use 3.7.12-ohos
fvm flutter doctor
项目里所有flutter命令都用fvm flutter开头,VS Code的Dart插件也支持读取.fvm/flutter_sdk路径,配置好之后IDE能自动识别当前项目的SDK版本。
为什么要花这个篇幅讲版本管理?因为在踩坑阶段,有几次报错我排查半天,最后发现是SDK版本和OpenHarmony SDK版本不匹配——引擎API对不上,相机插件编译不过。用fvm锁版本之后,至少环境是可复现的,出了问题能确定是代码问题还是环境问题。
3.2 工程创建与依赖配置
OpenHarmony的Flutter工程创建和Android不一样,没有直接一条flutter create就完事。我当时的做法是先用标准flutter create生成Dart侧工程,再在工程里加入ohos目录作为OpenHarmony壳工程,或者反过来用DevEco Studio创建空工程,再把Flutter模块嵌入进去。
推荐用后者,原因很简单:签名和hap构建流程在DevEco Studio里更完善,手工搭壳工程容易漏签名配置文件。
依赖配置上,pubspec.yaml需要加入相机和扫码相关依赖:
yaml复制dependencies:
flutter:
sdk: flutter
camera_ohos: ^0.6.0
flutter_zxing: ^2.0.0
注意这里的camera_ohos是OpenHarmony适配版本,pub.dev上搜到的同名包可能不是同一个,安装时最好确认包的来源仓库。我就踩过一次,装成了Android专用的老版本camera插件,结果运行时直接报CameraException。
3.3 构建参数与OpenHarmony侧签名配置
Flutter for OpenHarmony的构建流程最终产物是hap包。在DevEco Studio里配置好签名后,用命令行构建:
bash复制fvm flutter build hap --debug
签名是绕不开的坎。OpenHarmony应用安装到真机必须签名,如果没配签名或签名类型不对,hdc install会报INSTALL_PARSE_FAILED_BAD_SIGNATURE。签名配置在DevEco Studio的File -> Project Structure -> Signing Configs里,自动签名会用OpenHarmony的调试证书。
还有一点,如果设备是API 9以下,模块的兼容版本compileSdkVersion和targetSdkVersion要注意,API版本不匹配也会导致安装失败。尽量和真机系统版本保持一致,少一档兼容多一档,但跨度太大安检会卡。
3.4 模拟器与真机的差异处理
项目初期为了调试方便,用了OpenHarmony模拟器,结果差点被带偏。
模拟器上的OpenHarmony对相机的支持非常有限。x86架构的模拟器很多没有虚拟摄像头设备,有的虽然有,但摄像头数据走的不是真实硬件管线,startImageStream回调可能一直不来,或者帧率极低。如果一开始就在模拟器上调通扫码,到了真机上很可能出现截然相反的表现。
我的建议是:模拟器只用来验证Flutter页面和业务逻辑,相机和扫码相关功能尽早切换到真机联调。真机性能、散热、帧率、权限弹窗这些表现,模拟器完全模拟不出来。后面踩坑章节里x86模拟器相关的坑,就是这段时间攒下的经验。
4. 踩坑实录:接入期间遇到的典型问题与修复
4.1 Windows环境编译报错:unable to find suitable visual studio toolc
第一次在Windows上构建Flutter for OpenHarmony工程,编译到一半就停了,屏幕上一行醒目的报错:
text复制unable to find suitable visual studio toolc
当时第一反应是Flutter工具链没识别到Visual Studio。检查了VS安装路径、环境变量、flutter doctor的输出,全都没问题,但报错依旧。
后来发现,问题出在VS组件缺失。Flutter在Windows上构建本地插件时需要用到Visual Studio的C++生成工具,尤其是“使用C++的桌面开发”工作负载。我的机器上虽然装了VS,但当时为了方便只装了C#相关组件,没有完整安装C++工具链。补齐组件后重新打开VS Code,构建就过了。
这个坑很有代表性。很多Windows用户在Flutter环境配置时检查过Android Studio和SDK,但容易忽略VS C++工具链。Flutter for OpenHarmony的构建链路里有本地C++编译环节,VS组件不全会直接报这个错。解决方案一句话:安装VS时勾选“使用C++的桌面开发”,并确保包含MSVC编译器和Windows SDK。
4.2 Gradle插件声明冲突:you are applying flutter's main gradle plugin imperatively
第二个卡了两天的坑,来自构建系统。项目构建时Gradle抛出一段错误,核心信息是:
text复制you are applying flutter's main gradle plugin imperatively using the apply script method, which is not supported and will be removed
这个报错的起因是OpenHarmony壳工程里用了比较老的Gradle插件apply方式,而Flutter for OpenHarmony的构建插件已经切到了新的插件机制。两者叠加,Gradle认为你在用不推荐的方式重复应用Flutter主插件。
排查过程是这样的:先找到壳工程的build.gradle,看到里面有这样一行:
gradle复制apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
这是老式写法,需要改成在settings.gradle里通过pluginManagement引入。改完后再重新构建,这个报错就消失了。
这个坑的经验是:不要照抄老教程里的工程配置。Flutter的Gradle插件体系近年更新很快,老教程的apply from写法在OpenHarmony这种较新的适配分支上已经不受支持。遇到构建报错,优先看当前SDK版本自带的工程模板是怎么写的,直接对照修正。
4.3 OpenHarmony画面渲染异常与预览花屏
相机预览在真机上出现了两种渲染异常。第一种是初始化后黑屏,预览画面不出来;第二种是画面旋转角度不对,竖屏界面显示横屏画面,而且有拉伸。
先解决黑屏。日志显示相机初始化成功,但没有预览纹理输出。排查camera_ohos的源码后发现,预览需要通过Texture Widget承载,而我在页面里没有正确设置Texture Widget的尺寸和比例,导致纹理创建成功后无法上屏。
修复方法:拿到CameraController的previewWidget,用AspectRatio约束宽高比,并确保Texture Widget在页面树中存在:
dart复制controller.initialize().then((_) {
setState(() {});
}).catchError((e) {
debugPrint("预览初始化失败: $e");
});
显示时用:
dart复制if (controller.value.isInitialized) {
AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: CameraPreview(controller),
)
}
第二个旋转角度问题,是OpenHarmony摄像头传感器方向和UI方向不一致导致的。在Android上可以用SensorOrientation做校正,camera_ohos虽然接口对齐了官方camera插件,但部分版本的orientation计算并不准确。我最后是在帧转换时做了旋转处理,把YUV数据按设备当前方向转成正确角度,再送解码。这里写了一个简单的旋转函数,按90度步进处理:
dart复制Uint8List rotateYuv90(Uint8List src, int width, int height) {
// 按Y,U,V分量分别旋转,旋转后宽高互换
}
具体旋转逻辑不展开贴代码了,核心是别依赖插件把方向改好,自己兜底处理更稳。
4.4 x86模拟器上无法打开相机的问题
模拟器调试期间遇到了一个让人哭笑不得的问题:所有代码正常,但startImageStream一直不回调,相机预览区域一片黑。
检查后确认是x86模拟器对相机模拟的支持问题。模拟器里的摄像头设备分两种:一种是模拟的虚拟摄像头,另一种是透传宿主机的摄像头。OpenHarmony的x86模拟器里虚拟摄像头的实现并不完整,部分镜像没有对应的Camera HAL实现,导致相机服务启动失败。
排查思路:通过hdc shell进入设备,查看相机服务日志。反复重启模拟器、切换镜像版本,最终确认不是代码问题,而是模拟器环境不支持。解决方式也就明确了——真机联调。
如果非要在模拟器上看效果,可以试试用arm64镜像的模拟器,但速度会慢到怀疑人生,不推荐。指纹、相机、传感器这类强依赖硬件的功能,在模拟器上调通是运气,调不通是常态,不要在这上面死磕。
5. 常见问题速查与调优建议
5.1 问题速查表
把整个接入过程遇到的问题整理成表格,方便以后遇到类似报错快速定位:
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 构建报unable to find suitable visual studio toolc | VS缺少C++桌面开发工具 | 安装VS时勾选C++生成工具和Windows SDK |
| Gradle报flutter main gradle plugin imperative | 壳工程使用旧的apply from方式 | 改为settings.gradle的pluginManagement方式 |
| 相机初始化成功但预览黑屏 | Texture Widget未正确设置或未挂载 | 用AspectRatio包裹CameraPreview并确保setState刷新 |
| 预览画面方向不对或拉伸 | 传感器方向与UI方向不一致 | 自研YUV旋转函数校正方向 |
| startImageStream一直不回调 | x86模拟器Camera HAL缺失 | 放弃模拟器,切换到真机调试 |
| 解不出码或识别率低 | 分辨率过高或过低、光线不足 | 使用medium分辨率,调整扫描区域,tryHarder开启 |
| 反复进入退出后摄像头占用 | CameraController未释放 | 在dispose里stopImageStream和dispose |
5.2 提高扫码成功率的几个细节
功能跑通之后,我花了两天时间做识别率和体验的调优,有几个细节很值得分享。
第一个是扫描区域裁剪。在Zxing解码时,如果把整帧图像都送入解码器,背景复杂时会出现误识别或识别慢的问题。按扫码框的区域裁剪后再解码,识别率和速度都会有明显提升。裁剪的坐标要从帧坐标系换算到扫码框在预览流中的位置,这一步需要根据相机预览的显示尺寸和实际帧尺寸换算比例。
第二个是多码场景的防抖。默认情况下,如果画面里同时出现多个二维码,每帧识别出来的结果可能不同,页面会来回跳。我在业务层加了一个结果确认机制:连续两次识别出同一个结果才认为是有效码,有效后短时间内不再接受新结果。这个机制尤其适合仓库盘点、图书借阅这类密集扫码场景。
第三个是闪光灯控制。camera_ohos接口里对闪光灯的支持不是所有设备都一致。我做了能力探测,如果设备不支持闪光灯控制,就不显示闪光灯按钮,避免用户点击无响应造成体验问题。
扫码性能这块还要提醒一点:不要在decode回调里做耗时操作。Zxing解码本身就在工作线程执行,结果回到Dart层后只做UI提示和结果分发。如果扫码结果的业务处理很重,比如查询库存、调接口,应该放到独立队列,不要阻塞扫码线程,否则会出现扫码成功到界面反馈延迟很长的问题。
5.3 后续可以继续扩展的方向
这个扫一扫模块现在的状态是可用的,但它还有几个可以继续深挖的方向。
一是支持更多码制。目前我接入了QR Code和Code128,实际业务里可能还有Data Matrix、EAN-13、PDF417这些需求。flutter_zxing底层Zxing是支持这些码制的,直接在format参数里加枚举值就可以,工作量不大。
二是识别能力前移到OpenHarmony原生侧。目前的实现是YUV帧从Flutter层走一遍转换再解码,整个过程在Dart和FFI之间传递图像数据。如果后续扫码场景变得很重,比如要同时识别多个码或者加增强现实效果,可以考虑把帧流处理和识别逻辑整体下沉到OpenHarmony侧,用C++实现,Flutter层只负责展示结果。
三是接入图像流分析管道。扫一扫只是相机帧流的一个应用场景。同一套相机帧流能力,可以继续做边缘检测、人脸追踪、文档扫描这些功能。现在我实现的一套帧流采集和转换工具,在项目里已经被复用到了取景框实时测距的模块,扩展性比想象中好。
四是用CameraX还是新相机架构的问题。如果设备升级到OpenHarmony的新版本,相机服务和Flutter插件适配情况可能会变化,到时候要留意camera_ohos的更新记录,提前做好接口升级的准备。
从我个人的经验来说,这次Flutter for OpenHarmony扫一扫最值钱的部分不是最后跑通的代码,而是过程中建立的排查思路。平台适配类问题,多数时候不是你代码写得不对,而是框架层、插件层、系统能力层之间的缝隙没有对齐。遇到问题时,先确认问题出现在哪一层,再动手改,效率会高很多。最后再给一个小建议:如果你只是做一个内部演示用的扫码,走系统扫码能力最快;但如果是做面向用户、要长期迭代的真正产品功能,还是老老实实把帧流和解码链路握在自己手里。一次投入,后面所有扩展都顺了。
