Butter Knife 版本发布流程全解析:基于 Gradle 与 Sonatype Nexus 的 Android 开源库发布指南
【免费下载链接】butterknifeBind Android views and callbacks to fields and methods.项目地址: https://gitcode.com/gh_mirrors/bu/butterknife
导读
本文以 Butter Knife 仓库根目录下的 RELEASING.md 为骨架,完整还原一个多模块 Android 开源库从"开发中快照版本"到"正式发布版本"再到"下一个开发版本"的全生命周期操作流程。文中每一步均结合仓库内的真实配置文件(如 gradle.properties、gradle/gradle-mvn-push.gradle)与示例模块(sample/app/build.gradle、sample/library/build.gradle)给出可验证的底层原理,读者学完后可以完整掌握 Butter Knife 自身的发布操作,也能将同样的发布模型迁移到自己的 Android 开源项目中。
一、发布流程总览:从 SNAPSHOT 到正式版本
Butter Knife 的发布策略遵循经典的"主版本号 + 快照"双状态模式:日常开发阶段,gradle.properties中的版本号是X.Y.Z-SNAPSHOT;只有在真正发版时,才临时把版本号切换为非 SNAPSHOT 的正式版本号,构建上传后打 tag,再立刻改回下一个 SNAPSHOT 版本,让主干永远保持"可发布"的连续状态。
当前仓库的 gradle.properties 中记录了发布所需的全部元数据:
GROUP=com.jakewharton VERSION_NAME=10.2.4-SNAPSHOT POM_DESCRIPTION=Field and method binding for Android views. POM_URL=https://github.com/JakeWharton/butterknife/ POM_SCM_URL=https://github.com/JakeWharton/butterknife/ POM_SCM_CONNECTION=scm:git:git://github.com/JakeWharton/butterknife.git POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/JakeWharton/butterknife.git POM_LICENCE_NAME=The Apache Software License, Version 2.0 POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt POM_LICENCE_DIST=repo POM_DEVELOPER_ID=jakewharton POM_DEVELOPER_NAME=Jake Wharton其中GROUP决定所有构件(artifact)的 Maven 坐标组名,VERSION_NAME是本次要发布(或正在开发)的版本号,其余POM_*属性会被注入到生成的 POM 文件中,供 Sonatype Nexus 审核与使用者解析依赖时读取。结合 CHANGELOG.md 可见,最近一次正式发布为 10.2.3(2020-08-12),当前仓库正处于向 10.2.4 版本开发的 SNAPSHOT 阶段,与发布文档的流程完全吻合。
发布涉及哪些构件
Butter Knife 是一个多模块工程,settings.gradle 中注册了 8 个模块:butterknife、butterknife-annotations、butterknife-compiler、butterknife-gradle-plugin、butterknife-integration-test、butterknife-lint、butterknife-reflect、butterknife-runtime。其中butterknife-integration-test是纯测试模块,不会发布;其余模块在发布时会被一起构建并上传到 Maven 仓库。根 build.gradle 中通过subprojects为所有子项目统一设置了group = GROUP与version = VERSION_NAME,因此一次uploadArchives即完成全部分发模块的发布。
二、发布前的准备工作(步骤 1-3)
1. 修改版本号为非 SNAPSHOT 版本
将 gradle.properties 中的VERSION_NAME从10.2.4-SNAPSHOT改为正式版本号,例如:
VERSION_NAME=10.2.4这一步的意义在于:根 build.gradle 会把VERSION_NAME同步到所有子项目的version属性,同时 gradle/gradle-mvn-push.gradle 中的isReleaseBuild()判断决定了上传路径与签名行为:
def isReleaseBuild() { return VERSION_NAME.contains("SNAPSHOT") == false }- 版本号不含
SNAPSHOT:属于发布构建,uploadArchives会上传到 Release 仓库,并触发 POM 签名(signing); - 版本号包含
SNAPSHOT:属于开发构建,上传到 Snapshot 仓库,不进行签名。
2. 更新 CHANGELOG.md
发布前需要在 CHANGELOG.md 顶部为该版本新增一段变更记录,格式参照既有条目,例如:
Version 10.2.3 *(2020-08-12)* ----------------------------- * Fix: Support receiving `MotionEvent` in an `@OnTouch` callback when using 'butterknife-reflect'.变更记录应如实覆盖该版本的所有 New / Fix / 破坏性变更,这是发布后使用者在升级时最主要的参考依据。
3. 更新 README.md 中的版本号
README.md 的依赖示例中硬编码了版本号:
dependencies { implementation 'com.jakewharton:butterknife:10.2.3' annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' }发布新版本时,需要把这些示例中的版本号同步更新为本次发布的新版本,确保文档与 Maven 仓库实际可用版本一致。注意 README 中同时涉及butterknife-gradle-plugin(库工程使用)与butterknife-reflect(IDE 构建使用)的版本引用,也应一并核对。
三、提交发布准备并构建上传(步骤 4-5)
4. 提交发布准备
git commit -am "Prepare for release X.Y.Z."将上述对gradle.properties、CHANGELOG.md、README.md的修改作为一次独立的"发布准备"提交,便于日后回滚与审计。
5. 执行 clean uploadArchives
./gradlew clean uploadArchivesclean确保所有模块从零构建,排除脏产物;uploadArchives是 gradle/gradle-mvn-push.gradle 中为每个模块统一配置的发布任务。该脚本的核心逻辑如下:
afterEvaluate { project -> uploadArchives { repositories { mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } repository(url: getReleaseRepositoryUrl()) { authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) } snapshotRepository(url: getSnapshotRepositoryUrl()) { authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) } configurePom(pom) } } } ... }从中可以提取出几个关键机制:
- 双仓库路由:
getReleaseRepositoryUrl()默认指向 Sonatype Nexus 的 staging deploy 地址,getSnapshotRepositoryUrl()默认指向 snapshots 仓库;两者都支持通过RELEASE_REPOSITORY_URL/SNAPSHOT_REPOSITORY_URL属性覆盖(例如发布到内部私有仓库); - 认证信息:通过
SONATYPE_NEXUS_USERNAME与SONATYPE_NEXUS_PASSWORD两个 Gradle 属性注入,通常放在~/.gradle/gradle.properties中,避免把账号密码提交进仓库; - POM 生成:
configurePom(pom)会把 gradle.properties 中的GROUP、POM_*系列属性写入 POM 的 groupId、description、SCM、license、developer 等节点; - 签名规则:
signing { required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } sign configurations.archives }只有发布构建(非 SNAPSHOT)且确实在执行uploadArchives时才要求 GPG 签名,签名对象是configurations.archives中的全部构件。
该脚本还为每个模块生成了源码包与 Javadoc 包(Android 模块使用androidSourcesJar/androidJavadocsJar,普通 Java 模块使用sourcesJar/javadocJar),并统一挂载到archives配置中,因此执行uploadArchives时 POM、源码 jar、Javadoc jar、主 jar 会一并上传,这也是通过 Sonatype 审核的必要条件。此外脚本还提供了installLocally任务,可将构件安装到本地build/localMaven目录用于联调验证。
四、在 Sonatype Nexus 提升构件(步骤 6)
# 上传成功后,登录 Sonatype Nexus 管理界面(oss.sonatype.org) # 在 Staging Repositories 中找到本次上传的 staging repo # 点击 Close 关闭仓库(触发校验),确认无误后点击 Release 正式发布构建上传成功后,构件并不会立即出现在 Maven Central 中,而是停留在 Sonatype Nexus 的 staging 区域,需要人工登录 Nexus 完成Close(关闭)→ Release(发布)两步操作:
- Close:对 staging 仓库执行校验(如 POM 完整性、签名有效性、源码/Javadoc 是否齐全),校验通过后仓库变为 closed 状态,构件可从临时 staging 地址被拉取验证;
- Release:确认无误后执行 release,构件才会被同步到 Maven Central 并最终对全球开发者可见。
这一步与步骤 5 一样,是整个发布流程中唯一不能完全自动化的环节,也是发布文档要求人工关注的原因。
五、打版本标签(步骤 7)
git tag -a X.Y.Z -m "Version X.Y.Z"发布成功后在当前提交上打带注释的标签(annotated tag),记录版本号与发布说明。标签名与版本号保持一致(如10.2.4),它是后续追溯某个版本源码快照的唯一锚点。
注意:原文档此步的 tag 命令中写的是
X.Y.X,结合上下文与第 4、7 步的注释("where X.Y.Z is the new version")可以判断这是文档笔误,实际打 tag 时应使用与版本号一致的X.Y.Z。
六、准备下一个开发版本(步骤 8-9)
8. 更新到下一个 SNAPSHOT 版本
再次修改 gradle.properties,把版本号推进为下一个开发版本:
VERSION_NAME=10.2.5-SNAPSHOT9. 提交开发版本切换
git commit -am "Prepare next development version."通过"发布完立即切回 SNAPSHOT"的方式,主干的版本号始终处于可继续开发的状态,同时避免两个版本号混用导致依赖解析歧义。
七、推送代码与标签(步骤 10)
git push && git push --tagsgit push推送提交到远程主干,git push --tags单独推送步骤 7 创建的标签。两个推送必须都成功,远程仓库才与本地发布状态完全一致。
八、更新两个示例模块(步骤 11)
Butter Knife 仓库内置了两个示例模块(sample/app 与 sample/library),它们不直接依赖 SNAPSHOT,而是通过根 build.gradle 中的deps.release引用已发布的正式版本:
'release': [ 'runtime': "com.jakewharton:butterknife:${versions.release}", 'compiler': "com.jakewharton:butterknife-compiler:${versions.release}" ],其中versions.release = '8.8.1'。因此每次发布新版本后,需要:
- 将根 build.gradle 中的
versions.release更新为刚发布的新版本号; - 由于 sample/library/build.gradle 通过
classpath "com.jakewharton:butterknife-gradle-plugin:${versions.release}"引用插件,示例库工程同时验证了butterknife-gradle-plugin的可用性; - 更新后重新构建 sample,确认示例工程能在新版本下正常编译运行,起到"发布冒烟测试"的作用。
九、失败处理与回滚(文档补充条款)
RELEASING.md 末尾明确给出了失败处理约定:
如果步骤 5 或 6 失败,drop 掉 Sonatype 上的 staging 仓库,修复问题,提交,然后从步骤 5 重新开始。
也就是说:
- 若
./gradlew clean uploadArchives失败(构建错误、认证失败、签名失败),直接修复代码或配置后重新执行即可,尚未进入 Nexus 的 stage,无需清理; - 若在 Nexus 的 Close / Release 阶段失败(如 POM 校验不通过、签名缺失),需要先在 Nexus 界面Drop掉对应的 staging 仓库,把发布状态重置干净,修复后再从步骤 5(重新构建上传)开始,而不是在残留的半成品 staging 仓库上继续操作。
这条约定保证了"要么不发布,要么发布出完整可用的版本",避免 Maven Central 上出现残缺构件。
十、发布流程的源码级依据小结
整个发布流程可以从仓库中找到一一对应的实现证据:
| 发布环节 | 仓库依据 |
|---|---|
| 版本号与坐标 | gradle.properties 中的GROUP、VERSION_NAME |
| 版本分发到各模块 | build.gradle 中subprojects { group = GROUP; version = VERSION_NAME } |
| 上传任务与仓库地址 | gradle/gradle-mvn-push.gradle 中的uploadArchives、getReleaseRepositoryUrl()、getSnapshotRepositoryUrl() |
| 发布/快照区分与签名 | 同一脚本中的isReleaseBuild()与signing { required { ... } } |
| POM 元数据 | 同一脚本中的configurePom(pom)配合POM_*属性 |
| 源码/Javadoc 包 | 同一脚本中的sourcesJar/javadocJar/androidSourcesJar/androidJavadocsJar |
| 版本历史 | CHANGELOG.md 中每次发布对应的变更条目 |
| 示例模块版本同步 | build.gradle 的versions.release与两个 sample 模块的依赖声明 |
需要注意的是,本仓库的 Gradle Wrapper 版本为 4.10.3(见 gradle/wrapper/gradle-wrapper.properties),且根 gradle.properties 中设置了android.enableAapt2=false以规避旧版 AGP 的已知问题。这意味着上述发布流程是围绕该历史版本的工具链设计的;若要在现代环境(新版 AGP / Gradle)下复刻,应关注maven插件(已被maven-publish取代)、android.enableAapt2弃用等兼容性差异,并基于实际环境调整命令与配置。
结语
Butter Knife 的发布流程虽然只有短短十余步,却完整覆盖了"版本切换—变更记录—构建签名—Nexus 提升—打标—切回快照—示例验证—失败回滚"的闭环,其背后的 gradle-mvn-push.gradle 更是浓缩了一套可复用的多模块 Android 开源库发布模板。无论是作为 Butter Knife 的维护者,还是想为自己的库搭建类似发布管线的开发者,都可以直接以本仓库为参照,逐行对照 RELEASING.md 与构建脚本,快速落地一套同样规范的发布流程。
【免费下载链接】butterknifeBind Android views and callbacks to fields and methods.项目地址: https://gitcode.com/gh_mirrors/bu/butterknife
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考