ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Flutter三方库鸿蒙化:用pub_release构建跨平台自动化发布管线

Flutter三方库鸿蒙化:用pub_release构建跨平台自动化发布管线 鸿蒙生态的这波浪潮来得比很多人想象中要快。我自己的 Flutter 三方库从纯 Android/iOS 市场转向鸿蒙适配时最先被卡住的居然不是 PlatformView 兼容也不是 arkts 语法改造而是一件看起来特别不起眼的事——包怎么发。以前维护一个 Flutter 库发版只需要在 pub.dev 上跑一遍flutter pub publish加上手写 CHANGELOG、手动打 tag顶多十分钟。鸿蒙化之后同一个库可能要同时面向 pub.dev、ohpm 仓库、甚至私有 Git 依赖三个出口版本号要同步、产物要验证、tag 要一致手动操作一次就想骂人。最后我把这套流程全部交给了 Flutter 三方库发布工具 pub_release并针对鸿蒙场景做了完整的适配改造才算真正把“研发生命线”这个词从口号变成了日常。这篇指南就是把整个适配过程和踩过的坑完整记录下来给同样在 Flutter 鸿蒙化路上挣扎的库维护者一个可以照抄的作业。1. 鸿蒙时代的包发布困境手动发版已经撑不住了如果只是给一个项目发版本手动操作其实没那么致命。但三方库维护者的情况完全不同你面对的不是一个 app而是几十个甚至上百个下游项目。任何一个库版本发布不规范影响到的是整个依赖链条。1.1 一个典型的手动发布事故我印象很深的一次事故是这样的某天下午我准备发一个 Flutter 工具库的 1.3.0 版本修复了三个 bug。手动改了pubspec.yaml的版本号写了一段 CHANGELOG然后执行flutter pub publish一切看起来都很顺利。两小时后有人反馈依赖锁定失败——他在pubspec.lock里锁定的 1.3.0 解析不到。我查了半天发现 git tag 没有打而且版本号在pubspec.yaml里和 CHANGELOG 头部的版本号不一致。更尴尬的是鸿蒙那边的适配仓还在等 1.3.0 的 ohpm 包而oh-package.json5里写的还是 1.2.1。当时我的感觉就是发布流程里任何一个环节只要靠人工记忆就一定会出错。这不是责任心的问题是人脑本身不可靠。而鸿蒙化之后发布链路从一条变成三条手动操作从“有点麻烦”直接升级为“完全不可行”。1.2 鸿蒙生态让发布这件事复杂了不止一倍先理清一个背景。Flutter 在鸿蒙上运行靠的是鸿蒙侧对 Flutter 引擎的适配层而不是 Flutter 官方直接支持。这意味着三方库要真正跑在鸿蒙上通常会涉及两到三层依赖关系Dart 层代码这部分照常发布到 pub.dev供所有 Flutter 项目使用。鸿蒙原生层能力如果库里有原生实现或者在鸿蒙上要依赖特定的鸿蒙 SDK 能力就可能需要发布到 ohpmOpenHarmony 三方库中心。内部分支或灰度版本很多时候不会立刻公开发布而是先用 Git 依赖让合作方验证。同一个版本要在这些出口之间保持版本号同步、内容一致。现实是这三种位置的版本校验规则并不一样pub.dev 看的是pubspec.yamlohpm 看的是oh-package.json5Git 依赖看的是 tag。任何一个没同步下游就会收到错配的组合。这就是为什么我说鸿蒙化适配的第一步不是写代码而是先把发布管线管起来。管好了后面所有迭代都是顺的管不好你会在每次发版时消耗大量精力在低级错误上。2. pub_release 的工作机制一条标准化的包发布流水线pub_release 是 Dart/Flutter 生态里的一个命令行发布工具核心思路是把“改版本号—更新 CHANGELOG—打 tag—执行发布”这条链路串成一条自动化的流水线。它不是我写的工具但我深度使用之后认为它的设计思路非常适合作为鸿蒙化发布管线的基础。2.1 从 git 历史自动推导版本增量pub_release 最核心的设计是让版本号不再依赖人工决策而是从 git 提交信息里自动推导。它遵循的是 Conventional Commits 规范也就是提交信息要写成feat: xxx、fix: xxx这样的格式。这套规则的映射逻辑很直观提交类型版本变化示例fixpatch 版本 11.2.0 → 1.2.1featminor 版本 11.2.0 → 1.3.0BREAKING CHANGEmajor 版本 11.2.0 → 2.0.0docs/refactor/test不发版—我第一次看到这个设计时觉得有点小题大做但真正用起来才发现它解决了一个根本问题版本号应该有逻辑依据而不是“我觉得这次改动不小”。当你维护的库跨了 Android、iOS、鸿蒙三个平台时“觉得”是最靠不住的东西。2.2 自动维护 CHANGELOG 与 git tag版本号推导出来之后pub_release 会按提交类型对 commit 进行归类自动生成 CHANGELOG 段落。feat和fix会列进去docs这类不会。这样做的好处是 CHANGELOG 不会漏项也不会出现“忘了写某个改动”这种低级问题。同时它会创建对应的 git tag。tag 的命名默认是v版本号这种形式。这一步看着简单但它卡住了整个版本追溯能力下游用 Git 依赖锁定版本靠的就是 tag出问题要回滚也得知道哪个 commit 对应哪个版本。2.3 最终发布动作与验证工具链的最后一步才是执行flutter pub publish。发布完成后它会做基本的结果检查确认包确实上传到了远端然后打印一个发布摘要把本次版本号、CHANGELOG 位置、tag 信息都列出来。值得注意的是pub_release 提供了 dry run 能力。发布前可以预演一遍看它会推导出什么版本号、生成什么 CHANGELOG确认无误后再真正执行。对于鸿蒙化适配的场景dry run 几乎是救命功能因为多目标发布下的错误成本太高了提前看一眼生成结果能拦截至少一半问题。3. 鸿蒙化适配的关键关节不是改一行配置那么简单标准用法下 pub_release 只处理 pub.dev 的发布链路。鸿蒙化适配要做的是把它从“单点发布工具”扩展成“多出口发布总闸”。我在改造过程中主要动了四个地方。3.1 依赖源切换pub.dev、ohpm 与 Git 依赖怎么共存鸿蒙三方库在实际情况中经常是“一个库三个出口”。我的处理原则是分清楚每个出口的定位pub.dev承载通用 Dart/Flutter 能力是所有平台共用的代码主体。ohpm承载鸿蒙原生适配能力例如用到了鸿蒙的 Ability、Service 能力封装或者对鸿蒙 SDK 做了桥接。Git 依赖用于灰度验证和内部分发不进公共仓库。这样划分的好处是职责清晰。发布管线的核心逻辑变成pub_release 负责触发和版本决策执行完 pub.dev 发布后自动同步触发 ohpm 上传和 Git tag 推送。相当于用 pub_release 作为“主调度器”其他出口作为“联动节点”。这里有个细节需要注意pub.dev 的版本号规则和 ohpm 的版本号规则虽然有细微差别ohpm 要求严格遵守 semver不允许1.0.01这种 build metadata 写法但只要你坚持纯 semver 格式就不会踩到。所以我在适配时把版本号硬性规范成了不携带后缀的纯三位段格式。3.2 平台声明与目录结构的鸿蒙化补充要让 pub_release 生成的包在鸿蒙侧可用光有 Dart 代码不够。鸿蒙适配层的 Flutter 插件识别机制需要你在包里补上对应的鸿蒙平台实现。现在的标准做法是在插件根目录下维护harmonyos目录命名按鸿蒙适配层的约定来里面放oh-package.json5、hvigorfile.ts以及实际的 arkts 桥接代码。然后在 pubspec.yaml 的 flutter 插件声明中通过pluginClass注册鸿蒙侧的入口。这个步骤必须在发布管线的验证阶段被检查到否则你发布出去的包在 pub.dev 上看起来没问题但鸿蒙工程一依赖就编译失败。适配之后我把“检查 harmonyos 目录是否存在且包含 oh-package.json5”写成了发布前置条件不满足就直接中断发布。3.3 双仓库版本同步策略这个是我认为整个鸿蒙化适配里最容易忽视、也最容易出问题的点。pub.dev 的包和 ohpm 的包虽然是同一个逻辑版本但它们是两套独立的上传记录。如果脚本只负责发布 pub.dev而 ohpm 那边靠手动改版本号早晚会出现两边版本对不上的情况。我的解法是建立一个“单版本源”机制在发布管线入口处维护一个版本配置文件pub_release 推导出最终版本号后把pubspec.yaml、oh-package.json5里的版本号统一用这个最终值覆盖。这样不管后续发布到哪个仓库版本号永远来自同一个计算结果。同步脚本的核心逻辑就是三个步骤读 pub_release 的输出版本号、用该值重写两个 manifest、做一次 diff 确认没有意外改动。这样双仓库的版本一致性并不是靠“记得”而是靠机制保证。3.4 发布前必须过鸿蒙构建验证以前发版前我会跑一遍flutter test和flutter analyze感觉已经够保险了。但鸿蒙化之后这个验证强度远远不够。Dart 代码能编译不代表鸿蒙侧的构建能过。适配时我在发布链路里加入了鸿蒙构建验证准备好鸿蒙 SDK 和 Flutter 鸿蒙适配环境的 CI 镜像在发布前执行完整的 hvigor 构建任务同时跑一次针对 arkts 代码的静态检查。这一步很耗时间但它拦住过至少三次“pub.dev 已发布但鸿蒙编译不过”的问题。一旦走到发布这一步出问题就是公共事故——pub 包一旦发布就算后续版本覆盖旧版本也还挂在仓库里。发布前多花三分钟构建验证远比发布后发勘误通知要划算。4. 落地实操把 pub_release 接进鸿蒙研发管线理论部分讲完直接进入操作层面。下面这套步骤是我在多个库上验证过的流程照着做就能搭出一条可重复执行的鸿蒙化发布管线。4.1 项目侧改造从手动标记到可重复执行先做三件事第一规范提交信息要求所有 commit 遵循 Conventional Commits 格式第二在库里初始化 pub_release第三把鸿蒙侧文件纳入版本管理并纳入发布检查。我在项目根目录跑 pub_release 的初始化命令dart run pub_release init初始化后它会在项目里生成配置文件用来设定版本增量策略、CHANGELOG 输出路径、tag 前缀这些参数。不同版本的默认字段略有差别跑完之后记得打开配置文件看一眼里面每个字段的含义。这里要注意一个容易被忽略的点如果库的历史提交信息非常不规范比如大量update、fix bug这类无类型前缀的提交pub_release 推导版本时会很痛苦。我的建议是适配鸿蒙化发布管线的同时在仓库里加上一条提交信息规范检查不合格的 commit 直接拦截在 CI 阶段别让它们流到主分支。4.2 核心命令序列日常发版时我的操作基本是两个命令的组合。发一个 patch 版本dart run pub_release --patch --dry-run dart run pub_release --patch如果你已经完成了 Custom 代码的同步钩子可以在 pub_release 执行后追加 ohpm 上传和 tag 同步命令。整体看起来是这样的# 1. 预演发布确认版本号和 CHANGELOG dart run pub_release --patch --dry-run # 2. 真正执行 pub 发布与 tag 生成 dart run pub_release --patch # 3. 同步 ohpm 版本号并上传自定义脚本 dart run tool/publish_harmony.dart --version 1.2.3 # 4. 推送所有 tag 到远端 git push --tags注意发 minor 或 major 版本时把参数换成对应类型即可。如果库积累了大量改动第一次用 pub_release 时建议多用几次 dry run看看版本号推导是否符合预期别上来就直接 publish。4.3 CI 集成自动发布与质量门禁手动在本地跑命令还只是半自动化。完整的研发生命线应该把发布动作放进 CI/CD 里让每次发版都走同一条被验证过的路径。我的 CI 流水线主要分两个阶段。第一个阶段是 MR/PR 合并前的质量门禁包括常规的 analyze、test、鸿蒙构建验证。第二个阶段是版本发布通常由维护者手动触发或者在新的版本 tag 推送后自动触发。一个典型的 CI 发布任务大致如下jobs: release: runs-on: ubuntu-latest steps: - name: 拉取代码 uses: actions/checkoutv4 with: fetch-depth: 0 - name: 准备 Flutter 环境 uses: subosito/flutter-actionv2 - name: 准备鸿蒙适配环境 run: | # 安装鸿蒙 SDK 与 Flutter 鸿蒙适配分支 - name: 执行发布质量校验 run: | flutter analyze flutter test # 鸿蒙构建验证命令 - name: 发布到 pub.dev env: PUB_TOKEN: ${{ secrets.PUB_TOKEN }} run: dart run pub_release --release - name: 发布到 ohpm 并同步版本 env: OHPM_TOKEN: ${{ secrets.OHPM_TOKEN }} run: dart run tool/publish_harmony.dart这里我强烈建议不要把发布动作绑定在“推送 tag 时自动触发”上。听起来很自动化实际很容易误触发。比如 commit 消息不规范导致 tag 错乱远端会多出一个脏 tag。我更倾向于用workflow_dispatch手动触发或者等 pub_release 在本地完成 tag 创建后再推送CI 只做构建验证和上传。5. 鸿蒙化适配的踩坑实录问题排查链路任何发布管线都不是一次跑通的。我整理了几个真实踩过的坑每个都附带了完整的排查思路希望能帮你少走弯路。5.1 坑一版本号不一致ohpm 直接拒绝上传现象pub.dev 的包已经发布到 1.4.0但 ohpm 上传时提示版本号不合法或者与已有版本冲突。我一度以为是自己记错了反复检查后才发现oh-package.json5里还是 1.3.0。排查链路先看 ohpm 的失败日志确认是版本格式问题还是重复上传问题再对比两个 manifest 文件里的版本号果然不一致最后回看上一次手动发版的记录发现当时只改了 pubspec.yaml完全没有动过 oh-package.json5。这个坑的根因很简单双仓库版本号没有联动机制。后续我在发布脚本里增加了一个强制同步步骤任何发布动作在开始前都会比对两个 manifest 的版本号不一致就中止。5.2 坑二Dart SDK 约束与鸿蒙 Flutter 分支不匹配现象发布到 pub.dev 后鸿蒙侧工程集成依赖时flutter pub get报错提示当前 Dart SDK 版本无法解析该包。排查链路先看错误信息里的 SDK 版本要求再确认鸿蒙适配层对应的 Flutter/Dart 版本。发现 pubspec.yaml 里面environment: sdk的范围写得太激进使用了鸿蒙适配分支尚未支持的 Dart 语法。这个问题的本质是“发布目标环境”和“使用场景环境”的版本差异。修复方式是把 SDK 约束范围放宽到鸿蒙适配层支持的最低版本同时在 CI 里加一个双 SDK 版本矩阵测试确保低版本 SDK 也能正常解析。5.3 坑三tag 已被使用发布中止现象发布 1.4.1 时git push tag 失败提示v1.4.1已经存在。排查链路查看远端 tag 列表发现v1.4.1被错误地打到了一个旧 commit 上。再翻历史是上一次手动发版时在错误的分支上打了 tag然后一直没删。这个坑在多人协作仓库里特别容易发生。我的处理方式是双管齐下第一在 CI 发布任务里先执行git fetch --tags并检查目标 tag 是否存在第二把 tag 创建逻辑移到发布脚本内部与 pub.dev 发布动作绑定在同一个事务式流程里要么一起成功要么一起失败避免半途状态。5.4 坑四PlatformView 等原生代码在鸿蒙构建机上报错现象pub 发布已经成功但 CI 里鸿蒙构建步骤挂了报错指向 flutter/platform_view 相关的原生桥接代码。排查链路鸿蒙适配层对 PlatformView 的整套支持机制和 Android 侧并不完全一致。报错信息看起来是“找不到符号”实际原因是插件在鸿蒙侧的注册入口没有正确声明原生代码没有被加载进鸿蒙构建产物。解决方式是在插件的 harmonyos 目录里补全入口注册声明同时检查 pubspec.yaml 中 flutter 插件部分的声明是否把鸿蒙入口排除在外了。这个坑给我最大的教训就是发布前的构建验证必须是完整的鸿蒙构建而不是只跑 Dart 层的测试。坑根因预防手段ohpm 上传失败版本号手动维护未联动发布脚本统一重写版本号SDK 约束冲突environment 范围过窄CI 双 SDK 版本矩阵tag 冲突人工打 tag 出错发布脚本事务式管理 tag鸿蒙构建失败插件注册入口缺失发布前全量 hvigor 构建6. 发布之后这条研发生命线如何倒逼工程规范化把 pub_release 适配到鸿蒙之后我最大的感受是发布管线不只是“发个包”这么简单它实际上成了倒逼工程规范化的抓手。6.1 一次发布多方同步的标准动作现在每次发版的动作是标准化的不会再因为“今天心情好想手动来一下”导致某个仓库漏更新。整个流程可以被任何人接手拉代码、跑发布脚本、看输出、确认结果。哪怕是新加入的维护者按 README 里的发布文档操作也能发出版本一致的跨平台包。这套标准动作天然适合做成“发布单”一个版本的发布记录包含 pub.dev 版本号、ohpm 版本号、对应 tag、CHANGELOG 摘要四个要素全部由脚本产出并汇总。下游用户看到一个版本号就能判断这个版本影响范围、包含哪些改动、从哪个 commit 开始。6.2 发布质量门禁与回滚预案把发布动作接进 CI 之后质量门禁变成了一道硬性关卡。代码不通过 analyze、测试失败、鸿蒙构建不过都到不了发布这一步。这个设计有很现实的理由三方库一旦发出去影响面不可控不要寄希望于“发现问题再打个补丁”应该把问题挡在发布前。回滚预案同样重要。我维护的发布文档里固定写明了三件事如果 pub.dev 版本发错了怎么通过废弃旧版本yank处理如果 tag 打错了怎么安全地删远端 tag 并重新标记如果 ohpm 版本发错了怎么联系仓库方下线版本。这些内容不需要每天看但在事故发生时能省下大量时间。6.3 权限与账号安全发布凭证的管理也要纳入管线设计。pub.dev 和 ohpm 的 token 都不应该出现在本地环境或者明文配置里统一放进 CI 的 secrets 中并且按最小权限原则分配。token 需要定期轮换一旦怀疑泄露立即吊销。发布操作尽量由 CI 统一执行本地只保留 dry run 和预演能力这样即使开发者电脑被入侵攻击者也拿不到完整的发布凭证。6.4 扩展思路这套管路还有很多可玩的方向。如果维护的是 monorepo 多包仓库可以给 pub_release 加上包级批处理逻辑一次遍历多个包、各自推导版本、批量发布如果库里还包含鸿蒙原生组件库可以把 ohpm 发布从“手动脚本”升级为“独立发布服务”和主库联动还可以把发布结果接入 IM 或邮件通知让团队第一时间知道新版本状态。我个人实际用下来的体会是鸿蒙化适配缠着你的不仅仅是平台的 API 差异更大的成本来自工程链路的混乱。把 pub_release 变成整个发布流程的总调度相当于先把最不性感但又最容易翻车的地基打牢。地基稳了后面往鸿蒙上加原生能力、做性能优化、支撑多业务方接入都会顺畅很多。如果你也在维护 Flutter 三方库并准备适配鸿蒙建议第一件事不是深挖鸿蒙的编码规范而是先把这条发布生命线接起来。
返回列表