一、前言:为什么要发布"制品"

上一篇我们完成了 adaptive_image_picker 的鸿蒙化适配,业务侧通过 AtomGit 的 Git 依赖就能在鸿蒙工程里使用。但"能被引用"和"是一个合格的制品"之间还有一段距离:包名是否规范、元信息是否完整、文档和变更记录是否齐全、静态分析是否干净、依赖下限是否经得起推敲——这些共同决定了别人拿到你的包时的第一印象和维护成本。

这篇以我们这个真实库为例,把 pub 制品从零到发布完整走一遍,覆盖新手最容易卡住的环节:pubspec 怎么写才算规范、发布前的自检清单、--dry-run 常见报错怎么解、发布之后评分和版本怎么管,最后单独讲讲鸿蒙化版本的分发选择——这是 Flutter 鸿蒙生态里每个发包人都会遇到的问题。

先交代案例背景:adaptive_image_picker 是一个零权限媒体选择库(选图、拍照、裁剪、压缩三合一),上游 1.0.2 已发布在 pub.dev;我们的鸿蒙化版本托管在 AtomGit 的 oh-flutter 组织下,保留上游全部提交历史,以一个适配提交的形式存在。

在这里插入图片描述

二、包结构:pubspec.yaml 逐字段讲清楚

新手发布最常见的问题不是代码跑不通,而是元信息残缺导致包页"素面朝天"。下面是我们发布时实际使用的 pubspec.yaml(有删减):

name: adaptive_image_picker
description: "A production-grade, zero-permission adaptive image picker for Flutter with pure-Dart cropping, binary-search compression, and native PhotoPicker integration."
version: 1.0.2
homepage: https://github.com/Karan8686/adaptive_image_picker
repository: https://github.com/Karan8686/adaptive_image_picker
issue_tracker: https://github.com/Karan8686/adaptive_image_picker/issues
topics:
  - image-picker
  - image-cropper
  - image-compression
  - camera
  - photopicker

environment:
  sdk: '>=3.4.0 <4.0.0'
  flutter: '>=3.19.0'

flutter:
  plugin:
    platforms:
      android:
        package: com.yourdomain.adaptive_image_picker
        pluginClass: AdaptiveImagePickerPlugin
      ios:
        pluginClass: AdaptiveImagePickerPlugin
      ohos:
        pluginClass: AdaptiveImagePickerPlugin
      web:
        pluginClass: AdaptiveImagePickerWeb
        fileName: adaptive_image_picker_web.dart
      ...

逐个说重点:

name:全小写 + 下划线,全局唯一,发布后就"占用"了,起名前先去 pub.dev 搜一下有没有撞名。

description:一句话说清包做什么。它会出现在搜索结果里,别写"my first package"这种,认真写。

version:语义化版本(SemVer)。破坏性变更升主版本,新增功能升次版本,修 bug 升修订号。发布后版本号不能复用,错了只能发新版本。

homepage / repository / issue_tracker:三个链接都填上。repository 指向源码仓库,pub.dev 包页会直接展示,也是使用者提 issue 的入口。

topics:主题标签,最多 5 个。pub.dev 靠它做检索聚合,填准了能带来自然流量,这几乎是免费曝光。

environment:SDK 约束。这里有个新手盲区:约束写得越宽,兼容性验证越严。pub.dev 会对你声明的整个版本区间做"下限分析"(用最低版本跑一遍分析),下限写得太乐观会直接挂掉,后面 FAQ 里有我们的真实案例。

plugin.platforms:声明支持的 平台和各端的插件类。注意看我们的配置里有 ohos 平台——这是 Flutter 鸿蒙版工具链认识的字段,插件注册时靠它找到 ArkTS 侧的实现。

三、质量四件套:README、CHANGELOG、LICENSE、静态分析

这四样决定了 pub.dev 给你的第一印象分,缺一个都肉眼可见。

README.md 是包的门面。我们的 README 从"Why Choose"切入,给了能力对比矩阵、快速上手、8 个典型场景的完整代码。经验是:README 里的每一段示例代码都应该是真实跑过的,新手最恨"文档代码编译不过"。

