使用 Gradle 插件发布 Android library 到 maven 远程仓库

sddtc 于 2021-02-22 发布

最近在项目里更新了 gradle 插件到 6.1.1 之后发现它支持使用 maven-publish 这个插件来打包发布并部署到 maven 的内部远程仓库去。简单记录下,希望能帮助到需要的人。

之前项目使用 mavenuploadArchives:

这种方式没什么问题,一直都可以运行的很好。 如果不是遇见了一些问题,在繁忙的日常你很难跑去更新工作得好好滴东西 😑
我们的 Android 项目是基于 KotlinKoin + apollo-androidMFE 架构。 项目使用的一些第三方依赖很新,他们更新版本的速度真的惊人 😳
直到有一天在我试图将 apollo-android2.3.1 升级到 2.4.2 时发现打包发布失败了。 堆栈错误信息:

> Task uploadArchives FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task 'uploadArchives'.
> Could not publish configuration 'archives'
   > Cannot publish artifact 'metadata.json' (/Users/xxx/app/build/generated/metadata/apollo/debugAndroidTest/service/metadata.json) as it does not exist.

* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task 'uploadArchives'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:205)
        at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:263)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:203)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:184)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:109)
        at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)
...

于是去查看了相关的 issues, 果然也有人遇见了同样的问题。
说到这个我真的忍不住吐槽最近更新了我的手机 Google Camera app,直接导致前置摄像头打不开害闪退 🙃, 去 Goggle Play 商店查看评论发现大家都遇到了同样的问题。。
也是万万妹想到大公司也会出现这么致命的问题 = =。。 因为这个 Crush 最近真的开机支付连脸部识别都失效,哎。如果不是真爱,谁会用 Android 机啊咳咳。
扯远了,回到正题来说,出现异常的原因是 apollo-android 试图在 这一行UnitTests/AndroidTests 添加 metadata.json。 但是很有可能项目的 UnitTests/AndroidTestsmetadata.json 是不会被生成的。因为通常这些目录不会有 graphql 相关的文件。

为了解决这个问题其实有两个方案:

然而回到一开始,他们更新版本的速度之快一方面修复了一些 bug, 修复了一些 issue, 更有可能修复一些安全隐患,所以升级是必要的。 更新了之后前置摄像头更新坏了也是有概率发生的
更新的脚本非常简单,因为 maven-publish 插件非常强大:

有几点需要注意:

接下来我们简单说下细节

2021-02-23-4YWFw1-BZNhGU

发布什么

Gradle 需要知道要我们在发布时需要哪些文件和信息。 通常是 artifactsmetadata 的集合, Gradle 将其定义为 publication

举例来说, 你打包发布到远端 maven 仓库的内容可以包括:

另外,Gradle 还会发布上述所有内容的校验和,并在配置时发布签名。从 Gradle 6.0 开始,多了 SHA256SHA512 的校验和文件。

代码示例:

...
task androidSourcesJar(type: Jar) {
    archiveClassifier.set('sources')
    from android.sourceSets.main.java.source
}

publishing {
        publications {
            release(MavenPublication) {
                from(components["release"])
                pom {
                    groupId = 'sddtc-company-v-'
                    version = '1.0.0'
                    artifactId = 'app-name'
                }
                artifact(androidSourcesJar)
            }
        }
...
}

发布到哪里

Gradle 需要知道在发布的存储库地址。 该存储库提供了各种组件。 Gradle 需要与远程仓库进行交互,因此我们必须提供存储库的类型及其位置。

代码示例:

repositories {
    maven {
        credentials {
            username getRepositoryUsername()
            password getRepositoryPassword()
        }
        url getRepositoryUrl()
        println("> Configure maven repo: ${url}")
    }
}

发行方式你会选择哪种

Gradle 会自动为发布和存储库的所有可能组合生成发布任务(除了贴心还能说啥),从而使我们可以将任何组件发布到任何存储库。
如果要发布到 maven 存储库,则 Task 的类型为 PublishToMavenRepository,而对于 Ivy 存储库,任务的类型为 PublishToIvyRepository

代码示例:

#!/bin/bash
set -xeuo pipefail

echo "+++ :buildkite: Publishing library to maven"
./gradlew clean publishReleasePublicationToMavenRepository