Gradle 和 Maven
Gradle 插件之 maven-publish
maven-publish 介绍
maven-publish 官方文档:publishing_maven.htmlmaven
插件已经过时,官方推荐使用 maven-publish
插件来实现将我们的代码发布到 Apache Maven 仓库的功能。
maven-publish 插件引入
- groovy 脚本引入
1
2
3
4
// build.gradle
plugins {
id 'maven-publish'
}
- kts 脚本引入
1
2
3
4
// build.gradle.kts
plugins {
`maven-publish`
}
基础概念
Tasks
所有以下任务都归在名为 publishing 类型为 PublishingExtension
的扩展下。
- generatePomFileFor
PubName
Publication
为名为PubName
的发布创建一个 POM 文件,填充已知元数据,如项目名称、项目版本和依赖项。生成的 POM 文件默认放在build/publications/$pubName/pom-default.xml
. - publish
PubName
PublicationToRepoName
Repository
将名为PubName
的发布发布到名为RepoName
的存储库中。如果您有一个没有显式名称的存储库定义,那么 RepoName 将是 Maven。 - publish
PubName
PublicationToMavenLocal
将 PubName
发布复制到 mavenLocal 缓存—通常是 $USER_HOME/.m2/repository
——连同发布的 POM 文件和其他元数据一起。
- publish
依赖:所有 publishPubNamePublicationToRepoNameRepository 任务。将所有已定义的发布发布到所有已定义存储库的聚合任务。它不包括将发布复制到 mavenLocal
- publishToMavenLocal
依赖:所有 publishPubNamePublicationToMavenLocal 任务。将所有已定义的发布复制 mavenLocal 存,包括它们的元数据 (POM 文件等)。
Publications
Maven 发布中的配置主要有四种:
- A component
通过MavenPublication.from(org.gradle.api.component.SoftwareComponent)
配置 - Custom artifacts
通过MavenPublication.artifact(java.lang.Object)
方法配置。查看 MavenArtifact 获取所有可配置选项。 - Standard metadata
标准元数据,例如 artifactId, groupId and version. - Other contents of the POM file
通过 MavenPublication.pom(org.gradle.api.Action) 配置
groovy:
1
2
3
4
5
6
7
8
9
10
11
12
// build.gradle
publishing {
publications {
maven(MavenPublication) {
groupId = 'org.gradle.sample'
artifactId = 'library'
version = '1.1'
from components.java
}
}
}
kotlin:
1
2
3
4
5
6
7
8
9
10
11
12
// build.gradle.kts
publishing {
publications {
create<MavenPublication>("maven") {
groupId = "org.gradle.sample"
artifactId = "library"
version = "1.1"
from(components["java"])
}
}
}
Repositories
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
publishing {
repositories {
maven {
// 基于版本名称选择不同的仓库地址
def releasesRepoUrl = "$buildDir/repos/releases"
def snapshotsRepoUrl = "$buildDir/repos/snapshots"
// url是必须要配置的
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
// 仓库用户名密码
credentials {
username = "root"
password = "root"
}
}
}
}
POM
pom 文件定于了一个 maven 项目的 maven 配置,一般 pom 文件的放在项目或者模块的根目录下
maven:pom 文件详解
https://blog.csdn.net/weixin_38569499/article/details/91456988
maven-plugin 插件 pom 文件生成
Android Library
Android 插件所创建的组件取决于模块是否使用应用或库插件,如下表所述。
Android Gradle 插件 | 发布内容工件 | 组件名称 |
---|---|---|
com.android.library | AAR | components.variant |
com.android.application | APK 和可用的 ProGuard 或 R8 映射文件的 ZIP | components.variant_apk |
com.android.application | Android App Bundle (AAB) | components.variant_aab |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
afterEvaluate {
publishing {
publications {
// Creates a Maven publication called "release".
release(MavenPublication) {
// Applies the component for the release build variant.
from components.release
// You can then customize attributes of the publication as shown below.
groupId = 'me.hacket'
artifactId = 'pagergridlayoutmanager'
version = '1.0.0'
}
}
}
}
或者 pom.withXml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
private def getArtifactFilePath(Project p) {
def isJavaPlugin = p.plugins.hasPlugin("java")
def isAndroidLibPlugin = p.plugins.hasPlugin('com.android.library')
def artifactFilePath = ""
if (isAndroidLibPlugin) {
if (isReleaseBuild()) {
artifactFilePath = "${p.buildDir}/outputs/aar/${project.name}-release.aar"
} else {
artifactFilePath = "${p.buildDir}/outputs/aar/${project.name}-debug.aar"
}
} else {
if (isReleaseBuild()) {
artifactFilePath = "${p.buildDir}/libs/${project.name}.jar"
} else {
artifactFilePath = "${p.buildDir}/libs/${project.name}.jar"
}
}
// println("=========== afterEvaluate ${p.name} isJavaPlugin=$isJavaPlugin, isAndroidLibPlugin=$isAndroidLibPlugin, artifactFilePath=$artifactFilePath")
return artifactFilePath
}
project.afterEvaluate {
Project p = it
publishing {
publications {
"${getPublicationName()}"(MavenPublication) {
groupId Config.groupId // com.company.project
artifactId p.name // my-component-library
version Config.versionName // 1.0.0-SNAPSHOT
artifact getArtifactFilePath(p)
println("=========== afterEvaluate -> publishing -> publications ${p.name} groupId=${Config.groupId} , artifactId=${p.name}, version=${Config.versionName}, artifact=${getArtifactFilePath(p)}")
// // To include project dependencies
try {
// pom.withXml {
// def dependencies = asNode().appendNode('dependencies')
// println("=========== afterEvaluate ${p.name} dependencies=$dependencies")
// configurations.getByName("${getPublicationName()}CompileClasspath").getResolvedConfiguration().getFirstLevelModuleDependencies().each {
// def dependency = dependencies.appendNode('dependency')
// dependency.appendNode('groupId', it.moduleGroup)
// dependency.appendNode('artifactId', it.moduleName)
// dependency.appendNode('version', it.moduleVersion)
// }
// }
// 或者
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.implementation.allDependencies.each {
// 避免出现空节点或 artifactId=unspecified 的节点
if (it.group != null && (it.name != null && "unspecified" != it.name) && it.version != null) {
println it.toString()
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
dependencyNode.appendNode('scope', 'implementation')
}
}
}
} catch (Exception e) {
e.printStackTrace()
println("=========== afterEvaluate ${p.name} e=$e")
}
}
}
repositories {
maven {
name = "repo"
url = "${rootDir}/repo"
}
maven {
name = "GitLab"
url "https://gitlab.com/api/v4/projects/${Config.gitLabProjectId}/packages/maven"
credentials(HttpHeaderCredentials) {
name = "Private-Token"
value = Config.gitLabAccessToken
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
}
}
Java 项目
1
2
3
4
5
6
7
8
publications {
Production(MavenPublication) {
from components.java
groupId = "me.ele"
artifactId = "lancet-plugin"
version = "1.0.0"
}
}
components.java,会自动生成 pom.xml
案例
简洁版(不支持输出 source)
- groovy 版本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// build.gradle
plugins {
id "java"
id "maven-publish"
}
publishing {
publications {
release(MavenPublication) {
from components.java
groupId = "me.hacket"
artifactId = "my-java-plugin2"
version = "0.0.1"
}
}
repositories {
mavenLocal()
}
}
- kts 版本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// build.gradle.kts
plugins {
java
kotlin("jvm") // version "1.3.50"
maven-publish
}
publishing {
publications {
create<MavenPublication>("release") {
from(components["java"])
groupId = "me.hacket"
artifactId = "my-kt-plugin1"
version = "0.0.1"
}
}
repositories {
mavenLocal()
}
}
完整例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
apply plugin: 'maven-publish'
// 输出source
task generateSourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
getArchiveClassifier().set('sources')
}
def versionName = "2.7.0-SNAPSHOT"
publishing {
publications {
Production(MavenPublication) {
// 使用方引用 implementation 'cn.com.jack:mavendemo:2.7.0-SNAPSHOT'
groupId = "cn.com.jack"
artifactId = "mavendemo"
version = versionName
// 依赖 bundleReleaseAar 任务,并上传其产出的aar
afterEvaluate { artifact(tasks.getByName("bundleReleaseAar")) }
// 也可以指定上传的AAR包,但是需要先手动生成aar
// artifact("$buildDir/outputs/aar/${project.getName()}-debug.aar")
// 上传source,这样使用放可以看到方法注释
artifact generateSourcesJar
// pom文件中声明依赖,从而传递到使用方
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.implementation.allDependencies.each {
// 避免出现空节点或 artifactId=unspecified 的节点
if (it.group != null && (it.name != null && "unspecified" != it.name) && it.version != null) {
println it.toString()
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
dependencyNode.appendNode('scope', 'implementation')
}
}
}
}
}
repositories {
// 定义一个 maven 仓库
maven {
// 可以有且仅有一个仓库不指定 name 属性,会隐式设置为 Maven
// 根据 versionName 来判断仓库地址
url = versionName.endsWith('SNAPSHOT') ? SNAPSHOT_REPOSITORY_URL : RELEASE_REPOSITORY_URL
// 仓库用户名密码
credentials {
username = "shine"
password = "shine"
}
}
// 定义第二个 maven 仓库,名为 Nexus
maven {
// 必须显示指定 name
name = "nexus"
url = versionName.endsWith('SNAPSHOT') ? SNAPSHOT_REPOSITORY_URL : RELEASE_REPOSITORY_URL
}
}
}
案例 2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
打包源码
task generateSourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
getArchiveClassifier().set('sources')
// classifier 'sources'
}
apply plugin: 'maven-publish'
afterEvaluate {
publishing {
publications {
release(MavenPublication) {
from components.release
// 指定group/artifact/version信息,可以不填。默认使用项目group/name/version作为groupId/artifactId/version
groupId = Config.Maven.groupId
artifactId = "${project.name.toLowerCase()}"
version = Config.moduleVersion[project.name.toLowerCase()]
// 配置上传源码
// 上传source,这样使用方可以看到方法注释
artifact generateSourcesJar
}
}
repositories {
// mavenLocal()
maven {
url = "${rootDir}/repo"
}
// credentials {
// username 'xxx'
// password 'xxx'
// }
}
}
}
发布三方 aar 到 maven repo
当 module 作为 sdk 同时又依赖 aar 时,此时接入 sdk 会报错,提示引用不到 aar 中的类
解决 1:直接把 aar 给到业务测,业务测直接依赖
解决 2:将三方 aar 也发布到 maven 仓库,当作远端依赖来依赖
- 去除要发布的 moduleA 的本地 aar 依赖(如
api fileTree(dir: "libs", include: ["_.jar", "_.aar"])
),不然执行 gradle task publishShanYanSdkPublicationToMavenRepository 会编译出错 - 定义 maven-publish 的配置
- 通过 gradle task publishShanYanSdkPublicationToMavenRepository 就其发布到本地 repo
- 和 remote 方式一样依赖这个 aar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
apply plugin: 'maven-publish'
publishing {
publications {
// gradlew publishMicroTTSPublicationToMavenRepository
// implementation 'com.microsoft.cognitiveservices.speech:sdk:1.23.0'
microTTS(MavenPublication) {
artifact("./libs/client-sdk-embedded-static-1.23.0-beta.0.29448579.aar") {
groupId 'com.microsoft.cognitiveservices.speech'
artifactId 'sdk'
version '1.23.0'
}
}
// 地平线
// gradlew publishAntaresManagerPublicationToMavenRepository
// implementation 'com.horizon.antares:sdk:1.1.0'
antaresManager(MavenPublication) {
artifact("./libs/antares_manager.aar") {
groupId 'com.horizon.antares'
artifactId 'sdk'
version '1.0.0'
}
}
}
repositories {
maven {
url "${rootDir}/repo"
}
}
}
AGP3.6.0+ 更简便方式获取 components
Android Gradle 插件 3.6.0 及更高版本(说的是这里 classpath 'com.android.tools.build:gradle:3.6.0'
)支持 Maven Publish Gradle 插件,可让您将构建工件发布到 Apache Maven 代码库。Android Gradle 插件会为应用或库模块中的每个构建变体工件创建一个组件,您可以使用它来自定义要发布到 Maven 代码库的发布内容。
Android 插件所创建的组件取决于模块是否使用应用或库插件,如下表所述。
Android Gradle 插件 | 发布内容工件 | 组件名称 |
---|---|---|
com.android.library | AAR | components.variant |
com.android.application | APK 和可用的 ProGuard 或 R8 映射文件的 ZIP | components.variant_apk |
com.android.application | Android App Bundle (AAB) | components.variant_aab |
- library,release 就是
components.release
,debug 就是components.debug
- application,release 就是
components.release_apk
,debug 就是components.debug_apk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apply plugin: "maven-publish"
afterEvaluate {
publishing {
publications {
Production(MavenPublication) {
from components.release_apk
groupId = "me.hacket"
artifactId = "my-android-plugin3"
version = "1.0.0"
}
}
repositories {
mavenLocal()
}
}
}
获取 module 中已有的 components
1
2
3
4
5
task printComponents(group: 'tools', description: project.name) {
doLast {
println("Components: " + components*.name)
}
}
执行 gradlew printComponents
输出:Components: [all, debug, release]
多 productFlavor 情况
自定义 maven-publish 插件
使用:
1
2
3
4
5
6
7
apply plugin: 'qb-maven-publish'
publishConfig {
isEnable = true
groupId = "me.hacket"
artifactId = "core"
version = "1.0.0"
}
源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class PublishMavenPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
// 是否有com.android.library插件
if (!project.plugins.hasPlugin("com.android.library")) {
throw new RuntimeException("Plugin(qb-maven-publish) requires the 'com.android.library' plugin to be configured.", null)
}
project.extensions.create("publishConfig", PublishConfig)
project.afterEvaluate {
def myConfig = project.extensions.getByType(PublishConfig)
println("Plugin(qb-maven-publish) publishConfig extensions: " + myConfig)
if (!myConfig.isEnable) {
println("Plugin(qb-maven-publish) isEnable=false!")
return
}
project.plugins.apply MavenPublishPlugin
PublishingExtension mavenPublishingExt = project.extensions.getByType(PublishingExtension)
for (SoftwareComponent components : project.components) {
mavenPublishingExt.publications({ publications ->
publications.create(components.name, MavenPublication.class, { MavenPublication pub ->
pub.groupId = myConfig.getGroupId()
pub.artifactId = myConfig.getArtifactId(project)
pub.version = myConfig.version
pub.from(components)
def generateSourcesJarTask = project.tasks.create("generateSourcesJarMaven${components.name.capitalize()}", GenerateSourcesJarTask)
pub.artifact(generateSourcesJarTask)
pub.pom {
mavenPom -> configPom(mavenPom, myConfig)
}
})
})
}
mavenPublishingExt.repositories { artifactRepositories ->
artifactRepositories.maven { mavenArtifactRepository ->
mavenArtifactRepository.url = myConfig.getRepoUrl(project)
if (myConfig.isNeedLogin()) {
mavenArtifactRepository.credentials {
credentials ->
credentials.username = myConfig.repoName
credentials.password = myConfig.repoPassword
}
}
}
}
}
}
private static void configPom(MavenPom mavenPom, PublishConfig config) {
mavenPom.name = config.pomName
mavenPom.description = config.pomDescription
mavenPom.url = config.pomUrl
}
}
具体代码见大圣助手 maven_publish_qb
module
遇到的问题
1、找不到插件类
1
2
3
What went wrong:
An exception occurred applying plugin request [id: 'appinit-auto-register']
> Could not find implementation class 'me.hacket.appinit.autoregister.AppInitAutoRegisterPlugin' for plugin 'appinit-auto-register' specified in jar:file:/C:/Users/hacket/.gradle/caches/jars-9/a6583eb47811da0aaaa4984b4cc74a47/appinit-1.0.0.jar!/META-INF/gradle-plugins/appinit-auto-register.properties.
现象: 生成的 jar 中没有 classes
解决:
将 groovy 代码移动到 groovy 的 sourcesets 目录下
2、找不到 AppExtension
1
2
3
An exception occurred applying plugin request [id: 'appinit-auto-register']
> Failed to apply plugin 'appinit-auto-register'.
> No such property: AppExtension for class: me.hacket.appinit.autoregister.AppInitAutoRegisterPlugin
原因:
复制过来的代码,没有自动导包 AppExtension
3、Could not get unknown property ‘release’ for SoftwareComponentInternal
1
2
A problem occurred evaluating project ':Modularization2'.
> Could not get unknown property 'release' for SoftwareComponentInternal set of type org.gradle.api.internal.component.DefaultSoftwareComponentContainer.
解决:需要将插件配置写在 afterEvaluate
里面:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
afterEvaluate {
publishing {
publications {
release(MavenPublication) {
from components.release
groupId = "me.hacket"
artifactId = "${project.name}"
version = "1.0.0"
}
}
repositories {
maven {
url = "${rootDir}/repo"
}
}
}
}
gradle-maven-publish-plugin:三方 maven-publish 增强插件
https://github.com/vanniktech/gradle-maven-publish-plugin
MavenCentral 发布流程
准备 maven 仓库
注册 maven 账号
https://issues.sonatype.org/secure/Dashboard.jspa
创建 Project
如 AppInit
过几分钟在 Projects
→Community Support - Open Source Project Repository Hosting
下,选择 Switch filter,Reported by me
OSSRH-86107 AppInit
- 证明自己的域名或者在 github 创建公开的仓库 OSSRH-86107
- 将状态更改为 OPEN
- 过一会状态改为 RESOLVED 就可以用了
登录 maven
maven 登录地址:https://s01.oss.sonatype.org/
账号密码:hacket/*#Zfs
配置 GPG
具体见 Git ssh key和deploy-keys(GPG).md
核心信息:
1
2
3
4
pub rsa3072 2022-11-13 [SC] [expires: 2024-11-12]
76EE3442B366C8120B552703890A6B2749FAA5EA
uid hacket <shengfanzeng@gmail.com>
sub rsa3072 2022-11-13 [E] [expires: 2024-11-12]
配置上传 maven:
1
2
3
4
5
6
7
8
# maven账号密码
mavenCentralUsername=hacket
mavenCentralPassword=xxx
# GPG keyId、密码和gpg文件
signing.keyId=49FAA5EA
signing.password=zfs1314520
signing.secretKeyRingFile=/Users/hacket/.gnupg/secring.gpg
maven 上传插件 gradle-maven-publish-plugin
https://github.com/vanniktech/gradle-maven-publish-plugin
docs: https://vanniktech.github.io/gradle-maven-publish-plugin/central/
参考用法见:https://github.com/cashapp/turbine
引入插件
1
2
3
4
5
6
7
8
9
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.7.20'
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.14.2'
}
}
1
2
3
4
5
plugins {
// ...
id 'org.jetbrains.dokka' // 低版本需要
id 'com.vanniktech.maven.publish'
}
Secrets(配置 Maven 账号密码和 GPG key 和密码)
在 ~/.gradle/gradle.properties
将 secret.gpg 复制到~/.gradle/gradle.properties 目录下去
1
2
3
4
5
6
7
8
9
10
11
# GPG
signing.keyId=00581DF6
signing.password=zfs1314520
signing.secretKeyRingFile=secret.gpg
## nexus账号信息,也就是创建issue时的账号和密码
mavenCentralUsername=hacket
mavenCentralPassword=*#Zfs1314520
### 有的是这个?
ossrhUsername=hacket
ossrhPassword=*#Zfs1314520
配置 group,version 和 artifactId(默认 project.name)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SONATYPE_HOST=DEFAULT
## or when publishing to https://s01.oss.sonatype.org
#SONATYPE_HOST=S01
RELEASE_SIGNING_ENABLED=true
POM_NAME=AppInit
POM_DESCRIPTION=A small library for Android startup init task.
POM_INCEPTION_YEAR=2021
POM_URL=https://github.com/hacket/AppInit
POM_SCM_URL=https://github.com/hacket/AppInit
POM_SCM_CONNECTION=scm:git:git://github.com/hacket/AppInit
POM_SCM_DEV_CONNECTION=scm:git:git://github.com/hacket/AppInit
POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=hacket
POM_DEVELOPER_NAME=hacket
POM_DEVELOPER_URL=https://github.com/hacket/
在每个单独的 module 配置 group 和 version
1
2
group = 'io.github.hacket'
version = '1.0.0'
发布
1
./gradlew publishAllPublicationsToMavenCentral
或 publish task
发布 library
- 在左侧面板 Staging Repositories
- 选中要发布的 Repository
- 点击 Release,会弹窗进行二次 Confirm
- 确认无误后,发布
搜索
搜索你刚刚发布的 library
https://s01.oss.sonatype.org/#welcome
遇到的问题
Cannot get stagingProfiles for account
secret.gpg 找不到
报错:
1
2
3
Execution failed for task ':appInit-api:signMavenPublication'.
> Error while evaluating property 'signatory' of task ':appInit-api:signMavenPublication'
> Unable to retrieve secret key from key ring file 'F:\Workspace\AppInit\appInit-api\C:Usershacket.gradlesecret.gpg' as it does not exist
解决:windows 系统下 secretKeyRingFile 用/而不是\
1
2
3
4
# GPG
signing.keyId=00581DF6
signing.password=zfs1314520
signing.secretKeyRingFile=C:/Users/hacket/.gradle/secret.gpg
plugins 引入找不到插件
1
2
3
4
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'appinit-auto-register' version '1.0.0' apply false
}
报错:
1
2
* Exception is:
org.gradle.api.plugins.UnknownPluginException: Plugin [id: 'appinit-auto-register', version: '1.0.0', apply: false] was not found in any of the following sources:
解决:在根 build.gradle 中
1
2
3
4
5
buildscript {
dependencies {
classpath "io.github.hacket:appinit-auto-register:1.0.0"
}
}
Ref
- MavenCentral 发布流程
https://juejin.cn/post/7023219116534136840
GitHub Packages
什么是 GitHub Packages?
GitHub Package Registry 是一个包托管服务,类似 npm、gem、docker 之类的,允许开发者在上面托管包和代码,当然可以是私有的或公开的,并将它们用作项目中的依赖
GitHub Packages 不支持像 jcenter、jitpack 那样的匿名下载
步骤
添加项目的 token
个人账号 Settings
→ Developer settings
→Personal access tokens
→后续操作:
- Note:填写 Token 名字
- Expiration:选择有效期
- Select scopes:
repo/write:packages/delete:packages
- Generate token
将 user 和 token 配置到 gradle.properties
1
2
3
4
#------ Github name&ntoken ------
gpr.user=hacket
gpr.key=xxx
#------ Github name&token ------
添加 maven-publish 脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apply plugin: 'maven-publish'
afterEvaluate {
publishing {
publications {
release(MavenPublication) {
from components.release
groupId = Config.Maven.groupId
artifactId = "${project.name}"
version = Config.moduleVersion[project.name]
}
}
repositories {
maven {
name = "HacketGitHubPackages"
url = "https://maven.pkg.github.com/hacket/Maven"
credentials {
username = project.findProperty("gpr.user")
password = project.findProperty("gpr.key")
}
}
}
}
}
发布脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
CUR_DIR=$(cd `dirname $0` && pwd -P)
echo 'relocation to project root dir'
module=('libcommon' 'libwidget' 'core')
echo ${module[@]}
for m in ${module[@]}
do
sed -i "" "/$m/s/false/true/g" gradle.properties
sed -n "/^$m.*/p" gradle.properties
./gradlew :$m:publishReleasePublicationToHacketGitHubPackagesRepository
sed -i "" "/$m/s/true/false/g" gradle.properties
sed -n "/^$m.*/p" gradle.properties
done
Ref
- Working with the Gradle registry
https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry - 把 Android Module 的 aar 包发布到 GitHub Packages
https://apqx.me/post/original/2020/12/04/把Android-Module的aar包发布到GitHub-Packages上.html - gradle 发布 jar 到 GitHub Packages
https://juejin.cn/post/7007289428158709797
GitLab Packages
步骤
- Preference→Access Tokens→Private Access Tokens
- maven-publish 脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
apply plugin: 'maven-publish'
static def isReleaseBuild() {
return true
}
// gitlab
class Config {
static groupId = "me.hacket"
static versionName = "1.0.0"
static gitLabAccessToken = "glpat-xxx"
static gitLabProjectId = "52451437"
}
def getOutputDir() {
if (isReleaseBuild()) {
return "${project.buildDir}/releases"
} else {
return "${project.buildDir}/snapshots"
}
}
private def getArtifactFilePath(Project p) {
def isJavaPlugin = p.plugins.hasPlugin("java")
def isAndroidLibPlugin = p.plugins.hasPlugin('com.android.library')
def artifactFilePath = ""
if (isAndroidLibPlugin) {
if (isReleaseBuild()) {
artifactFilePath = "${p.buildDir}/outputs/aar/${project.name}-release.aar"
} else {
artifactFilePath = "${p.buildDir}/outputs/aar/${project.name}-debug.aar"
}
} else {
if (isReleaseBuild()) {
artifactFilePath = "${p.buildDir}/libs/${project.name}.jar"
} else {
artifactFilePath = "${p.buildDir}/libs/${project.name}.jar"
}
}
// println("=========== afterEvaluate ${p.name} isJavaPlugin=$isJavaPlugin, isAndroidLibPlugin=$isAndroidLibPlugin, artifactFilePath=$artifactFilePath")
return artifactFilePath
}
static def getPublicationName() {
if (isReleaseBuild()) {
return "release"
} else {
return "debug"
}
}
project.afterEvaluate {
Project p = it
publishing {
publications {
"${getPublicationName()}"(MavenPublication) {
groupId Config.groupId // com.company.project
artifactId p.name // my-component-library
version Config.versionName // 1.0.0-SNAPSHOT
artifact getArtifactFilePath(p)
println("=========== afterEvaluate -> publishing -> publications ${p.name} groupId=${Config.groupId} , artifactId=${p.name}, version=${Config.versionName}, artifact=${getArtifactFilePath(p)}")
// // To include project dependencies
try {
// pom.withXml {
// def dependencies = asNode().appendNode('dependencies')
// println("=========== afterEvaluate ${p.name} dependencies=$dependencies")
// configurations.getByName("${getPublicationName()}CompileClasspath").getResolvedConfiguration().getFirstLevelModuleDependencies().each {
// def dependency = dependencies.appendNode('dependency')
// dependency.appendNode('groupId', it.moduleGroup)
// dependency.appendNode('artifactId', it.moduleName)
// dependency.appendNode('version', it.moduleVersion)
// }
// }
// 或者
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.implementation.allDependencies.each {
// 避免出现空节点或 artifactId=unspecified 的节点
if (it.group != null && (it.name != null && "unspecified" != it.name) && it.version != null) {
println it.toString()
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
dependencyNode.appendNode('scope', 'implementation')
}
}
}
} catch (Exception e) {
e.printStackTrace()
println("=========== afterEvaluate ${p.name} e=$e")
}
}
}
repositories {
maven {
name = "repo"
url = "${rootDir}/repo"
}
maven {
name = "GitLab"
url "https://gitlab.com/api/v4/projects/${Config.gitLabProjectId}/packages/maven"
credentials(HttpHeaderCredentials) {
name = "Private-Token"
value = Config.gitLabAccessToken
}
authentication {
header(HttpHeaderAuthentication)
}
}
maven {
name = "HacketGitHubPackages"
url = "https://maven.pkg.github.com/hacket/Maven"
credentials {
username = project.findProperty("gpr.user")
password = project.findProperty("gpr.key")
}
}
}
}
}
- gradlew publish
- 查看 gitlab packages
https://gitlab.com/hacket/debugtools/-/packages
https://github.com/hacket?tab=packages&repo_name=Maven
Ref
Nexus 搭建私有仓库
安装 Nexus
- 下载免费版
https://www.sonatype.com/nexus-repository-oss - 解压
用tar zxvf nexus-3.13.0-01-mac.tgz
解压 - 启动
找到nexus-xxx/bin
目录
用 nexus start
启动
- 浏览器打开
http://127.0.0.1:8081/
配置 Nexus
用默认账号登录 admin/admin123
然后新增一个用户
http://127.0.0.1:8081/repository/AndroidCoreLib/
遇到的问题
如果用的 mac 自带解压工具,可能启动不了,会出现启动报错,用 nexus run
查看报错原因:
1
Could not resolve mvn:org.apache.felix/org.apache.felix.framework/5.6.2
解决,由于解压方式不对,要用 tar 命令:
1
tar zxvf nexus-3.13.0-01-mac.tgz
发布到 localMaven
- 定义
maven_local_publish.gradle
1
2
3
4
5
6
7
8
9
10
11
apply plugin: 'maven'
apply from: "$rootDir/config/gradle/config.gradle"
uploadArchives {
repositories {
mavenDeployer {
repository(url: uri(project.POM_REPOSITORY_REPO))
pom.groupId = project.POM_GROUP_ID
pom.version = project.POM_VERSION_NAME
}
}
}
- gradle.properties 定义相关信息
1
2
3
4
5
#需要发布到localMaven的时候才设置为true,开发false
publishToLocalMaven=false
POM_GROUP_ID=qsbk.app.voice
POM_VERSION_NAME=0.5.0
POM_REPOSITORY_REPO=/Users/zengfansheng/maven/chatroom
- 本地 localMaven 引入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
}
}
allprojects {
repositories {
jcenter()
maven {
url 'file:///Users/zengfansheng/maven/chatroom'
}
}
}
- 发布 Android studio 项目到本地 Maven 仓库
https://juejin.im/entry/583edfafa22b9d006c25bfaa