CHANGELOG.md 每个版本必须有一条对应记录,Keep a Changelog 格式即可。它会被渲染到包页的 Changelog 标签下,使用者升级前会看它。

LICENSE 必须有。没有 LICENSE 的包,发布预检直接报错——这是硬性要求,MIT 是最省事的选择。

静态分析与测试。发布前跑一遍:

flutter analyze
flutter test
dart format --set-exit-if-changed .
flutter pub publish --dry-run

我们的库在发布态是 flutter analyze 零问题、28 项测试全绿。这不是炫技——dry-run 会把分析告警列出来,带着告警发包,包页评分里会写得明明白白。

在这里插入图片描述

四、–dry-run 的真实踩坑:一个依赖下限引发的报错

--dry-run 会做一次完整预演:校验元信息、跑分析、检查 LICENSE、估算包体积,但不上传。新手遇到的报错八成在这里。

分享我们 1.0.1 版本的真实案例。当时 pubspec.yamlimage 依赖写的是 ^4.2.0,本地用的是新版,一切正常。但 dry-run(以及发布后的自动分析)会对依赖下限版本做分析,结果在旧版本上 encodeWebP 相关代码编译不过,验证直接失败:

Validation error: Analysis using the lower bound of the dependency
`image: ^4.2.0` failed to compile.

修复方式是把约束提到真实验证过的版本 image: ^4.9.2。这条修复后来原样进了 1.0.1 的 CHANGELOG:

## 1.0.1
* Fix: Bumped `image` dependency constraint to `^4.9.2` to resolve
  `encodeWebP` compilation errors during lower bounds downgrade analysis.

教训提炼成一句话:声明依赖约束时,"能跑"的版本不等于"下限安全"的版本,dry-run 会替你验证下限,别嫌它严。

其他高频报错:缺 LICENSE、description 为空或太短、homepage 链接 404、包体积超限(把构建产物、示例的 build 目录误提交进包里是重灾区,用 .pubignore 或确认 .gitignore 生效)。

五、正式发布:三步走

第一步,准备 Google 账号。 pub.dev 使用 Google 账号登录,发布命令会拉起浏览器做 OAuth 授权,首次发布会引导你完成登录并拿到一个永久凭证。

第二步,执行发布。 在插件根目录(不是 example 目录)运行:

flutter pub publish

命令会把最终将要上传的文件列表全部列出来让你确认——认真扫一眼,确认没有混入不该发的东西。输入 y 之后上传,成功后终端会给出包页地址。

在这里插入图片描述

第三步(可选),创建认证发布者(Verified Publisher)。 个人邮箱直接发的包,包页 Publisher 一栏显示的是 unverified uploader——我们这次就是以个人 Google 账号直接发布,对个人项目完全够用。如果你有自己的域名,可以在 pub.dev 上创建 verified publisher 并验证域名所有权,之后用发布者身份发包,包名旁边会带认证徽章。团队维护的项目强烈建议做这个——徽章就是"这个包有人长期负责"的官方背书。

六、发布之后:评分、文档与版本迭代

发布完成不等于结束。pub.dev 会用 pana 自动分析你的包并给出 Pub Points,评分维度包括:文档覆盖率(公开 API 是否有注释)、静态分析干净度、依赖约束合理性、多平台支持情况、元信息完整度。分析在新包发布后约半小时内完成,点开包页的 Scores 标签可以看到逐项明细,按缺失项补就行——比如我们曾为补齐公开 API 的文档注释专门过了一遍,公开成员的文档覆盖率能拉不少分。

在这里插入图片描述

版本迭代坚持 SemVer:我们库的演进轨迹是 1.0.0 首发全功能 → 1.0.1 修依赖约束(纯修复)→ 1.0.2 新增桌面端支持(功能新增)。每次发版同步更新 CHANGELOG,使用者一看版本号加变更记录就知道该不该升。

