Butter Knife 版本发布流程全解析:基于 Gradle 与 Sonatype Nexus 的 Android 开源库发布指南
2026/9/20 13:48:52 网站建设 项目流程

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 个模块:butterknifebutterknife-annotationsbutterknife-compilerbutterknife-gradle-pluginbutterknife-integration-testbutterknife-lintbutterknife-reflectbutterknife-runtime。其中butterknife-integration-test是纯测试模块,不会发布;其余模块在发布时会被一起构建并上传到 Maven 仓库。根 build.gradle 中通过subprojects为所有子项目统一设置了group = GROUPversion = VERSION_NAME,因此一次uploadArchives即完成全部分发模块的发布。


二、发布前的准备工作(步骤 1-3)

1. 修改版本号为非 SNAPSHOT 版本

将 gradle.properties 中的VERSION_NAME10.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.propertiesCHANGELOG.mdREADME.md的修改作为一次独立的"发布准备"提交,便于日后回滚与审计。

5. 执行 clean uploadArchives

./gradlew clean uploadArchives

clean确保所有模块从零构建,排除脏产物;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_USERNAMESONATYPE_NEXUS_PASSWORD两个 Gradle 属性注入,通常放在~/.gradle/gradle.properties中,避免把账号密码提交进仓库;
  • POM 生成configurePom(pom)会把 gradle.properties 中的GROUPPOM_*系列属性写入 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(发布)两步操作:

  1. Close:对 staging 仓库执行校验(如 POM 完整性、签名有效性、源码/Javadoc 是否齐全),校验通过后仓库变为 closed 状态,构件可从临时 staging 地址被拉取验证;
  2. 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-SNAPSHOT

9. 提交开发版本切换

git commit -am "Prepare next development version."

通过"发布完立即切回 SNAPSHOT"的方式,主干的版本号始终处于可继续开发的状态,同时避免两个版本号混用导致依赖解析歧义。


七、推送代码与标签(步骤 10)

git push && git push --tags

git 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'。因此每次发布新版本后,需要:

  1. 将根 build.gradle 中的versions.release更新为刚发布的新版本号;
  2. 由于 sample/library/build.gradle 通过classpath "com.jakewharton:butterknife-gradle-plugin:${versions.release}"引用插件,示例库工程同时验证了butterknife-gradle-plugin的可用性;
  3. 更新后重新构建 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 中的GROUPVERSION_NAME
版本分发到各模块build.gradle 中subprojects { group = GROUP; version = VERSION_NAME }
上传任务与仓库地址gradle/gradle-mvn-push.gradle 中的uploadArchivesgetReleaseRepositoryUrl()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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询