优雅实现Android Library发布到Maven私有库:动态切换+自动化配置
在Android模块化开发中,将通用Library发布到Maven私有库是提升团队协作效率的核心手段。本文将分享一套可复用、高灵活性的Maven发布方案,实现本地/远程依赖动态切换、SNAPSHOT/Release版本自动分发,并提供开箱即用的脚本和完整使用指南。我们这里使用的Sonatype Nexus
一、方案核心优势
- 开发调试高效:一键切换本地源码依赖/Maven远程依赖,无需手动修改依赖代码
- 版本管理规范:自动区分SNAPSHOT(开发版)/Release(正式版)仓库,符合Maven规范
- 配置复用性强:通用发布脚本抽离,所有Library一键复用,降低维护成本
- 产物完整:自动打包AAR、源码包、文档包,生成标准POM文件(包含依赖信息)
二、整体目录结构
- maven-publish.gradle # Maven 发布核心脚本
- gradle.properties # 全局配置(仓库地址、版本坐标、开关)
- settings.gradle # 仓库源配置 + 模块引入控制
三、核心配置实现
1. 全局配置(gradle.properties)
集中管理仓库地址、版本坐标、依赖切换开关,便于统一维护:
注意:这里定义的maven的groupId、artifactId、version命名的前缀必须与useLocalSource_的后缀相同,因为我们定义的方便切换的依赖方法getLibraryDependency是基于这种规则。
# ******************** Maven 仓库配置(发布/拉取) ********************
# 私服地址(Maven 仓库地址)
mavenRepoUrl = https://xxx.xxx.xxx/repository/maven-releases/
# 快照库地址(开发中版本用)
mavenSnapshotRepoUrl = https://xxx.xxx.xxx/repository/maven-snapshots/
# 仓库账号密码
mavenRepoUsername = xxx
mavenRepoPassword = xxx
# ******************** 各 Library 的 Maven 坐标 ********************
# baseLibrary 库
baselibrary_groupId = com.xxx.baselibrary
baselibrary_artifactId = baselibrary
baselibrary_version = 1.0.0
# 快照版示例:1.0.0-SNAPSHOT
# asrlibrary 库
asrlibrary_groupId = com.xxx.asrlibrary
asrlibrary_artifactId = asrlibrary
asrlibrary_version = 1.0.0
# ******************** POM 文件通用配置 ********************
proj_name = aie Library
proj_descriptionInfo = aie 系列基础库(数据/UI)
proj_url = https://github.com/your-name/milestone
proj_licenceName = The Apache Software License, Version 2.0
proj_licenceUrl = http://www.apache.org/licenses/LICENSE-2.0.txt
proj_developerId = aie
proj_developerName = aie Dev
proj_developerEmail = dev@aie.com
# ******************** 依赖切换开关(每个 library 独立控制) ********************
useLocalSource_baselibrary = false // true=源码依赖,false=Maven依赖
useLocalSource_asrlibrary = false // true=源码依赖,false=Maven依赖
2. 依赖动态切换脚本(lib_common.gradle)
封装通用方法,实现本地 / 远程依赖一键切换
/**
* 通用依赖切换方法
* @param libName Library 名称(对应 gradle.properties 中的开关前缀,如 baselibrary)
* @param modulePath 本地模块路径(如 :Libraries:BaseLibrary)
* @return 对应的依赖配置
*/
ext {
getLibraryDependency = { String libName, String modulePath ->
// 1. 读取开关变量(是否本地源码依赖)
def useLocal = project.hasProperty("useLocalSource_${libName}") && project.property("useLocalSource_${libName}").toBoolean()
if (useLocal) {
// 本地源码依赖
return project(modulePath)
} else {
// Maven 依赖:拼接坐标(groupId:artifactId:version)
def groupId = project.hasProperty("${libName}_groupId") ? project.property("${libName}_groupId") : ""
def artifactId = project.hasProperty("${libName}_artifactId") ? project.property("${libName}_artifactId") : ""
def version = project.hasProperty("${libName}_version") ? project.property("${libName}_version") : ""
// 校验坐标完整性,避免报错
if (groupId && artifactId && version) {
return "${groupId}:${artifactId}:${version}"
} else {
throw new GradleException("${libName} 的 Maven 坐标配置不完整!请检查 gradle.properties 中的 ${libName}_groupId/${libName}_artifactId/${libName}_version")
}
}
}
}
3. Maven 发布核心脚本(maven-publish.gradle)
实现 AAR 打包、源码 / 文档生成、仓库自动分发:
// 通用 Maven 发布配置,所有 library 复用
apply plugin: 'maven-publish'
// ******************** 生成源码包(必选) ********************
tasks.register('androidSourcesJar', Jar) {
// 源码包命名:artifactId-version-sources.jar
archiveClassifier.set('sources')
// 包含 Java/Kotlin 源码
from android.sourceSets.main.java.srcDirs
from android.sourceSets.main.kotlin.srcDirs // 若用 Kotlin 需加
}
// ******************** Maven 发布核心配置 ********************
publishing {
// 配置发布的仓库地址
repositories {
maven {
// 区分正式版/快照版仓库
url = uri(project.versionName.endsWith('SNAPSHOT') ?
rootProject.properties['mavenSnapshotRepoUrl'] :
rootProject.properties['mavenRepoUrl'])
// 仓库账号密码
credentials {
username = rootProject.properties['mavenRepoUsername']
password = rootProject.properties['mavenRepoPassword']
}
}
}
publications {
mavenAndroid(MavenPublication) {
// 从 library 模块读取专属坐标
groupId = project.groupId
artifactId = project.artifactId
version = project.versionName
// 确保 Android 任务初始化完成后再获取产物
afterEvaluate {
// 发布 Release 版 AAR(核心)
artifact(tasks.getByName("bundleReleaseAar"))
// 发布源码包(依赖方可看源码)
artifact(androidSourcesJar)
}
// 生成 POM 文件(包含依赖、开发者、许可证等)
pom {
name = rootProject.properties['proj_name']
description = rootProject.properties['proj_descriptionInfo']
url = rootProject.properties['proj_url']
// 许可证信息
licenses {
license {
name = rootProject.properties['proj_licenceName']
url = rootProject.properties['proj_licenceUrl']
}
}
// 开发者信息
developers {
developer {
id = rootProject.properties['proj_developerId']
name = rootProject.properties['proj_developerName']
email = rootProject.properties['proj_developerEmail']
}
}
// 自动收集依赖到 POM(避免依赖丢失)
withXml {
def dependenciesNode = asNode().appendNode('dependencies')
// 收集 implementation 依赖
project.configurations.implementation.allDependencies.each { dep ->
if (dep.group != null && dep.name != "unspecified") {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dep.group)
dependencyNode.appendNode('artifactId', dep.name)
dependencyNode.appendNode('version', dep.version)
// 可选:添加依赖范围(默认 compile)
// dependencyNode.appendNode('scope', 'implementation')
}
}
}
}
}
}
}
// 发布前先构建 Release 产物
tasks.named('publishMavenAndroidPublicationToMavenRepository') {
dependsOn(tasks.named('bundleReleaseAar'))
dependsOn(tasks.named('androidSourcesJar'))
}
4. Library 模块配置(build.gradle)
引入通用脚本,配置专属坐标,极简接入:
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
id 'kotlin-kapt'
id 'kotlin-parcelize'
}
apply from: "${rootDir}/scripts/lib_common.gradle"
android {
namespace 'com.aiedevice.baselib'
defaultConfig {
ndk {
// 设置支持的SO库架构
abiFilters 'armeabi-v7a'
}
}
}
// ******************** 配置 Maven 坐标(和 gradle.properties 对应) ********************
ext {
groupId = baselibrary_groupId
artifactId = baselibrary_artifactId
versionName = baselibrary_version
}
// 引入通用发布脚本
apply from: rootProject.file('scripts/maven-publish.gradle')
dependencies {
api libs.androidx.core.ktx
api libs.androidx.appcompat
api libs.androidx.constraintlayout
api libs.androidx.material
}
5. 项目设置(settings.gradle)
控制模块引入,配合依赖开关实现源码 / 远程依赖切换:
pluginManagement {
repositories {
// 镜像/自定义仓库
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
gradlePluginPortal()
google()
mavenCentral()
// 个人 Maven 仓库(拉取依赖用)
maven { url = mavenRepoUrl }
maven { url = mavenSnapshotRepoUrl }
...
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
// 标准仓库
// 镜像/自定义仓库
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
google()
mavenCentral()
// 个人 Maven 仓库(拉取依赖用)
maven {
url = mavenRepoUrl
credentials {
username = mavenRepoUsername
password = mavenRepoPassword
}
}
maven {
url = mavenSnapshotRepoUrl
credentials {
username = mavenRepoUsername
password = mavenRepoPassword
}
}
...
}
}
include ':Basic:AppUpgrade'
include ':Basic:DataCenter'
include ':Basic:Guide'
include ':Basic:Mqtt'
include ':Basic:OTA'
...
四、使用方式
1. 依赖切换(开发调试)
只需修改gradle.properties中的开关变量:
useLocalSource_baselibrary = true:使用本地源码依赖(调试 Library 源码)useLocalSource_baselibrary = false:使用 Maven 远程依赖(集成已发布版本)
修改后同步 Gradle 即可生效,无需改动业务代码。
2. SNAPSHOT/Release 版本切换
通过版本号后缀自动区分:
- 快照版:版本号以
-SNAPSHOT结尾(如1.0.0-SNAPSHOT),自动发布到mavenSnapshotRepoUrl - 正式版:版本号无后缀(如
1.0.0),自动发布到mavenRepoUrl
3. 发布到 Maven 私有库
方式 1:命令行执行(推荐)
# 发布指定模块(推荐,速度更快)
./gradlew :Libraries:BaseLibrary:publish
# 发布所有模块
./gradlew publish
# 仅构建不发布(验证打包是否正常)
./gradlew :Libraries:BaseLibrary:bundleReleaseAar
方式 2:Android Studio 图形化操作
-
打开右侧
Gradle面板 -
找到对应 Library 模块(如
BaseLibrary) -
展开
Run Configurations目录 -
双击执行
publishMavenAndroidPublicationToMavenRepository任务
五、注意事项
-
仓库权限:确保配置的账号密码有对应仓库的发布权限
-
版本号规范:
- Release 版本号:
主版本.次版本.修订号(如1.0.0) - SNAPSHOT 版本号:
主版本.次版本.修订号-SNAPSHOT(如1.0.0-SNAPSHOT)
- Release 版本号:
-
依赖收集:脚本自动收集
implementation依赖到 POM,若需收集其他类型(如api),需修改project.configurations.implementation为对应配置 -
中文注释:生成 Javadoc 时若有中文注释,需确保编码为 UTF-8,避免乱码
-
构建环境:建议使用 Gradle 7.0+、AGP 7.0+,避免插件兼容问题