PublishPlugin 用于给 Android Library 和 Gradle Plugin 模块生成 Maven publication,并提供统一的本地发布、远程发布入口。
当前远程发布统一入口是 PublishLibraryRemoteTask,默认发布到 GitHub Packages;GitHub Packages 和 Sonatype Central Portal 统一通过 publishTarget 选择。旧私服发布仍保留历史兼容入口。
本仓库需求分支、pre_publish 预发布和 main 合入规则见 分支与发布工作流。版本变更记录见 changelog。
从 1.2.2 升级到 1.2.3 会改变 sources 包内容,发 Central 前必须先看这一节。
- 以前 Central 发布会无条件附带真实业务源码。现在本地 Maven、GitHub Packages 和 Central 都始终上传
sources.jar,但默认hasSource = false,内容是只含 README 的占位包。 - 开源组件必须在模块
PublishInfo里设置hasSource = true,否则下次 Central 发布会悄悄丢掉真实源码。 - 闭源组件保持默认即可。本地
publishToMavenLocal也会带占位 sources,用来预演 Central 产物形态。 - 运行时覆盖只用
-PhasSource/PUBLISH_HAS_SOURCE。不要使用无前缀的HAS_SOURCE或OBFUSCATE环境变量,避免被无关 CI 变量改掉发布结果。旧字段obfuscate仍可用:obfuscate = true等于hasSource = false。
Skills 配置适合在 Codex 中交互式完成发布接入、发布目标选择、配置校验和问题修复。入口示例:
使用 $publishplugin-one-click-publish,帮我为 :library 配置发布。
也可以指定目标,例如发布到 Central:
使用 $publishplugin-one-click-publish,帮我为 :library 配置 Central Portal 发布。
Skill 会根据发布目标引导配置:
| 发布目标 | 配置重点 |
|---|---|
| 本地 Maven 发布 | 校验模块 PublishInfo,执行 publishToMavenLocal 或 PublishLibraryLocalTask。 |
| GitHub Packages 发布 | 配置 GitHub Packages 仓库、凭据来源和远程发布命令。 |
| Sonatype Central Portal 发布 | 配置 Central namespace、Central token、GPG signing、POM/SCM 元数据、GitHub Actions workflow。 |
| 旧自定义 Maven 仓库 | 配置旧私服字段和兼容发布模式。 |
本地脚本配置用于不依赖 Codex 的终端执行。离线脚本封装的是一键发布配置流程,默认生成 GitHub Packages 发布 workflow;需要发布到 Central 时显式选择 central 或 all。
| 系统环境 | 支持状态 | 入口 |
|---|---|---|
| macOS | 支持 | scripts/configure-publish-offline.sh |
| Linux | 暂不支持 | 使用 Gradle task 或手动配置。 |
| Windows | 暂不支持 | 使用 Gradle task 或手动配置。 |
先生成配置模板:
scripts/configure-publish-offline.sh :library --generate-only然后在根目录 local.properties 中填写发布配置。敏感字段只用于写入 GitHub repository secrets,local.properties 必须保持 ignored/untracked。
完成配置后执行:
scripts/configure-publish-offline.sh :library --configure-only -- --stacktrace如果配置文件已填好,也可以直接一键执行生成与配置:
scripts/configure-publish-offline.sh :library -- --stacktrace等价 Gradle task:
./gradlew :library:generatePublishConfig
./gradlew :library:configurePublish本地 Maven 发布不需要执行一键发布配置脚本,可直接运行:
./gradlew :library:publishToMavenLocalGitHub Packages 是默认远程发布目标,配置仓库和凭据后执行:
GITHUB_ACTOR=<github-user> \
GITHUB_TOKEN=<token-with-package-write> \
./gradlew :library:PublishLibraryRemoteTask \
-PgithubPackagesRepository=owner/repo \
--stacktrace在根工程 build.gradle.kts 中加入插件依赖:
buildscript {
repositories {
google()
mavenCentral()
mavenLocal()
}
dependencies {
classpath("cn.entertech.android:publish:1.2.3")
}
}在需要发布的 Android Library 模块中应用插件:
plugins {
id("com.android.library")
id("cn.entertech.publish")
}配置最小 PublishInfo:
PublishInfo {
groupId ="cn.entertech.android"
artifactId ="base"
version ="0.0.1"
}发布到本机 Maven 仓库:
./gradlew :library:publishToMavenLocal消费方启用 mavenLocal() 后,通过 Maven 坐标依赖本地发布产物:
dependencies {
implementation("cn.entertech.android:base:0.0.1-local")
}Gradle Plugin 模块需要同时应用 cn.entertech.publish 和 java-gradle-plugin:
plugins {
id("cn.entertech.publish")
`java-gradle-plugin`
}如果项目仍使用 Groovy build.gradle,也可以使用旧写法:
apply plugin: 'cn.entertech.publish'最小 PublishInfo:
PublishInfo {
groupId ="cn.entertech.android"
artifactId ="demo-publish-plugin"
version ="1.0.0"
pluginId ="cn.entertech.demo"
implementationClass ="cn.entertech.demo.DemoPlugin"
}发布到本机 Maven 仓库:
./gradlew :demo-plugin:publishToMavenLocal消费方启用 mavenLocal() 后,可通过 buildscript classpath 引入插件 artifact:
buildscript {
dependencies {
classpath("cn.entertech.android:demo-publish-plugin:1.0.0-local")
}
}然后在消费方模块中应用已发布的 Gradle 插件:
apply(plugin ="cn.entertech.demo")PublishLibraryRemoteTask 是统一远程发布入口。默认远程发布目标是 GitHub Packages;Sonatype Central Portal 和旧自定义 Maven 仓库需要显式选择。
| 目标 | 关键配置 | 命令 |
|---|---|---|
| 本地 Maven | groupId、artifactId、version | ./gradlew :library:publishToMavenLocal |
| GitHub Packages | githubPackagesRepository=owner/repo 或 githubPackagesUrl=...,并提供 GitHub Packages 凭据 | ./gradlew :library:PublishLibraryRemoteTask |
| Sonatype Central Portal | publishTarget=central,Central token,GPG signing,POM/SCM 元数据 | ./gradlew :library:PublishLibraryRemoteTask -PpublishTarget=central |
| 旧自定义 Maven 仓库 | remotePublishMode=customRepository、publishUrl,按需配置用户名和密码 | ./gradlew :library:PublishLibraryRemoteTask -PremotePublishMode=customRepository |
发布到 GitHub Packages:
GITHUB_ACTOR=<github-user> \
GITHUB_TOKEN=<token-with-package-write> \
./gradlew :library:PublishLibraryRemoteTask \
-PgithubPackagesRepository=owner/repo \
--stacktrace发布到 Sonatype Central Portal:
CENTRAL_USERNAME=<central-token-username> \
CENTRAL_PASSWORD=<central-token-password> \
ORG_GRADLE_PROJECT_signingInMemoryKey=<gpg-private-key> \
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword=<gpg-password> \
./gradlew :library:PublishLibraryRemoteTask \
-PpublishTarget=central \
-PcentralNamespace=cn.entertech \
--stacktrace本仓库提供两个可运行示例:
| 模块 | 用途 | 覆盖内容 |
|---|---|---|
demo-lib | Android Library 发布示例 | PublishInfo 基础坐标、POM/Central 元数据、多 flavor release variant、artifactIdForVariant,以及动态 artifactId 辅助逻辑 DemoArtifactNames.kt。 |
demo-plugin | Gradle Plugin 发布示例 | java-gradle-plugin、pluginId、implementationClass、Gradle 插件入口类 DemoPublishPlugin.java、本地 Maven 发布。 |
com.vanniktech.maven.publish 是成熟的通用 Maven 发布插件。它对 Maven Central、签名、sources/javadoc、KMP 等场景支持更完整,但直接替换当前插件会改变已有业务项目的 DSL、任务名和版本基线。以下对比基于当前 cn.entertech.publish 设计,以及 Vanniktech 官方文档中 2026-07-07 可见的 0.37.0 版本信息;后续版本要求以 Vanniktech changelog 为准。
| 维度 | 当前自研 cn.entertech.publish | 直接使用 com.vanniktech.maven.publish | 判断 |
|---|---|---|---|
| 接入方式 | 业务项目继续配置 PublishInfo { ... } | 需要改为 mavenPublishing { ... } 或 Vanniktech 约定属性 | 自研对已有项目迁移成本更低 |
| 旧项目兼容 | 保留 publishUrl、publishUserName、publishPassword、PublishLibraryLocalTask、PublishLibraryRemoteTask | DSL、任务名、属性名都不同 | 自研更适合公司存量项目 |
| 版本基线 | 当前仓库 wrapper 为 Gradle 8.0;插件自身按 Java 8 target、AGP 4.2.0 compileOnly 维护兼容 | 0.37.0 最低要求 JDK 17、Gradle 9.0.0、AGP 8.13.0、KGP 2.2.0 | 直接引入 Vanniktech 会带来明显升级压力 |
| Central Portal 支持 | 已封装 Central staging 上传和 manual upload;状态轮询、deployment validation 仍偏轻 | 内置 Central Portal 发布、自动发布、deployment validation 等能力 | Vanniktech 更成熟 |
| POM 元数据 | Entertech 默认 license/developer/SCM 规则内置,可由 PublishInfo、Gradle property、环境变量覆盖 | 使用通用 DSL 或 Gradle properties 配置 | 自研更贴公司默认值,Vanniktech 更标准 |
| GPG 签名 | 已支持 in-memory key,但签名属性解析和校验由本插件维护 | 内置 CI 友好的 signing 配置 | Vanniktech 维护成本更低 |
| sources/javadoc | 由 PublishInfo.hasSource 控制真实源码是否上传。本地 Maven、GitHub Packages 和 Central 都始终上传 sources.jar:默认 hasSource = false 用只含 README 的占位 jar,hasSource = true 或 -debug 上传真实源码。Central 额外强制 javadoc 和签名 | 自动配置 sources/javadoc,可配合 Dokka | Vanniktech 更完整 |
| Android 多 variant | 只发布 release component,支持 artifactIdForVariant 和 skipVariantIf | 支持 Android variant 发布和过滤,但 DSL 不同 | 两者都能做,自研更贴现有业务规则 |
| Gradle Plugin 发布 | 支持 java-gradle-plugin,并复用公司坐标和 POM 规则 | 也支持 Gradle Plugin 发布 | 能力接近 |
| 旧私服发布 | 保留 remotePublishMode = "customRepository" 和旧私服字段 | 支持发布到任意 Maven repository,但配置方式不同 | 自研迁移成本更低 |
| CI 密钥管理 | 支持公司约定的 Central token、GPG key、SCM fallback 变量 | 支持标准 Gradle properties 和环境变量 | 都可用,Vanniktech 更通用 |
| 维护成本 | Central API、checksum、validation 行为变化需要自研跟进 | 社区插件持续维护这些细节 | Vanniktech 维护成本更低 |
| 可控性 | 可按公司规则定制任务名、默认值、校验和输出日志 | 受第三方插件 DSL 和版本策略约束 | 自研可控性更强 |
| 生态覆盖 | 主要覆盖 Android Library 和 Gradle Plugin | 覆盖 Android、Java、Kotlin Multiplatform、version catalog 等 | Vanniktech 覆盖面更广 |
推荐策略:已有业务项目继续使用 cn.entertech.publish,以保持 PublishInfo 和旧任务名兼容;新项目如果已经满足较新的 Gradle/AGP/Kotlin 基线,可以评估直接使用 Vanniktech。后续也可以在本插件内部增加可选 backend:外部 DSL 仍保持 PublishInfo,环境满足要求时内部委托 Vanniktech,否则继续走当前兼容实现。
PublishInfo 描述要发布的 Maven 坐标、POM 元数据以及多 variant 规则。远程发布目标使用 publishTarget 管理。不同发布场景需要的字段不同:
| 场景 | 必填字段 | 额外要求 |
|---|---|---|
| 本地 Maven 发布 | groupId、artifactId、version | 执行 PublishLibraryLocalTask 或 publishToMavenLocal。不要求 Central 凭据、签名和完整 POM 元数据。 |
| Android Library 远程发 Central | groupId、artifactId、version | pomDescription 默认使用通用 Maven 描述,pomUrl 优先从当前工程 git remote origin 推导,再使用 CI 环境兜底。非 cn.entertech namespace 必须覆盖 centralNamespace。version 不能包含 debug。 |
| Gradle Plugin 远程发 Central | Android Library 远程字段 + pluginId、implementationClass | pluginId 是用户使用 plugins { id("...") } 时看到的插件 ID。 |
| GitHub Packages 发布 | groupId、artifactId、version | 默认远程发布模式。配置 githubPackagesRepository=owner/repo 或 githubPackagesUrl=https://maven.pkg.github.com/owner/repo。凭据建议用 GITHUB_ACTOR / GITHUB_TOKEN,也兼容 gpr.user / gpr.key。 |
| 旧私服发布 | groupId、artifactId、version、remotePublishMode = "customRepository"、publishUrl | publishUserName、publishPassword 按仓库权限需要配置。 |
字段值解析优先级按用途分组:
groupId、artifactId、version直接来自PublishInfo。- Central、License、Developer、SCM 等仓库级字段支持命令行和本地通用配置覆盖:
Gradle property > 环境变量 > PublishInfo 显式配置 > local.properties 中 publish.* 非空值 > 默认/推导值。 pomName、pomDescription、pomUrl属于组件 POM 信息,不从local.properties读取;未显式配置时分别使用 artifactId、组件类型默认描述、当前工程 git remote / CI 推导 URL。publishUrl、publishUserName、publishPassword兼容local.properties:Gradle property > PublishInfo 字段 > local.properties。- GitHub Packages URL 可由
githubPackagesRepository=owner/repo推导;凭据优先使用 Gradle property / 环境变量,再回退到PublishInfo和local.properties中的 GitHub Packages 专用字段或旧私服字段。 - Central token 不建议写进
PublishInfo。优先使用-PcentralUsername/-PcentralPassword或CENTRAL_USERNAME/CENTRAL_PASSWORD。 - GPG signing 信息不是
PublishInfo字段;发布运行时只能通过 Gradle property 或环境变量传入。一键发布配置时可先放在 ignored/untracked 的local.properties中,用于写入 GitHub repository secrets。
local.properties 中的旧私服字段值不要加引号:
publishUrl=https://repo.example.com/releases
publishUserName=username
publishPassword=password一键发布配置用于降低新仓库接入发布能力的初始配置成本,着重点是为目标模块生成可执行的发布 workflow。不同发布目标需要的配置不同:
- 本地 Maven 发布不需要执行一键发布配置脚本,配置
PublishInfo后可直接运行本地发布任务。 - GitHub Packages 是默认远程发布模式,通常只需要配置
PublishInfo和 GitHub Packages 凭据。 - Sonatype Central Portal 需要额外完成仓库级元数据、GitHub repository secrets 和签名密钥配置;这是显式选择
central或all时才需要的配置。
因此,一键发布配置默认生成 GitHub Packages workflow。publish.* 是新的本地配置前缀;旧 centralPublish.* 只作为兼容读取保留。Central token/GPG 字段只在 publishTarget=central 或 publishTarget=all 时生效;publishTarget=central 会让 PublishLibraryRemoteTask 发布到 Central。
组件级信息继续放在目标模块 PublishInfo 中:
PublishInfo {
groupId ="cn.entertech.android"
artifactId ="demo-lib"
version ="1.0.0"
pomName ="Demo Library"
pomDescription ="Demo Android library"
pomUrl ="https://github.com/Entertech/demo-lib"
}仓库级配置和一次性 secret 输入放在根目录 local.properties 的 publish.* 字段中。不要在 local.properties 中声明 groupId、artifactId、version、pluginId、implementationClass、pomName、pomDescription、pomUrl、hasSource、obfuscate 等组件字段。
Codex Skill 方式:
使用 $publishplugin-one-click-publish,帮我为 :library 配置发布。
macOS 离线脚本方式:
scripts/configure-publish-offline.sh :library --generate-only
scripts/configure-publish-offline.sh :library --configure-only -- --stacktraceGradle task 方式:
./gradlew :library:generatePublishConfig
./gradlew :library:configurePublish插件会把发布相关入口注册到 Gradle 的 customPlugin task group 下。日常只需要使用下面这些推荐 task:
| Task | 作用 | 常见场景 |
|---|---|---|
generatePublishConfig | 生成或补全发布配置模板,默认写入根目录 local.properties,保留已有 sdk.dir / ndk.dir 和已有配置值。 | 首次接入发布、补齐缺失的 publish.* 配置。 |
configurePublish | 校验当前模块 PublishInfo,确认配置文件未被 Git 跟踪,按配置写入 GitHub repository secrets,并可生成 GitHub Actions workflow。 | 配好 local.properties 后,一键完成远程发布前置配置。 |
PublishLibraryLocalTask | 校验当前模块发布配置后,执行本模块的 publishToMavenLocal,发布到 ~/.m2/repository/。 | 本地联调、验证 Maven 坐标和 POM 依赖。 |
PublishLibraryRemoteTask | 远程发布统一入口。默认发布到 GitHub Packages,也可通过 publishTarget=central 发布到 Sonatype Central Portal;旧自定义 Maven 仓库保留兼容模式。 | 正式发布到远程 Maven 仓库。 |
rollbackPublishSecrets | 读取同一份发布配置,删除配置过的 GitHub repository secrets,并可按参数删除插件生成的 workflow。 | 回收发布凭据、撤销一键配置产生的远程 secrets。 |
- 在目标模块配置
PublishInfo的坐标和 POM 元数据。 - 生成或更新根目录
local.properties:./gradlew :library:generatePublishConfig
- 填写发布目标和必要的仓库级字段。Android 项目已有的
sdk.dir/ndk.dir会被保留。 - 建议先设置
publish.dryRun=true执行预演。dry run 只做解析、校验和摘要输出,不写.gitignore、workflow、secrets 或 GPG key。 - 确认配置后执行:
./gradlew :library:configurePublish
如果配置文件已存在且需要刷新注释,传入 -PoverwritePublishConfig=true。任务会刷新模板注释,并保留已有 publish.* value 和非 publish.* 行。
# GitHub repository in owner/repo format. Blank tries gh repo view, then git remote origin.publish.githubRepo=Entertech/demo-lib
# Dry-run switch.# true: Print planned files and secret names only. Do not write files or call gh secret set.# false/blank: Run normally.publish.dryRun=false
# Generated workflow publish target.# Blank/default: github_packages.# Supported values: github_packages, central, all.publish.publishTarget=github_packages
# GitHub Packages repository in owner/repo format. Blank uses the workflow caller repository.publish.githubPackagesRepository=
# Optional full GitHub Packages Maven repository URL. Blank derives it from githubPackagesRepository.publish.githubPackagesUrl=
# Sonatype Central namespace. Used when publishTarget is central or all. Blank uses plugin default cn.entertech.publish.centralNamespace=cn.entertech
# Central deployment publishing type.# user_managed: Upload and validate, then leave the deployment in Central Portal for manual Publish.# automatic: Upload and validate, then Central tries to publish to Maven Central automatically.publish.centralPublishingType=user_managed
# Central staging repository name. Blank uses plugin default CentralStaging.publish.centralRepositoryName=
# Shared POM metadata defaults. Blank values use PublishInfo, local inference, or plugin defaults.publish.pomInceptionYear=
publish.licenseName=
publish.licenseUrl=
publish.licenseDistribution=
publish.developerId=
publish.developerName=
publish.developerEmail=
publish.developerOrganization=
publish.developerOrganizationUrl=
publish.developerUrl=
publish.scmUrl=
publish.scmConnection=
publish.scmDeveloperConnection=
# Whether to configure GitHub repository secrets.# true: Call gh secret set for Central token and GPG signing secrets when publishTarget is central or all.# false/blank: Do not process GitHub secrets.publish.githubSecrets=false
# Whether to overwrite existing repository secrets.# true: Overwrite existing secrets.# false/blank: Reuse existing secrets to avoid replacing CI credentials by mistake.publish.overwriteGithubSecrets=false
# Central Portal User Token. Used only by configurePublish for central/all targets.publish.mavenCentralUsername=central-token-username
publish.mavenCentralPassword=central-token-password
# GPG signing secret inputs. Used only by configurePublish for central/all targets.publish.gpgKeyFile=/Users/example/secrets/gpg-private-key.asc
publish.signingPassword=gpg-private-key-password
publish.signingKeyId=
# Repository secret names. Blank values use the defaults shown in the comments below.publish.mavenCentralUsernameSecret=
publish.mavenCentralPasswordSecret=
publish.gpgKeySecret=
publish.signingPasswordSecret=
publish.signingKeyIdSecret=
# Optional local GPG key generation.publish.gpgGenerate=false
publish.gpgKeyType=
publish.gpgKeyLength=
publish.gpgKeyExpire=
publish.gpgName=
publish.gpgEmail=
publish.gpgComment=
# Whether to generate a GitHub Actions workflow.publish.githubActions=true
# Generated workflow path and reusable workflow reference.publish.workflowPath=
publish.workflowUses=Entertech/PublishPlugin/.github/workflows/publish.yml@main模板注释保持 ASCII English,避免 Java .properties 和 IDE 默认编码造成中文注释乱码。
| 字段 | 类别 | 默认/空值行为 | 说明 |
|---|---|---|---|
githubRepo | GitHub 目标仓库 | 空值时尝试 gh repo view,再回退到 git remote origin | GitHub repository,格式为 owner/repo,用于写 secrets 和定位 workflow。 |
dryRun | 执行控制 | false | true 时只打印计划执行内容,不写文件、不写 secrets、不生成 GPG key。 |
publishTarget | GitHub Actions | github_packages | 生成 workflow 的发布目标,可选 github_packages、central、all。 |
githubPackagesRepository | GitHub Packages | 调用 workflow 的仓库 | GitHub Packages 发布仓库,格式为 owner/repo。 |
githubPackagesUrl | GitHub Packages | 由 githubPackagesRepository 推导 | GitHub Packages Maven repository 完整 URL。 |
centralNamespace | Central 发布行为 | cn.entertech | Sonatype Central 已验证 namespace。PublishInfo.groupId 必须等于该值或位于该 namespace 下。 |
centralPublishingType | Central 发布行为 | user_managed | user_managed 上传并校验后需要在 Portal 手动 Publish;automatic 上传校验后自动尝试发布。 |
centralRepositoryName | Central 发布行为 | CentralStaging | Gradle Maven repository 名称,影响任务名,例如 publishEnterPublishPublicationToCentralStagingRepository。 |
pomInceptionYear | 共享 POM 默认值 | 当前年份 | POM <inceptionYear>。只在需要覆盖默认年份时填写。 |
licenseName | 共享 POM 默认值 | The Apache License, Version 2.0 | POM license name。 |
licenseUrl | 共享 POM 默认值 | https://www.apache.org/licenses/LICENSE-2.0.txt | POM license URL。 |
licenseDistribution | 共享 POM 默认值 | repo | POM license distribution。 |
developerId | 共享 POM 默认值 | Entertech | POM developer id。 |
developerName | 共享 POM 默认值 | Entertech | POM developer name。 |
developerEmail | 共享 POM 默认值 | developer@entertech.cn | POM developer email。 |
developerOrganization | 共享 POM 默认值 | Entertech | POM developer organization。 |
developerOrganizationUrl | 共享 POM 默认值 | https://github.com/Entertech | POM developer organization URL。 |
developerUrl | 共享 POM 默认值 | https://github.com/Entertech | POM developer URL。 |
scmUrl | 共享 POM 默认值 | 空值时从当前工程 git remote origin、GitHub Actions、GitLab CI 等推导 | POM SCM browser URL。 |
scmConnection | 共享 POM 默认值 | 空值时由 scmUrl 推导 | POM read-only SCM connection。 |
scmDeveloperConnection | 共享 POM 默认值 | 空值时由 scmUrl 推导 | POM developer SCM connection。 |
githubSecrets | GitHub secrets | false | true 且 publishTarget=central/all 时使用本机 gh 写入 Central token 和 GPG signing repository secrets。 |
overwriteGithubSecrets | GitHub secrets | false | true 时允许覆盖已有 repository secrets;默认复用已有 secrets,避免误替换 CI 凭据。 |
mavenCentralUsername | 一次性 secret 输入 | 无默认值 | Central Portal User Token username,只用于写入 repository secret。 |
mavenCentralPassword | 一次性 secret 输入 | 无默认值 | Central Portal User Token password,只用于写入 repository secret。 |
gpgKeyFile | 一次性 secret 输入 | 无默认值 | GPG ASCII private key 文件路径。需要写入 GPG secret 时必填。 |
signingPassword | 一次性 secret 输入 | 无默认值 | GPG private key password。需要写入 signing password secret 或生成新 key 时必填。 |
signingKeyId | 一次性 secret 输入 | 空值表示运行时由 Gradle signing 从私钥推断 | 可选 GPG key id。通常可以留空。 |
mavenCentralUsernameSecret | secret 名称覆盖 | MAVEN_CENTRAL_USERNAME | Central username repository secret 名称。 |
mavenCentralPasswordSecret | secret 名称覆盖 | MAVEN_CENTRAL_PASSWORD | Central password repository secret 名称。 |
gpgKeySecret | secret 名称覆盖 | GPG_KEY_CONTENTS | GPG private key repository secret 名称。 |
signingPasswordSecret | secret 名称覆盖 | SIGNING_PASSWORD | GPG private key password repository secret 名称。 |
signingKeyIdSecret | secret 名称覆盖 | SIGNING_KEY_ID | GPG key id repository secret 名称。 |
gpgGenerate | GPG 生成 | false | true 时调用本机 gpg 生成新发布签名 key,并覆盖对应 GPG secrets。 |
gpgKeyType | GPG 生成 | RSA | GPG key 类型。当前推荐 RSA。 |
gpgKeyLength | GPG 生成 | 4096 | RSA key length。 |
gpgKeyExpire | GPG 生成 | 无默认值 | GPG key 过期时间,例如 1y、2y、0。0 表示不过期。 |
gpgName | GPG 生成 | 无默认值 | GPG uid name。生成新 key 时必填。 |
gpgEmail | GPG 生成 | 无默认值 | GPG uid email。生成新 key 时必填。 |
gpgComment | GPG 生成 | 空值 | GPG uid comment。 |
githubActions | GitHub Actions | false | true 时生成或更新 GitHub Actions workflow。 |
workflowPath | GitHub Actions | .github/workflows/publish-<module>.yml | 生成 workflow 的路径。 |
workflowUses | GitHub Actions | Entertech/PublishPlugin/.github/workflows/publish.yml@main | 业务仓库调用的 reusable workflow 引用。 |
Central token、GPG key、signing password 在一键发布配置阶段只用于写入 GitHub repository secrets,不会作为发布运行时 fallback。CI 发布时使用 repository secrets:MAVEN_CENTRAL_USERNAME、MAVEN_CENTRAL_PASSWORD、GPG_KEY_CONTENTS、SIGNING_PASSWORD,可选 SIGNING_KEY_ID。
已有 repository secrets GPG_KEY_CONTENTS / SIGNING_PASSWORD 且未配置 publish.gpgGenerate=true 时,任务默认复用现有 GPG secrets,不重新生成 key。仓库只缺其中一个 GPG secret 时,任务只写入缺失的 secret,不覆盖已经存在的 secret;只有配置 publish.overwriteGithubSecrets=true 或 publish.gpgGenerate=true 时才会覆盖。
需要生成新 GPG key 时,配置 publish.gpgGenerate=true、publish.gpgName、publish.gpgEmail、publish.signingPassword、publish.gpgKeyFile 后再运行配置任务。
回退 GitHub repository secrets:
./gradlew :library:rollbackPublishSecrets回退任务会读取同一份 local.properties。如果没有配置 publish.githubRepo,会先尝试通过 gh repo view 推导仓库,再回退到 git remote origin。传入 -PremoveGeneratedWorkflow=true 时,会删除带 # Generated by PublishPlugin configurePublish 标记的 workflow;未显式配置 publish.workflowPath 时,默认删除 .github/workflows/publish-<module>.yml,并兼容清理旧的 .github/workflows/publish-central-<module>.yml。
如果 local.properties 曾被提交,需要先轮换 Central token / GPG key,再用 git filter-repo 或 BFG 清理历史;git replace 不能清理已经 push 到远程、fork、CI logs 或缓存中的泄露内容。
| 字段 | 必填场景 | 说明 |
|---|---|---|
groupId | 所有发布 | Maven 坐标的 groupId。Central 发布时必须落在已验证的 centralNamespace 下,例如 namespace 是 ai.looktech,则 groupId 可以是 ai.looktech 或 ai.looktech.xxx。 |
artifactId | 所有发布 | Maven 坐标的 artifactId。单 publication 直接使用该值;多 release variant 场景下是默认值,可被 artifactIdForVariant 为每个 variant 动态覆盖。 |
version | 所有发布 | Maven 坐标的 version。本地发布时,版本以 -debug 结尾会上传真实 sources jar;远程发布会拒绝包含 debug 的版本。 |
hasSource | 可选,默认 false | 是否上传真实业务源码。false 时本地 Maven、GitHub Packages 和 Central 都传只含 README 的占位 sources.jar。true 上传真实源码。-debug 版本仍会带真实 sources。旧字段 obfuscate 仍可用:obfuscate = true 等于 hasSource = false。该字段只影响源码包内容,不改写模块自己的 R8/isMinifyEnabled。 |
只有发布 Gradle Plugin 模块时需要配置这两个字段;普通 Android Library 不需要。
| 字段 | 必填场景 | 说明 |
|---|---|---|
pluginId | Gradle Plugin 发布 | Gradle 插件 ID,例如 cn.entertech.foo。用户消费插件时写 plugins { id("cn.entertech.foo") }。 |
implementationClass | Gradle Plugin 发布 | 插件入口类全限定名,例如 cn.entertech.foo.FooPlugin。该类必须实现 org.gradle.api.Plugin<Project>。 |
这些字段只影响远程发布任务 PublishLibraryRemoteTask 或标准远程 repository publish 任务;本地 publishToMavenLocal 不要求 Central token 或签名。
| 字段 | 默认值 | 说明 |
|---|---|---|
publishTarget | github_packages | 远程发布目标。github_packages 使用 GitHub Packages;central 使用 Sonatype Central Portal;all 由 reusable workflow 同时发布 GitHub Packages 和 Central。 |
centralNamespace | cn.entertech | Central namespace。发布前会校验 groupId 必须等于该 namespace 或以 ${centralNamespace}. 开头。非 Entertech namespace 必须覆盖该值。 |
centralPublishingType | user_managed | Central Portal deployment 发布方式。user_managed 表示上传并通过校验后,只在 Portal 生成一个待发布的 deployment,需要手动点击 Publish 才会真正发布到 Maven Central,也可以点击 Drop 丢弃;automatic 表示通过校验后自动发布到 Maven Central。Sonatype OSSRH Staging API 还支持 portal_api,但当前插件不会继续调用 Portal Publisher API 跟踪状态,因此不作为推荐值。 |
centralRepositoryName | CentralStaging | Gradle repository 名称,会影响任务名,例如 publishEnterPublishPublicationToCentralStagingRepository。一般不需要改。 |
| 字段 | 生效场景 | 说明 |
|---|---|---|
githubPackagesRepository | publishTarget = "github_packages" | GitHub 仓库,格式为 owner/repo。为空时会尝试使用 GITHUB_REPOSITORY 或当前工程 git remote origin 推导。 |
githubPackagesUrl | githubPackages | Maven 仓库完整地址。优先级高于 githubPackagesRepository 推导值。 |
githubPackagesRepositoryName | githubPackages | Gradle repository 名称,默认 GitHubPackages,会生成 publishEnterPublishPublicationToGitHubPackagesRepository。 |
githubPackagesUsername | githubPackages | GitHub Packages 用户名;CI 通常使用 GITHUB_ACTOR。 |
githubPackagesPassword | githubPackages | GitHub token;CI 通常使用 GITHUB_TOKEN。 |
这些字段保留是为了兼容旧项目;默认 GitHub Packages 和 Central 发布都不建议把凭据写在 build.gradle.kts 里。
| 字段 | 生效场景 | 说明 |
|---|---|---|
publishUrl | remotePublishMode = "customRepository" 兼容模式 | 旧私服 Maven 仓库地址。Central 模式不会把它作为上传地址。 |
publishUserName | customRepository;Central token fallback | 自定义仓库用户名;Central 模式下只作为 token username 的低优先级 fallback。 |
publishPassword | customRepository;Central token fallback | 自定义仓库密码;Central 模式下只作为 token password 的低优先级 fallback。 |
Central 远程发布要求 POM 元数据完整;这些字段本地发布可以为空,执行 PublishLibraryRemoteTask 时会校验。
| 字段 | Central 是否必填 | 说明 |
|---|---|---|
pomName | 否 | POM <name>。为空时使用当前 publication 的最终 artifactId。多 variant 动态 artifactId 场景下,每个 publication 都会用自己的最终 artifactId 作为 fallback。 |
pomDescription | 有效值必需 | POM <description>。为空时 Android Library 默认 Android library published as a Maven artifact,Gradle Plugin 默认 Gradle plugin published as a Maven artifact。 |
pomInceptionYear | 否 | POM <inceptionYear>,默认使用当前年份。只有项目起始年份不是当前年份时才需要覆盖。 |
pomUrl | 有效值必需 | POM <url>,通常是项目主页、Git 仓库或文档地址。为空时优先从当前工程 git remote origin 推导,再使用 GitHub Actions 环境兜底。 |
License 字段会写入 POM。默认使用 Apache-2.0,只有项目许可证不是 Apache-2.0 时才需要改。
| 字段 | 默认值 | 说明 |
|---|---|---|
licenseName | The Apache License, Version 2.0 | POM license name。 |
licenseUrl | https://www.apache.org/licenses/LICENSE-2.0.txt | POM license URL。 |
licenseDistribution | repo | POM license distribution。 |
Central 远程发布会校验开发者信息。插件默认使用 Entertech 信息,业务项目如需显示自己的组织或维护者,可以覆盖这些字段。
| 字段 | 默认值 | 说明 |
|---|---|---|
developerId | Entertech | 开发者或组织 ID。 |
developerName | Entertech | 开发者或组织名称。 |
developerEmail | developer@entertech.cn | 联系邮箱。 |
developerOrganization | Entertech | 组织名称。 |
developerOrganizationUrl | https://github.com/Entertech | 组织主页。 |
developerUrl | https://github.com/Entertech | 开发者主页。 |
Central 远程发布要求源码仓库信息。插件会按以下顺序推导 scmUrl:
-PscmUrl / SCM_URL > PublishInfo.scmUrl > git remote origin
> GitHub Actions(GITHUB_SERVER_URL + GITHUB_REPOSITORY) > GitLab CI(CI_PROJECT_URL)
> GIT_URL / BUILD_REPOSITORY_URI
scmConnection 和 scmDeveloperConnection 如果未显式配置,会根据最终 scmUrl 自动生成。以 https://github.com/Entertech/PublishPlugin 为例:
| 字段 | 说明 | 示例 |
|---|---|---|
scmUrl | 仓库浏览地址,可由 CI 或本地 Git 推导 | https://github.com/Entertech/PublishPlugin |
scmConnection | 只读 SCM 地址,可由 scmUrl 推导 | scm:git:https://github.com/Entertech/PublishPlugin.git |
scmDeveloperConnection | 开发者 SCM 地址,可由 scmUrl 推导 | scm:git:ssh://git@github.com/Entertech/PublishPlugin.git |
groupIdForVariant { variant -> ... }、artifactIdForVariant { variant -> ... }、versionForVariant { variant -> ... } 和 skipVariantIf { variant -> ... } 只对 Android Library 的 release variant 生效。无 flavor 的普通 release 组件不会传入 variant 回调,直接使用 groupId、artifactId、version。
| API/字段 | 作用 | 说明 |
|---|---|---|
groupIdForVariant | 为每个 release variant 返回独立 groupId | 返回空字符串时回退到 groupId。 |
artifactIdForVariant | 为每个 release variant 返回独立 artifactId | 返回空字符串时回退到 artifactId。适合多 flavor 输出不同 Maven 坐标。 |
versionForVariant | 为每个 release variant 返回独立 version | 返回空字符串时回退到 version。本地发布仍会追加 -local 后缀。 |
skipVariantIf | 过滤不需要发布的 release variant | 返回 true 时跳过该 variant,不注册 publication,也不会生成对应 publish 任务。 |
variant.name | 当前 component/variant 名 | 例如 breathAuthRelease。 |
variant.buildType | 当前 build type | 当前插件只发布 release component。 |
variant.flavors | flavor 维度到 flavor 名称的 Map | 例如 project -> breath、authentication -> auth。 |
variant.flavor("dimension") | 获取指定维度的 flavor 名称 | 不存在时返回空字符串,便于安全拼接 artifactId。 |
如果只是想在当前项目里生成一个本地 AAR 文件,不需要执行发布任务,直接使用 Android Gradle Plugin 的 assemble 任务。
单一 release 组件:
./gradlew :module:assembleRelease生成目录:
module/build/outputs/aar/
常见产物名:
module-release.aar
如果 Library 有 flavor,需要执行具体 variant 的 assemble 任务:
./gradlew :affective_local_sdk:assembleBreathAuthRelease
./gradlew :affective_local_sdk:assembleBreathNoAuthRelease也可以一次构建所有 release variant:
./gradlew :affective_local_sdk:assembleRelease多 flavor AAR 仍输出在模块的 build/outputs/aar/ 目录下,文件名由 Android Gradle Plugin 按 variant 生成,例如:
affective_local_sdk-breath-auth-release.aar
affective_local_sdk-breath-noAuth-release.aar
assemble... 只负责生成 AAR 文件,不会写入 ~/.m2,也不会生成可供其他项目通过 Maven 坐标依赖的本地库。
执行模块下的自定义任务:
./gradlew :module:PublishLibraryLocalTask或直接使用 Gradle Maven Publish 标准任务:
./gradlew :module:publishToMavenLocal本地和远程发布的 sources 规则:
- 本地发布时,实际 publication version 会使用
-local后缀;version = "1.0.0"会发布为1.0.0-local。 - 如果
PublishInfo.version已经以-local结尾,则保持原值,不会追加成-local-local。 PublishInfo.hasSource默认false,表示不上传真实业务源码。本地 Maven、GitHub Packages 和 Central Portal 都会上传sources.jar,但内容是只含 README 的占位包。hasSource = true时上传真实 sources jar,适合开源组件。version以-debug结尾时,即使hasSource = false也会发布真实 sources jar。- Central 远程发布额外附带 javadoc 和 GPG 签名。
hasSource只决定各目标的sources.jar是占位包还是真实源码。
发布成功后,产物会进入本机 Maven 仓库:
~/.m2/repository/<group-path>/<artifactId>/<version>/
例如:
~/.m2/repository/cn/entertech/android/affective-offline-sdk/1.0.0-local/
多 variant 发布时,每个未过滤的 release variant 都会生成独立 artifact 目录,并且目录里应至少包含 .aar、.pom、.module:
~/.m2/repository/cn/entertech/android/breath-affective-offline-sdk-authentication/1.3.6-local/
~/.m2/repository/cn/entertech/android/breath-affective-offline-sdk/1.3.6-local/
~/.m2/repository/cn/entertech/android/sdk-affective-offline-sdk-authentication/1.3.6-local/
~/.m2/repository/cn/entertech/android/sdk-affective-offline-sdk/1.3.6-local/
验证本地发布不能只看 BUILD SUCCESSFUL。如果 Gradle 显示成功但目标 artifact 目录没有 .aar/.pom/.module,说明 publication 没有真实执行,应优先检查插件日志和 publishToMavenLocal --stacktrace 输出。
其他项目使用本地发布产物时,需要在仓库中启用 mavenLocal():
repositories {
google()
mavenCentral()
mavenLocal()
}然后按 Maven 坐标依赖:
dependencies {
implementation("cn.entertech.android:affective-offline-sdk:1.0.0-local")
}多 variant 动态 artifactId 场景下,依赖最终生成的 artifactId:
dependencies {
implementation("cn.entertech.android:breath-affective-offline-sdk-authentication:1.0.0-local")
implementation("cn.entertech.android:breath-affective-offline-sdk:1.0.0-local")
}使用 PublishLibraryLocalTask 发布成功后,控制台会打印可直接复制的 Groovy DSL 和 Kotlin DSL dependencies { ... } 依赖代码块。
选择方式:
| 目标 | 使用命令 | 产物位置 | 适合场景 |
|---|---|---|---|
只要一个 .aar 文件 | assembleRelease 或具体 assemble<Variant>Release | module/build/outputs/aar/ | 手动拷贝、临时检查 AAR 内容 |
| 让其他项目通过 Maven 坐标依赖 | PublishLibraryLocalTask 或 publishToMavenLocal | ~/.m2/repository/ | 本地联调、验证 POM 依赖、模拟远程发布消费方式 |
GitHub Packages 是默认远程发布目标。发布前需要确认模块已经配置 PublishInfo 的 Maven 坐标:
PublishInfo {
groupId ="cn.entertech.android"
artifactId ="demo-lib"
version ="1.0.0"
}执行远程发布任务:
./gradlew :module:PublishLibraryRemoteTask显式指定 GitHub Packages repository:
GITHUB_ACTOR=<github-user> \
GITHUB_TOKEN=<token-with-package-write> \
./gradlew :module:PublishLibraryRemoteTask \
-PgithubPackagesRepository=owner/repo \
--stacktrace也可以在 PublishInfo 中固定仓库信息:
PublishInfo {
githubPackagesRepository ="owner/repo"
githubPackagesRepositoryName ="GitHubPackages"
}githubPackagesRepository=owner/repo 会推导出 Maven repository URL:
https://maven.pkg.github.com/owner/repo
这个 URL 是 Gradle/Maven repository endpoint,不是浏览器网页详情页;直接在浏览器打开可能显示 404 page not found。发布成功后请在 GitHub 仓库的 Packages 页面查看包,例如 https://github.com/owner/repo/packages,或带 GitHub Packages 认证访问具体 POM/metadata 路径验证。
如果需要直接覆盖完整地址,使用 githubPackagesUrl:
./gradlew :module:PublishLibraryRemoteTask \
-PgithubPackagesUrl=https://maven.pkg.github.com/owner/repo \
--stacktrace凭据来源建议使用 CI 环境变量:
| 用途 | 推荐环境变量 | 兼容 Gradle property |
|---|---|---|
| GitHub Packages 用户名 | GITHUB_ACTOR 或 GITHUB_PACKAGES_USER | -PgithubPackagesUsername=... 或 -Pgpr.user=... |
| GitHub Packages token | GITHUB_TOKEN 或 GITHUB_PACKAGES_TOKEN | -PgithubPackagesPassword=... 或 -Pgpr.key=... |
GitHub Actions 中可以使用默认 GITHUB_TOKEN,但 repository/package 权限必须允许写入 packages:
permissions:
contents: writepackages: write消费 GitHub Packages 产物时,业务工程需要配置同一个 Maven repository,并提供具备 package read 权限的 GitHub token:
repositories {
google()
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/owner/repo")
credentials {
username = providers.gradleProperty("gpr.user").orNull
?:System.getenv("GITHUB_ACTOR")
password = providers.gradleProperty("gpr.key").orNull
?:System.getenv("GITHUB_TOKEN")
}
}
}发布到 Central Portal 时,需要显式指定 publishTarget=central,并先确认这些事项:
- 发布账号已经在 Central Portal 验证过对应 namespace。
groupId必须等于该 namespace 或位于该 namespace 下;如果不是cn.entertech,必须配置centralNamespace或通过-PcentralNamespace=...覆盖。 - 模块已应用
cn.entertech.publish。Android Library 模块需要配置groupId、artifactId、version、pomDescription、pomUrl;Gradle Plugin 模块还需要配置pluginId和implementationClass。 - Central 凭据不要写入
build.gradle.kts。CI 中使用 Central Portal 生成的 User Token,传入CENTRAL_USERNAME/CENTRAL_PASSWORD,或使用兼容变量MAVEN_CENTRAL_USERNAME/MAVEN_CENTRAL_PASSWORD。 - GPG 签名信息必须由 CI 或命令行注入。通常传
ORG_GRADLE_PROJECT_signingInMemoryKey和ORG_GRADLE_PROJECT_signingInMemoryKeyPassword;key id 可以不传,让 Gradle 从私钥内容推断。 - SCM 信息默认会先从当前工程
git remote origin推导,再使用 GitHub Actions、GitLab CI、GIT_URL、BUILD_REPOSITORY_URI兜底。如果仍拿不到仓库地址,显式传-PscmUrl=...;scmConnection和scmDeveloperConnection会自动根据scmUrl生成。 version不能包含debug,并且发布到 Maven Central 的版本号不能复用;同一个坐标版本已经发布后不能覆盖。- 默认
centralPublishingType = "user_managed"。构建上传成功后,还需要登录 Central Portal 手动点击 Publish 才会真正发布到 Maven Central;如果要自动发布,再改成automatic。 - 如果业务仓库使用本仓库的 reusable workflow,需要使用
secrets: inherit,并确保 organization secrets 的 repository access 已授权给调用 workflow 的仓库。
Central 必需配置示例。centralNamespace、Developer、SCM、pomInceptionYear 都有默认或推导值;如果发布的 namespace 不是 cn.entertech,必须覆盖 centralNamespace:
PublishInfo {
groupId ="ai.looktech.ltrpc.schema"
artifactId ="bt-server"
version ="1.0.0"
centralNamespace ="ai.looktech"
centralPublishingType ="user_managed"
pomName ="Looktech RPC BT Server Schema"
pomDescription ="BT Server Schema library for Looktech RPC"
pomUrl ="https://github.com/Entertech/lt-rpc-schema"
}Central token 和签名建议通过环境变量或 Gradle property 注入,不要写入仓库:
CENTRAL_USERNAME="$TOKEN_USERNAME" \
CENTRAL_PASSWORD="$TOKEN_PASSWORD" \
ORG_GRADLE_PROJECT_signingInMemoryKey="$GPG_PRIVATE_KEY" \
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword="$GPG_PASSWORD" \
./gradlew :module:PublishLibraryRemoteTask \
-PpublishTarget=central \
-PcentralNamespace=ai.looktech \
-PcentralPublishingType=user_managed \
--stacktraceORG_GRADLE_PROJECT_signingInMemoryKeyId 可以不传。默认建议只传私钥内容和密码,让 Gradle 从 GPG_PRIVATE_KEY 中推断 key id;只有确实需要指定 key id 时,才传 8 位或 16 位 hex key id,例如 00B5050F、0x00B5050F 或 2BA16C9B594CE0E6。
支持的 Central 相关字段:
PublishInfo {
githubPackagesRepository ="owner/repo"
githubPackagesRepositoryName ="GitHubPackages"
centralNamespace ="cn.entertech"
centralPublishingType ="user_managed"// user_managed / automatic
centralRepositoryName ="CentralStaging"
pomName =""
pomDescription =""
pomInceptionYear ="<当前年份>"// 默认当前年份,通常不用配置
pomUrl =""
licenseName ="The Apache License, Version 2.0"
licenseUrl ="https://www.apache.org/licenses/LICENSE-2.0.txt"
licenseDistribution ="repo"
developerId ="Entertech"
developerName ="Entertech"
developerEmail ="developer@entertech.cn"
developerOrganization ="Entertech"
developerOrganizationUrl ="https://github.com/Entertech"
developerUrl ="https://github.com/Entertech"
scmUrl =""// 为空时优先从当前工程 git remote origin 推导,CI 环境兜底
scmConnection =""// 为空时根据 scmUrl 推导
scmDeveloperConnection =""// 为空时根据 scmUrl 推导
}centralPublishingType 对应 Sonatype Central 的 deployment 发布方式:
user_managed:默认值。上传并通过校验后,只会在 Central Portal 生成一个待发布的 deployment;此时还没有真正发布到 Maven Central,需要登录 Portal 手动点击 Publish 才会发布,也可以点击 Drop 丢弃这次上传。automatic:上传并校验后,如果校验通过,Central 会尝试自动发布到 Maven Central。
也就是说,user_managed 下“上传成功”不等于“已经发布成功”;它适合第一次发布、测试发布或需要人工检查产物后再确认发布的场景。确认 CI 发版流程稳定后,可以考虑切到 automatic。
Sonatype OSSRH Staging API 文档还列出 portal_api,它只上传 deployment,期望调用方继续使用 Portal Publisher API 查询状态和执行后续操作。当前插件没有实现这套后续 API 流程,因此建议只使用 user_managed 或 automatic。参考 Sonatype 文档:Publish OSSRH Staging API 和 Publish Portal API。
PublishInfo.artifactId 是默认 artifactId,也是没有 variant 回调时的 fallback。
当 Android Library 存在多个 release variant 时,插件会为每个 release component 创建独立 publication:
- 无 flavor 的普通
release组件仍使用旧 publication 名:EnterPublish。 - 配置了
groupIdForVariant、artifactIdForVariant或versionForVariant时,多 flavor release 组件使用<VariantName>EnterPublish,例如BreathAuthReleaseEnterPublish。 - 没有配置 variant 级坐标时,只注册并发布第一个可发布的 release variant,publication 名仍为
EnterPublish,避免多个 publication 使用同一 Maven 坐标互相覆盖。 PublishLibraryRemoteTask检测到多个*EnterPublishpublication 时,会执行publishAllPublicationsTo<RepositoryName>Repository。
如果需要按 variant 动态设置 Maven 坐标,使用 groupIdForVariant、artifactIdForVariant、versionForVariant:
val baseArtifactId ="affective-offline-sdk"PublishInfo {
groupId ="cn.entertech.android"
artifactId = baseArtifactId
version ="1.0.0"
groupIdForVariant { variant ->if (variant.flavor("project") =="sdk") {
"cn.entertech.android.sdk"
} else {
"cn.entertech.android.breath"
}
}
artifactIdForVariant { variant ->val productPrefix ="${variant.flavor("project")}-"val authSuffix =if (variant.flavor("authentication") =="auth") {
"-authentication"
} else {
""
}
"$productPrefix$baseArtifactId$authSuffix"
}
versionForVariant { variant ->if (variant.flavor("authentication") =="auth") {
"1.0.0-auth"
} else {
"1.0.0"
}
}
}对应 Groovy DSL:
def baseArtifactId ='affective-offline-sdk'PublishInfo {
groupId ='cn.entertech.android'
artifactId = baseArtifactId
version ='1.0.0'
groupIdForVariant { variant->return variant.flavor('project') =='sdk'?'cn.entertech.android.sdk':'cn.entertech.android.breath'
}
artifactIdForVariant { variant->def productPrefix ="${variant.flavor('project')}-"def authSuffix = variant.flavor('authentication') =='auth'?'-authentication':''return"${productPrefix}${baseArtifactId}${authSuffix}"
}
versionForVariant { variant->return variant.flavor('authentication') =='auth'?'1.0.0-auth':'1.0.0'
}
}示例结果:
| Variant | artifactId |
|---|---|
breathAuthRelease | breath-affective-offline-sdk-authentication |
breathNoAuthRelease | breath-affective-offline-sdk |
sdkAuthRelease | sdk-affective-offline-sdk-authentication |
sdkNoAuthRelease | sdk-affective-offline-sdk |
PublishVariantInfo 可用字段:
variant.name // 例如 breathAuthRelease
variant.buildType // 例如 release
variant.flavors // Map<String, String>
variant.flavor("project") // 例如 breath / sdk
variant.flavor("authentication") // 例如 auth / noAuth没有配置 groupIdForVariant、artifactIdForVariant 或 versionForVariant 时,多 flavor 模块只发布一次,并使用 PublishInfo 中的固定 groupId、artifactId 和 version。
如果某些 variant 不需要发布,使用 skipVariantIf:
PublishInfo {
groupId ="cn.entertech.android"
artifactId ="affective-offline-sdk"
version ="1.0.0"
skipVariantIf { variant ->
variant.flavor("project") =="flowtime"
}
}也可以只发布指定 product:
PublishInfo {
groupId ="cn.entertech.android"
artifactId ="affective-offline-sdk"
version ="1.0.0"
skipVariantIf { variant ->
variant.flavor("project") !="sdk"
}
}过滤规则:
- 未配置
skipVariantIf时发布所有 release variants。 - 可配置多个
skipVariantIf,任意一个返回true就跳过该 variant。 - 被跳过的 variant 不会注册
singleVariant,不会创建 publication,也不会生成对应publish...PublicationToMavenLocal任务。 - 如果所有候选 release variants 都被跳过,插件会让构建失败,避免出现没有实际发布内容的假成功。
CI 或本地临时发布时,建议用 Gradle property 或环境变量覆盖敏感信息和临时元数据,不要把 token、密码、GPG 私钥写入 build.gradle.kts。
常用覆盖项:
| 用途 | Gradle property | 环境变量 | 说明 |
|---|---|---|---|
| 发布目标 | -PpublishTarget=github_packages | PUBLISH_TARGET | 可选 github_packages / central / all。旧 -PremotePublishMode / REMOTE_PUBLISH_MODE 仅兼容读取。 |
| GitHub Packages 仓库 | -PgithubPackagesRepository=owner/repo | GITHUB_PACKAGES_REPOSITORY / GITHUB_REPOSITORY | 用于推导 https://maven.pkg.github.com/owner/repo。 |
| GitHub Packages URL | -PgithubPackagesUrl=... | GITHUB_PACKAGES_URL | 显式覆盖完整 Maven repository URL。 |
| GitHub Packages 用户名 | -PgithubPackagesUsername=... / -Pgpr.user=... | GITHUB_PACKAGES_USER / GITHUB_ACTOR / USERNAME | GitHub Packages repository credentials username。 |
| GitHub Packages Token | -PgithubPackagesPassword=... / -Pgpr.key=... | GITHUB_PACKAGES_TOKEN / GITHUB_TOKEN / TOKEN | GitHub Packages repository credentials password/token。 |
| 发布版本 | -PpublishVersion=... / -Pversion=... | PUBLISH_VERSION | 临时覆盖 PublishInfo.version。publishVersion 优先级更高;version 用于兼容 reusable workflow 的 version 输入。 |
| 源码包 | -PhasSource=true / -PhasSource=false | PUBLISH_HAS_SOURCE | 覆盖 PublishInfo.hasSource。true 上传真实 sources;false 上传占位 sources.jar。旧参数 -Pobfuscate / PUBLISH_OBFUSCATE 仍可用,语义相反。不要使用无前缀的 HAS_SOURCE 或 OBFUSCATE 环境变量。 |
| Central namespace | -PcentralNamespace=... | CENTRAL_NAMESPACE | 覆盖 PublishInfo.centralNamespace。 |
| Central 发布方式 | -PcentralPublishingType=user_managed | CENTRAL_PUBLISHING_TYPE | 可选 user_managed / automatic。 |
| Central release 类型 | -PcentralReleaseType=snapshot | CENTRAL_RELEASE_TYPE | 可选 release / snapshot。snapshot 使用 CentralSnapshots 和 https://central.sonatype.com/repository/maven-snapshots/。 |
| Central repository 名称 | -PcentralRepositoryName=CentralStaging | CENTRAL_REPOSITORY_NAME | 一般不需要改。 |
| Central token username | -PcentralUsername=... | CENTRAL_USERNAME | 优先级高于旧字段 publishUserName。 |
| Central token password | -PcentralPassword=... | CENTRAL_PASSWORD | 优先级高于旧字段 publishPassword。 |
| Central token username fallback | -PmavenCentralUsername=... | MAVEN_CENTRAL_USERNAME | 兼容已有 CI 变量名。 |
| Central token password fallback | -PmavenCentralPassword=... | MAVEN_CENTRAL_PASSWORD | 兼容已有 CI 变量名。 |
| POM name | -PpomName=... | POM_NAME | 覆盖 PublishInfo.pomName。 |
| POM description | -PpomDescription=... | POM_DESCRIPTION | 覆盖 PublishInfo.pomDescription。 |
| POM URL | -PpomUrl=... | POM_URL | 覆盖 PublishInfo.pomUrl。 |
| SCM URL | -PscmUrl=... | SCM_URL | 覆盖 SCM 仓库浏览地址;为空时从当前工程 git remote / CI 推导。 |
| SCM connection | -PscmConnection=... | SCM_CONNECTION | 覆盖只读 SCM 地址;为空时根据 scmUrl 推导。 |
| SCM developer connection | -PscmDeveloperConnection=... | SCM_DEVELOPER_CONNECTION | 覆盖开发者 SCM 地址;为空时根据 scmUrl 推导。 |
| GPG 私钥 | -PsigningInMemoryKey=... | SIGNING_IN_MEMORY_KEY / GPG_KEY_CONTENTS | Central 发布必需。 |
| GPG 私钥密码 | -PsigningInMemoryKeyPassword=... | SIGNING_IN_MEMORY_KEY_PASSWORD / SIGNING_PASSWORD | Central 发布必需。 |
| GPG key id | -PsigningInMemoryKeyId=... | SIGNING_IN_MEMORY_KEY_ID / SIGNING_KEY_ID | 可选;通常留空让 Gradle 从私钥推断。 |
旧私服字段的解析优先级不同:
publishUrl / publishUserName / publishPassword:
Gradle property > PublishInfo 字段 > local.properties
Central token 的解析优先级:
centralUsername / centralPassword:
Gradle property > 环境变量 > mavenCentral* fallback > PublishInfo 旧字段 > local.properties
业务项目可以调用本仓库提供的 reusable workflow 发布远程 Maven 产物。publish_target 不传时默认是 github_packages,也可以显式选择三种模式:
| publish_target | 行为 | 需要的凭据 |
|---|---|---|
central | 只发布到 Sonatype Central Portal | Central token、GPG signing secrets。 |
github_packages | 只发布到 GitHub Packages | GITHUB_TOKEN 或 GITHUB_PACKAGES_TOKEN,并授予 packages write 权限。 |
all | 先发布 GitHub Packages,再发布 Sonatype Central Portal | 同时满足上面两类凭据。 |
publish_mode 控制同一个 workflow 的发布语义:
| publish_mode | 行为 |
|---|---|
release | 正式发布。版本号保持 1.2.3,Central 走 release/staging 仓库;如果 sync_readme=true,发布成功后同步 README 并提交。 |
ci | CI 快照打包。只允许 publish_target=central;版本自动追加 -SNAPSHOT,发布到 https://central.sonatype.com/repository/maven-snapshots/;不更新 README。 |
业务项目不需要在各自仓库里单独维护 GPG 私钥和 Central token。把这些敏感字段配置为 Entertech organization secrets 后,业务项目只调用本仓库提供的 reusable workflow,并使用 secrets: inherit 继承组织级 secrets。
name: Publish Mavenon:
workflow_dispatch:
jobs:
publish:
uses: Entertech/PublishPlugin/.github/workflows/publish.yml@mainsecrets: inheritwith:
module: ":library"publish_target: "central"publish_mode: "release"version: "1.2.3"sync_readme: truenamespace: "cn.entertech"publishing_type: "user_managed"通过本仓库 skill 触发 CI 打包时使用 publish_mode: "ci"。该模式只支持 Central,workflow 会把 version: "1.2.3" 实际发布为 1.2.3-SNAPSHOT,并发布到 Sonatype Central snapshots 仓库;不会同步 README。
name: Publish CI Snapshoton:
workflow_dispatch:
jobs:
publish:
uses: Entertech/PublishPlugin/.github/workflows/publish.yml@mainsecrets: inheritwith:
module: ":library"publish_target: "central"publish_mode: "ci"version: "1.2.3"namespace: "cn.entertech"publishing_type: "user_managed"name: Publish GitHub Packageson:
workflow_dispatch:
permissions:
contents: writepackages: writejobs:
publish:
uses: Entertech/PublishPlugin/.github/workflows/publish.yml@mainwith:
module: ":library"publish_target: "github_packages"publish_mode: "release"version: "1.2.3"sync_readme: truegithub_packages_repository: "owner/repo"github_packages_repository 为空时会使用调用 workflow 的仓库。需要发布到其他仓库或使用 PAT 时,可以配置 repository secret GITHUB_PACKAGES_TOKEN,并使用 secrets: inherit 继承给 reusable workflow。
name: Publish Mavenon:
workflow_dispatch:
permissions:
contents: writepackages: writejobs:
publish:
uses: Entertech/PublishPlugin/.github/workflows/publish.yml@mainsecrets: inheritwith:
module: ":library"publish_target: "all"publish_mode: "release"namespace: "cn.entertech"publishing_type: "user_managed"version: "1.2.3"sync_readme: truegithub_packages_repository: "owner/repo"如果发布时需要临时覆盖版本,三种发布模式都可以传入;当开启 sync_readme 时,version 也是 README 版本同步的来源:
with:
module: ":library"publish_target: "all"publish_mode: "release"namespace: "cn.entertech"publishing_type: "user_managed"github_packages_repository: "owner/repo"version: "1.2.3"configurePublish 生成的 workflow 默认使用 publish_mode: "release",会传入 version 并开启 sync_readme。reusable workflow 发布成功后会把 README「代码配置」章节中的插件版本同步为本次发布版本;如果发布目标包含 github_packages,根工程插件仓库配置会切换为对应的 https://maven.pkg.github.com/owner/repo,否则保持 mavenCentral()。
Entertech organization secrets 需要维护:
MAVEN_CENTRAL_USERNAME
MAVEN_CENTRAL_PASSWORD
GPG_KEY_CONTENTS
SIGNING_PASSWORD
可选 secret:
SIGNING_KEY_ID
MAVEN_CENTRAL_USERNAME 和 MAVEN_CENTRAL_PASSWORD 必须使用 Central Portal 生成的 User Token。GPG_KEY_CONTENTS 和 SIGNING_PASSWORD 使用公司统一发布 GPG key。SIGNING_KEY_ID 建议留空,让 Gradle 从 GPG_KEY_CONTENTS 私钥内容推断;如果配置,必须是 Gradle signing 支持的 PGP key id,例如 00B5050F、0x00B5050F 或 16 位 long key id。业务仓库无需重复创建这些 secrets,但 organization secret 的 repository access 必须授权给调用 workflow 的仓库。
PublishPlugin 自身是 Gradle Plugin 模块,不通过自己的 PublishLibraryRemoteTask 发布。发布插件本身使用仓库内的 GitHub Actions:
.github/workflows/publish-plugin-central.yml
发布流程:
- PR 合入预发布分支
pre_publish前,publish-plugin-pr-check.yml校验版本号、构建、本地发布和 publication 元数据,并同步 README 中的插件版本。 - PR 合入
pre_publish后,publish-plugin-central.yml自动发布插件到 Central。 - 发布版本会自动规范化为
数字.数字.数字,例如1.2.0-local会发布为1.2.0;如果无法识别出三段数字,workflow 失败。 - 发布前先预演
pre_publish合入main,如果存在冲突,workflow 直接失败,不发布 Central。 - 同一个
pre_publish发布 run 正在执行时,如果又有新的提交 push 到pre_publish,旧 run 会被自动取消。 - Central deployment 创建成功后,workflow 再次同步 README 和根
build.gradle.kts中的插件版本,并把变更提交回pre_publish。 - 版本同步提交成功后,workflow 创建并推送
v<version>tag。 - tag 推送成功后,workflow 将当前
pre_publishmerge 到main。 - 如果 Central 发布失败,不会更新 README,不会创建 tag,也不会合入
main。
手动触发或自动发布时需要配置这些 secrets:
MAVEN_CENTRAL_USERNAME
MAVEN_CENTRAL_PASSWORD
GPG_KEY_CONTENTS
SIGNING_PASSWORD
SIGNING_KEY_ID 是可选项。为空时发布 workflow 不会传 key id 给 Gradle,Gradle 会从 GPG_KEY_CONTENTS 推断;如果填了 40 位 fingerprint,workflow 会自动截取最后 16 位作为 long key id;如果填了邮箱、描述文本等非法值,workflow 会清空该值并回退到从私钥推断,避免 Could not read PGP secret key。
发布坐标:
cn.entertech.android:publish:1.2.3
cn.entertech.publish:cn.entertech.publish.gradle.plugin:1.2.3
其中第二个是 Gradle plugin marker,用于支持:
plugins {
id("cn.entertech.publish") version "1.2.3"
}