---
url: /zh/artifact/maven.md
---
## 前置准备

1. [创建制品库](./intro.md#创建制品库)

2. [获取制品库的地址](./intro.md#获取制品库的地址)

3. [创建令牌](./intro.md#创建访问令牌)

## 本地开发

### 配置凭证

::: tabs
@tab Maven

将以下内容复制至settings.xml文件，替换 `<YOUR_TOKEN>` 为您的令牌， `<REPO_RUL>` 为制品库地址

```xml
<settings>
  <servers>
    <server>
      <id>cnb-maven-repo</id>
      <username>cnb</username>
      <!-- 替换为访问令牌 -->
      <password><YOUR_TOKEN></password>
    </server>
  </servers>
  <profiles>
    <profile>
      <id>cnb-maven-repo-profile</id>
      <repositories>
        <repository>
          <!-- 须与 server 的 id 一致 -->
          <id>cnb-maven-repo</id>
          <!-- 替换为制品库地址 -->
          <!-- 示例 
          <url>https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/</url>
          -->
          <url><REPO_URL></url>
        </repository>
      </repositories>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
    </profile>
  </profiles>
</settings>
```

@tab Gradle kotlin

1. 在项目根目录的gradle.properties中配置令牌，将 `<YOUR_TOKEN>` 替换为您的令牌

```properties
cnbArtifactsGradlePassword=<YOUR_TOKEN>
```

2. 粘贴以下内容到 build.gradle.kts 中，将 `<REPO_RUL>` 替换为制品库地址

```kotlin
publishing {
    repositories {
        maven {
            val cnbArtifactsGradlePassword = project.findProperty("cnbArtifactsGradlePassword")
            
            // 示例
            // url = uri("https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/")
            url = uri("<REPO_URL>")
            credentials {
                username = "cnb"
                password = cnbArtifactsGradlePassword.toString()
            }
        }
    }
}
```

@tab Gradle groovy

1. 在项目根目录的gradle.properties中配置令牌，将 `<YOUR_TOKEN>` 替换为您的令牌

```properties
cnbArtifactsGradlePassword=<YOUR_TOKEN>
```

2. 粘贴以下内容到build.gradle中，将 `<REPO_RUL>` 替换为制品库地址

```groovy
publishing {
      repositories {
        maven {
            def cnbArtifactsGradlePassword = project.findProperty('cnbArtifactsGradlePassword')

            // 示例 
            // url = uri("https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/")
            url = uri('<REPO_URL>')
            credentials {
                username = 'cnb'
                password = cnbArtifactsGradlePassword.toString()
            }
        }
    }
}
```

:::

### 拉取制品

::: tabs
@tab Maven

1. 在 pom.xml 中配置您需要拉取的包

```xml
<dependencies>
    <dependency>
        <groupId>[GROUP_ID]</groupId>
        <artifactId>[ARTIFACT_ID]</artifactId>
        <version>[VERSION]</version>
    </dependency>
</dependencies>

<!-- 示例
<dependencies>
    <dependency>
        <groupId>org.cnb</groupId>
        <artifactId>maven_demo</artifactId>
        <version>9.0.0</version>
    </dependency>
</dependencies> -->
```

2. 拉取制品

```shell
mvn clean install
# 如果选择指定位置的 settings.xml 请执行
mvn clean install -s ./settings.xml
```

@tab Gradle kotlin

1. 在 build.gradle.kts 中配置您所需要的依赖

```kotlin
dependencies {
  implementation("[GROUP_ID]:[ARTIFACT_ID]:[VERSION]")
}

// 示例
// dependencies {
//  implementation("com.google.guava:guava:32.1.3-jre")
// }
```

2. 拉取制品

```bash
./gradlew build --refresh-dependencies
```

@tab Gradle groovy

1. 在 build.gradle 中配置您所需要的依赖

```groovy
dependencies {
    implementation '[GROUP_ID]:[ARTIFACT_ID]:[VERSION]'
}

// 示例
// dependencies {
//   implementation 'com.google.guava:guava:32.1.3-jre'
// }
```

2. 拉取制品

```bash
./gradlew build --refresh-dependencies
```

:::

### 推送制品

::: tabs
@tab Maven

1. 在 pom.xml 中配置发布仓库，制品属性，替换 `<REPO_URL>` 为制品库地址

```xml
<project>
  <modelVersion>4.0.0</modelVersion>
  <!-- 制品属性 -->
  <groupId>[GROUP_ID]</groupId>
  <artifactId>[ARTIFACT_ID]</artifactId>
  <version>[VERSION]</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <!-- 发布仓库 -->
  <distributionManagement>
    <repository>
      <!-- 须与 settings.xml 中 server 的 id 一致 -->
      <id>cnb-maven-repo</id>
      <name>cnb-maven-repo</name>
      <!-- 示例 
      <url>https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/</url>
      -->
      <url><REPO_URL></url>
    </repository>
  </distributionManagement>
</project>
```

2. 推送制品

```shell
mvn deploy
# 如果选择指定位置的 settings.xml，请执行
mvn deploy -s ./settings.xml
```

@tab Gradle kotlin

1. 粘贴以下内容到 build.gradle.kts 中

```kotlin
plugins {
    `java-library`
    `maven-publish`
}

group = "[GROUP_ID]"
version = "[VERSION]"
val artifactName = "[ARTIFACT_ID]"

publishing {
    publications {
        create<MavenPublication>("myLibrary") {
            groupId = group.toString()
            version = version.toString()
            artifactId = artifactName
            from(components["java"])
        }
    }
}
```

2. 执行上传命令

```shell
./gradlew publish
```

@tab Gradle groovy

1. 粘贴以下内容到 build.gradle 中

```groovy
plugins {
    id 'java-library'
    id 'maven-publish'
}

group = '[GROUP_ID]'
version = '[VERSION]'
def artifactName = '[ARTIFACT_ID]'

publishing {
    publications {
        myLibrary(MavenPublication) {
            groupId = group
            version = version
            artifactId = artifactName
            from components.java
        }
    }
}
```

2. 执行上传命令

```shell
./gradlew publish
```

:::

## 云原生构建

### 配置凭证

云原生构建使用令牌有三种方式，参考[云原生构建，云原生开发中使用令牌](./intro.md#在云原生构建，云原生开发中使用令牌)，以下是具体客户端的使用方式

::: tabs
@tab Maven

替换 `<REPO_URL>` 为制品库地址

```xml
<settings>
  <servers>
    <server>
      <id>cnb-maven-repo</id>
      <username>cnb</username>
      <!--第一种方式 使用内置环境变量 CNB_TOKEN-->
      <password>${env.CNB_TOKEN}</password>
      <!--第二种方式 直接使用，替换 <YOUR_TOKEN> 为您的令牌即可-->
      <!--<password><YOUR_TOKEN></password>-->
      <!--第三种方式，密钥仓库，替换 <ENV_NAME> 为您密钥仓库的变量-->
      <!--<password>${env.<ENV_NAME>}</password>-->
    </server>
  </servers>
  <profiles>
    <profile>
      <id>cnb-maven-repo-profile</id>
      <repositories>
        <repository>
          <!-- 须与 server 的 id 一致 -->
          <id>cnb-maven-repo</id>
          <!-- 示例 
          <url>https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/</url>
          -->
          <url><REPO_URL></url>
        </repository>
      </repositories>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
    </profile>
  </profiles>
</settings>
```

@tab Gradle kotlin

替换 `<REPO_URL>` 为制品库地址

```kotlin
publishing {
    repositories {
        maven {
            // 第一种方式 使用内置环境变量 CNB_TOKEN
            val cnbArtifactsGradlePassword = System.getenv("CNB_TOKEN")
            // 第二种方式 直接使用令牌，替换<YOUR_TOKEN>为您的令牌
            // val cnbArtifactsGradlePassword = "<YOUR_TOKEN>"
            // 第三种方式，密钥仓库，替换 <ENV_NAME> 为您密钥仓库的变量
            // val cnbArtifactsGradlePassword = System.getenv("ENV_NAME")

            // 示例 
            // url = uri("https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/")
            url = uri("<REPO_URL>")
            credentials {
                username = "cnb"
                password = cnbArtifactsGradlePassword.toString()
            }
        }
    }
}
```

@tab Gradle groovy

替换 `<REPO_URL>` 为制品库地址

```groovy
publishing {
      repositories {
        maven {
            // 第一种方式 使用内置环境变量 CNB_TOKEN
            def cnbArtifactsGradlePassword = System.getenv("CNB_TOKEN")
            // 第二种方式 直接使用令牌，替换<YOUR_TOKEN>为您的令牌
            // def cnbArtifactsGradlePassword = '<YOUR_TOKEN>'
            // 第三种方式，密钥仓库，替换 <ENV_NAME> 为您密钥仓库的变量
            // def cnbArtifactsGradlePassword = System.getenv("ENV_NAME")

            // 示例 
            // url = uri("https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/")
            url = uri('<REPO_URL>')
            credentials {
                username = 'cnb'
                password = cnbArtifactsGradlePassword.toString()
            }
        }
    }
}
```

:::

### 拉取制品

将如下内容粘贴至 .cnb.yml
::: tabs

@tab Maven

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: maven:3.8.5-openjdk-17
      stages:
        - name: mvn package
          script:
            mvn clean install -s ./settings.xml
```

@tab Gradle

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: gradle:7.6.6-jdk17
      stages:
        - name: gradle build and run
          script:
            - ./gradlew build --refresh-dependencies
```

:::

### 推送制品

将如下内容粘贴至 .cnb.yml

::: tabs
@tab Maven

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: maven:3.8.5-openjdk-17
      stages:
        - name: mvn package
          script:
            mvn clean deploy -s ./settings.xml
```

@tab Gradle

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: gradle:7.6.6-jdk17
      stages:
        - name: gradle publish
          script:
            - ./gradlew publish
```

:::

## 云原生开发

### 配置凭证

与 [云原生构建 配置凭证](./maven.md#配置凭证-1) 相同

### 配置开发镜像

根据不同客户端选择您的开发镜像
::: tabs
@tab Maven

```yaml title=".cnb.yml"
$:
  vscode:
    - docker:
        image: maven:3.8.5-openjdk-17
```

@tab Gradle

```yaml title=".cnb.yml"
$:
  vscode:
    - docker:
        image: gradle:7.6.6-jdk17
```

:::

### 拉取制品

与 [本地开发 拉取制品](./maven.md#拉取制品) 相同

### 推送制品

与 [本地开发 推送制品](./maven.md#推送制品) 相同

## 示例

### Gradle本地推送apk包

1. 配置 android-application 插件, 配置文件在 gradle/libs.versions.toml

```toml
[versions]
agp = "8.11.1"
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
```

2. 在 build.gradle 或者 build.gradle.kts 中配置maven推送插件, apk打包插件

::: tabs
@tab Gradle kotlin

```kotlin
// build.gradle.kts
plugins {
    id("com.android.application") // apk打包插件
    id("maven-publish") 
}
```

@tab Gradle groovy

```groovy
// build.gradle
plugins {
    id 'com.android.application'  // apk打包插件
    id 'maven-publish'
}
```

:::

3. 在 build.gradle 或者 build.gradle.kts 中配置构建任务和推送地址

::: tabs
@tab Gradle kotlin

```kotlin
// build.gradle.kts
afterEvaluate {
    publishing {
        publications {
            create<MavenPublication>("releaseApk") {
                groupId = "cnb"
                artifactId = "artifact"
                version = "1.0.0"

                // 如果需要发布签名应用则为 outputs/apk/release/${project.name}-release.apk
                val apkFile = layout.buildDirectory.file(
                    "outputs/apk/release/${project.name}-release-unsigned.apk"
                ).get().asFile

                artifact(apkFile) {
                    builtBy(tasks.named("assembleRelease"))
                    classifier = "release"
                    extension = "apk"
                }
            }
        }
        repositories {
            maven {
                // 可在 gradle.properties 文件中声明 cnbArtifactsGradlePassword = 你在 cnb 的访问令牌
                // 或者 export CNB_TOKEN=${YOUR_TOKEN}
                val cnbArtifactsGradlePassword = System.getenv("CNB_TOKEN") ?: project.findProperty("cnbArtifactsGradlePassword")

                // 示例 
                // url = uri("https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/")
                url = uri("<REPO_URL>")
                credentials {
                    username = "cnb"
                    password = cnbArtifactsGradlePassword.toString()
                }
            }
        }
    }
}
```

@tab Gradle groovy

```groovy
// build.gradle
afterEvaluate {
    publishing {
        publications {
            releaseApk(MavenPublication) {
                // 配置成您需要的
                groupId = 'cnb'
                artifactId = "artifact"
                version = '1.0.0'

                // 如果需要发布签名应用则为 outputs/apk/release/${project.name}-release.apk
                def apkFile = layout.buildDirectory.file(
                    'outputs/apk/release/${project.name}-release-unsigned.apk'
                ).get().asFile

                artifact(apkFile) {
                    builtBy tasks.assembleRelease
                    classifier = 'release'
                    extension = 'apk'
                }
            }
        }
        repositories {
            maven {
                // 可在 gradle.properties 文件中声明 cnbArtifactsGradlePassword = 你在 cnb 的访问令牌
                // 或者 export CNB_TOKEN=${YOUR_TOKEN}
                def cnbArtifactsGradlePassword = System.getenv('CNB_TOKEN') ?: project.findProperty('cnbArtifactsGradlePassword')

                // 示例 
                // url = uri("https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/")
                url = '<REPO_URL>'
                credentials {
                    username = 'cnb'
                    password = cnbArtifactsGradlePassword.toString()
                }
            }
        }
    }
}
```

:::
4\. 执行如下命令

```bash
./gradlew publish
```

### Gradle本地推送aar包

1. 配置android-library插件, 配置文件在 gradle/libs.versions.toml

```toml
[versions]
agp = "8.11.1"
[plugins]
android-library = { id = "com.android.library", version.ref = "agp" }
```

2. 在 build.gradle 或者 build.gradle.kts 中配置aar打包插件和maven推送插件

::: tabs
@tab Gradle kotlin

```kotlin
// build.gradle.kts
plugins {
    id("com.android.library") // aar打包插件
    id("maven-publish") 
}
```

@tab Gradle groovy

```groovy
// build.gradle
plugins {
    id 'com.android.library'  // aar打包插件
    id 'maven-publish'
}
```

:::

3. 在 build.gradle 或者 build.gradle.kts 中配置构建任务和推送地址

::: tabs
@tab Gradle kotlin

```kotlin
// build.gradle.kts
afterEvaluate {
    publishing {
        publications {
            create<MavenPublication>("releaseAar") {
                // 配置成您需要的
                groupId = "cnb"
                artifactId = "artifact"
                version = "1.0.0"

                from(components["release"])
            }
        }
        repositories {
            maven {
                // 可在 gradle.properties 文件中声明 cnbArtifactsGradlePassword = 你在 cnb 的访问令牌
                // 或者 export CNB_TOKEN=${YOUR_TOKEN}
                val cnbArtifactsGradlePassword = System.getenv("CNB_TOKEN") ?: project.findProperty("cnbArtifactsGradlePassword")

                // 示例 
                // url = uri("https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/")
                url = uri("<REPO_URL>")
                credentials {
                    username = "cnb"
                    password = cnbArtifactsGradlePassword.toString()
                }
            }
        }
    }
}
```

@tab Gradle groovy

```groovy
// build.gradle
afterEvaluate {
    publishing {
        publications {
            releaseAar(MavenPublication) {
                // 配置成您需要的
                groupId = 'cnb'
                artifactId = "artifact"
                version = '1.0.0'

                from components.release
            }
        }
        repositories {
            maven {
                // 可在 gradle.properties 文件中声明 cnbArtifactsGradlePassword = 你在 cnb 的访问令牌
                // 或者 export CNB_TOKEN=${YOUR_TOKEN}
                def cnbArtifactsGradlePassword = System.getenv('CNB_TOKEN') ?: project.findProperty('cnbArtifactsGradlePassword')

                // 示例 
                // url = uri("https://maven.cnb.share.ralphlauren.cn/cnb/maven-repo/-/packages/")
                url = uri("<REPO_URL>")
                credentials {
                    username = 'cnb'
                    password = cnbArtifactsGradlePassword.toString()
                }
            }
        }
    }
}
```

:::

4. 执行如下命令

```bash
./gradlew publish
```

## FAQ

### 覆盖已有版本后，依赖构建仍使用覆盖前的版本？

Maven机制如此，本地缓存有，就不去远程仓库中拉取。有三种解决方案：

1. 使用--update-snapshots命令，该命令强制Maven检查远程仓库中快照依赖的更新，此策略仅对 SNAPSHOT 有效

```bash
mvn clean package -U
```

2. 移除缓存中的包，直接删除maven在本地的缓存

```bash
# macOS和Linux 默认位置为 ～/.m2
# Windows 默认位置为 C:\Users\{用户名}\.m2\repository
# 也可以直接通过如下命令查询
mvn help:evaluate -Dexpression=settings.localRepository
```

3. 将settings.xml 对应依赖仓库的 updatePolicy 调整为 true, 此策略仅对 SNAPSHOT 有效

```xml
<settings>
  <profiles>
    <profile>
      <id>cnb-maven-repo-profile</id>
      <repositories>
        <repository>
          <id>cnb-maven-repo</id>
          <url><REPO_URL></url>
          <!-- 这里配置snapshot版本的拉取策略 -->
          <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
          </snapshots>
        </repository>
      </repositories>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
    </profile>
  </profiles>
</settings>
```

### 遇到 409 Forbidden

您已经上传过此包且禁止覆盖，如需覆盖包，请进入对应制品仓库->制品库设置->策略管理

* 仅覆盖SNAPSHOT，请选择 `Maven Snapshot策略`
* 覆盖SNAPSHOT和RELEASE，请选择 `允许覆盖全部已有版本`

## 更多用法

更多 Maven 用法，请查阅 Maven 官方文档
