定制侠鸿蒙版攻坚纪要:白屏四层根因、构建链路梳理与分享带图修复

xiezitai · 2026-10-20 19:03 · 14 次阅读
踩坑

背景

定制侠(Flutter + OpenHarmony)鸿蒙端进入真机验证阶段。这一天的目标只有一个:把装到手机上的包从「白屏」救到「功能可用」。过程中踩了四个叠加的坑、返工三次,最终华为账号登录、微信登录、带图分享全部跑通。

环境:HarmonyOS 商用 SDK(API 26 编译,真机 HarmonyOS 6.1 / API 23),Flutter OHOS 3.41.9。


一、白屏:四层根因,逐一剥离

现象很典型——hap 安装成功、进程活着、界面纯白。这类问题难在「没有任何一条致命日志」,只能靠逐层剥离。

第 1 层:Dart 前端编译产物被旧 SDK 污染

.dart_tool/package_config.json 仍指向本机 D 盘旧 Flutter(Dart 3.6.2)解析出的依赖路径,产出的 kernel 字节码版本是 v120,而 F 盘新 SDK 引擎期望 v127。版本对不上,引擎加载失败。

处置:用 F 盘 SDK 重新 pub get,并在构建脚本里做 PATH 加固(新 SDK 路径前置),杜绝外部 flutter 命令再次污染。

第 2 层:构建中间目录的中文编码残留

工程路径含中文,构建中间目录里残留了 URL 编码后的路径片段,导致增量构建复用了错误产物。

处置:删掉 defaultRelease 中间目录重建。

第 3 层:ohpm 依赖模块里 BuildProfile 硬编码 DEBUG

ohpm 依赖模块中生成的 BuildProfile.ets 把构建模式写死为 DEBUG,release 构建下这些模块仍按 debug 分支执行。

处置:加 patch_buildprofile.py,构建前统一改写。

第 4 层(致命):release 包里混进了 debug 引擎

oh-package.json5 的 overrides 写死了 debug 引擎 har,libflutter.so 38.9MB。而 debug 引擎带 TRACING_CHECKS_NECESSARY 检查,要求启动时传 --enable-checked-mode(只有 flutter run 才会传),桌面/hdc 直接启动会被拒绝创建引擎,于是秒退白屏。

处置:加 switch_engine.py,按构建模式切换 native so(release 引擎 16.4MB),构建后自动还原。

排查抓手:白屏/秒退优先抓 hilog 里的 XComFlutterOHOS_Native 与 FlutterNapi 标签。

四层全部修完后产出 rel4(36.8MB),真机验证:登录页完整渲染、进程稳定。


二、为什么绕开 flutter 工具链

有个很自然的疑问:打包不是应该用 flutter build 吗,为什么要直连 hvigorw?

实测回答了这个问题。跑 flutter build app --release,在 assembleApp 阶段崩在两个点上:

  1. 00303231:The srcPath is not a relative path。fluwx/tobias 是 hosted 包,被解析回 D 盘旧缓存,Node 的 path.relative 跨盘无法相对化,产出绝对 srcPath,hvigor 拒收。
  2. 架构性原因:本工程是 TS builder(hvigorfile.ts 含 flutter-hvigor-plugin),flutter build 走 OhosHvigorBuilder 直连 hvigor,不执行 flutterBuildPre——不复制引擎 har、不装 ohpm 依赖。实测证据:ohos/har/ 未创建、oh-package.json5 未被改写、oh_modules 里仍是 debug so。也就是说标准命令对本工程零增益。

绕开是有代价的:正是 flutterBuildPre 里的 copyFlutterRuntime 负责按模式复制引擎 har,跳过它就埋下了上面第 4 层根因,switch_engine.py 本质上是在手工补回这一步。

长期最优解是把 ohpm/pub get 链路修好后回归 flutter build ohos,三个补丁脚本即可退役。


三、依赖 path 化:根治 00303231

既然 00303231 的根源是 hosted 包跨盘解析,就把它们改成 path 依赖,指向本地已配好鸿蒙实现的副本,重新 pub get。改完后 .flutter-plugins-dependencies 自动指向新路径,不再需要手工修补。

途中补了两个洞:

产出 rel6,真机验证通过,00303231 彻底消失。


四、ShareKit 带图分享:三次返工才找到的真根因

现象

定制页分享出去只有文字,图片丢了。

第一次误判

查 SDK 文档看到 SharedRecord 的约束「Either content or uri must be set」,判断是同一条 record 里同时塞了 uri 和 content,ShareKit 按文本处理、图片被丢弃。于是把 record 拆开——没修好。

决定性的线索

用户反馈:老版本是正常的,能分享出图片。

对比旧工程后发现了此前一直没注意的事实:两边根本不是同一份代码。

旧工程(能出图) 当前工程
share_plus 来源 git 依赖,鸿蒙适配 fork 分支 pub.dev hosted 版
ohos 实现 完整真 ShareKit 实现 stub 空壳

版本号都是 10.1.1,但实际代码天差地别。hosted 版的 ohos 实现是空壳,所以「去 stub」时等于自己重写了一份——这才是写法不同的来源,不是把旧版改坏了。

真根因:抓真机日志实锤

在插件里埋了 ERROR 级诊断后,日志给出决定性证据:

Share --> shareFiles
Share --> DZDIAG paths=1 | EXCEPTION={}
Share --> DZDIAG result paths=1 | EXCEPTION={} | uris=0
Share --> shareFiles uris count:0
HuaweiShare: DataUtils no valid uris

paths=1 之后立刻抛异常——取第一个路径时就炸了。原因是:MethodChannel 里 call.argument('paths') 从 Dart 侧过来的是普通 JS Array,不是签名上声明的 @ohos.util.List。为修复 forEach(async) 不等待的问题,取值被改成了 paths.get(i),而 Array 上没有 get,直接 TypeError,于是 uri 一个都没拿到,退化成纯文字。

旧版用 forEach 恰恰绕开了这个坑。

修复

产出 rel10,真机验证:分享正常带图。


五、沉淀下来的经验

排查方法

平台特性

工程协作


当前状态

功能 状态
启动渲染 通过
华为账号登录 通过
微信登录 通过
分享带图 通过
支付宝拉起 待真机验证

构建链路仍是直连 hvigorw 加三个补丁脚本(切换引擎、补丁 BuildProfile、切换签名)。待 ohpm/pub get 链路修好后可回归标准命令并让补丁脚本退役。

评论

还没有评论,登录后来说两句。