另外提醒一个很多新手踩过的坑:已发布的版本撤不回。单个版本在发布后 7 天内可以 dart pub retract 撤回,超过时限只能发新版本修复;整个包可以标记为 discontinued(停止维护),但任何人都能继续依赖历史版本。所以发版前 dry-run + 人工过一遍文件列表,永远值得。

七、鸿蒙化版本怎么发:两条路线

这是 Flutter 鸿蒙生态特有的问题:官方 Flutter SDK 并不认识 ohos 平台字段,那鸿蒙化版本应该怎么分发?目前社区有两条成熟路线,我们都实践过:

路线 A:Git 依赖分发(本库采用)。 鸿蒙化版本托管在 AtomGit 仓库,业务侧用 Git 依赖引入:

dependencies:
  adaptive_image_picker:
    git:
      url: https://atomgit.com/oh-flutter/adaptive_image_picker.git

优点:一个仓库同时保留上游历史和适配提交,回溯、同步上游、提 PR 都顺;发版跟着 Git 标签走,不需要 pub.dev 账号。适合组织内部或小范围推广。

路线 B:_ohos 后缀独立包。 OpenHarmony SIG 对 path_providerpermission_handlerdevice_info_plus 等主流插件的鸿蒙化实现,就是以 path_provider_ohos 这样的独立包名发布在 pub.dev 上的,业务侧通过 dependency_overrides 把官方包的平台实现替换为 ohos 实现。优点是对使用者透明、能进 pub.dev 搜索体系;代价是包名翻倍、版本要跟上游保持同步。

两条路线没有绝对优劣:改造成本低、跟进上游勤,选 B;想保留单仓库完整历史、面向组织内交付,选 A。无论哪条,前文的质量要求——元信息、CHANGELOG、analyze 干净、dry-run 通过——一条都不能少,鸿蒙化包同样代表工程素养。

顺带一提,如果包里有 ArkTS 原生组件需要给非 Flutter 的鸿蒙应用复用,还可以发布到 OpenHarmony 三方库中心仓(ohpm),那是另一个生态的"pub",流程思想相通。

八、FAQ

Q1:包名被人占了怎么办?
pub.dev 的包名先到先得且不可转移。起名前先搜,实在撞了就在名字里加领域限定词。这也是为什么建议尽早把"占坑版"发出去。

Q2:dry-run 报依赖下限分析失败?
见第四节案例:把出问题的依赖约束提高到你真实验证过的版本。不要为了"兼容性好看"故意把下限写得很低。

Q3:发布时一直失败/超时?
检查终端环境变量里是否配置了国内镜像(PUB_HOSTED_URL / FLUTTER_STORAGE_BASE_URL)。镜像用于加速下载,上传必须直达官方源,发布前临时移除这两个变量再试。

Q4:发错了能删吗?
不能删除。7 天内可 retract 单个版本,整包只能 discontinued。所以版本号别手抖,dry-run 别跳过。

Q5:鸿蒙化版本的 bug 提到哪里?
本库统一提到 AtomGit 仓库的 issues(https://atomgit.com/oh-flutter/adaptive_image_picker/issues ),附上 flutter doctor -v、设备型号、复现步骤。想直接修复的,Fork 后从 main 拉分支,本地跑通 flutter analyzeflutter testflutter build hap --debug 再发 PR。

九、总结

把一个包发到 pub.dev,技术上只有 flutter pub publish 一条命令,但围绕这条命令的元信息、文档、变更记录、依赖约束、预检习惯,才是"制品"和"压缩包"的区别。以我们维护的 adaptive_image_picker 为例走完这一整套,你会发现大部分工作在第一次发包前就完成了,之后的每次发版只是:改代码、补 CHANGELOG、升版本号、dry-run、publish。

Flutter 鸿蒙生态正在补齐三方库版图,每一个规范发布的包——无论走 pub.dev 的 _ohos 路线还是 AtomGit 的 Git 依赖路线——都是在给这张版图添砖。欢迎把你的适配成果发出来。

欢迎加入 Flutter 鸿蒙化社区(oh-flutter 组织):https://atomgit.com/oh-flutter

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