总览
本文围绕 “**配置 → 任务 → 动态化 → 依赖 → 本地库 → 资源 → 自动化**” 七大主题,把日常高频痛点一次讲透。
阅读方式:
先通读“思路”了解为什么;
再抄“最小可运行示例”快速验证;
最后看“延伸”拓展到多项目/组件化。
1 全局配置(Root Project)
目标:一次声明、所有子模块(application / library / test
)全部生效,避免每个 build.gradle
反复复制。
1.1 统一 UTF-8(编译期 + 控制台)
// root/gradle.properties
file.encoding=UTF-8
org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8
org.gradle.console=rich // 彩色输出
// root/build.gradle.kts
allprojects {
tasks.withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "17"
// 统一 Kotlin 编码
freeCompilerArgs += listOf("-Xjsr305=strict", "-Xemit-jvm-type-annotations")
}
}
}
1.2 依赖 Google/MavenCentral 仓库(一次声明)
// root/settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) // 强制收敛
repositories {
google()
mavenCentral()
// 公司私有仓库
maven("https://nexus.xxx.com/repository/android-public/")
}
}
1.3 支持 Groovy(混合遗留脚本)
// root/buildSrc/build.gradle.kts
plugins {
`groovy-gradle-plugin` // 预编译 Groovy 脚本插件
}
把旧 Groovy 脚本放到 root/buildSrc/src/main/groovy
即可被 Kotlin 引用。
1.4 定义全局变量(版本号、SDK、编译参数)
推荐 **Version Catalogs**(Gradle 7.0+ 官方方案):
# root/gradle/libs.versions.toml
[versions]
compileSdk = "34"
minSdk = "24"
targetSdk = "34"
agp = "8.3.0"
kotlin = "1.9.20"
retrofit = "2.9.0"
[libraries]
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
[bundles]
network = ["retrofit"]
任何模块:
android {
compileSdk = libs.versions.compileSdk.get().toInt()
}
dependencies {
implementation(libs.bundles.network)
}
旧项目可用
buildSrc/src/main/kotlin/Config.kt
单文件枚举,但维护成本高,不推荐。
1.5 配置 Lint(全局选项 + 自定义规则)
// root/build.gradle.kts
subprojects {
afterEvaluate {
extensions.findByType<com.android.build.api.dsl.CommonExtension<*, *, *, *, *>>()?.apply {
lint {
abortOnError = false //有lint错误也不停止构建
checkReleaseBuilds = false //禁用在发布构建时进行lint检查
disable += "InvalidPackage" // 忽略跨平台 RN 警告
baseline = file("lint-baseline.xml") //lint检查的基准文件
}
}
}
}
2 操控 Task(AGP 生成的标准任务)
所有 Android 任务继承自
Task
,名字/类型/顺序均可改。
2.1 更改输出 APK 名字(含版本、渠道、时间)
android.applicationVariants.all {
val variant = this
variant.outputs.all {
val apkName = "App-${variant.flavorName}-${variant.buildType.name}-${variant.versionName}-${gitCommitShort()}.apk"
(this as com.android.build.gradle.internal.api.BaseVariantOutputImpl).outputFileName = apkName
}
}
gitCommitShort()
为自定义函数,返回当前 commit 前 7 位。
2.2 更改 AAR 输出目录(方便 CI 收集)
android.libraryVariants.all {
val variant = this
variant.packageLibraryProvider.configure {
val dest = rootProject.layout.buildDirectory.dir("outputs/aar/${variant.name}")
destinationDirectory.set(dest)
}
}
2.3 跳过 AndroidTest(CI 加速)
android.libraryVariants.all {
val variant = this
variant.packageLibraryProvider.configure {
val dest = rootProject.layout.buildDirectory.dir("outputs/aar/${variant.name}")
destinationDirectory.set(dest)
}
}
或在命令行:
./gradlew assembleDebug -x testDebugUnitTest -x connectedDebugAndroidTest
2.4 找出耗时的 Task(构建速度分析)
./gradlew assembleDebug --profile --scan
Gradle 会生成 build/reports/profile/...
火焰图;
或配置 buildSrc
插件:
gradle.taskGraph.afterTask {
if (this is TaskExecutionListener) {
val cost = endTime - startTime
if (cost > 1000) println("Slow task: $path took ${cost}ms")
}
}
2.5 抽离 Task 脚本(可复用)
在
buildSrc/src/main/kotlin
建ApkRenamePlugin.kt
继承
Plugin<Project>
,内部注册 task;任何模块
plugins { id("apk-rename") }
即可。
3 动态化(Build-Time 黑科技)
3.1 动态设置 BuildConfig
android.defaultConfig {
buildConfigField("String", "API_URL", "\"${findProperty("API_URL") ?: "https://api.example.com"}\"")
buildConfigField("long", "BUILD_TIMESTAMP", "${System.currentTimeMillis()}L")
}
通过
gradle.properties
或 CI 环境变量注入,无需改代码。
3.2 填充 Manifest 占位符
android.defaultConfig {
manifestPlaceholders["UMENG_CHANNEL"] = "default"
}
productFlavors {
create("xiaomi") { manifestPlaceholders["UMENG_CHANNEL"] = "xiaomi" }
}
Manifest:
<meta-data android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL}" />
3.3 让 buildType 支持继承(减少重复)
android.buildTypes {
create("staging") {
initWith(getByName("debug"))
isDebuggable = false
applicationIdSuffix = ".stg"
}
}
3.4 让 Flavor 支持继承(使用 dimension
+ fallback
)
flavorDimensions += listOf("api")
productFlavors {
create("api19") { dimension = "api" }
create("api21") { dimension = "api" }
create("free") { dimension = "tier" }
create("paid") { dimension = "tier" }
}
android.variantFilter {
if (flavors.any { it.name == "api19" } && flavors.any { it.name == "paid" }) {
ignore = true // 屏蔽 api19+paid 组合
}
}
3.5 内测版本用特定 Icon
sourceSets {
getByName("debug") {
res.srcDirs("src/debug/res")
}
}
src/debug/res/mipmap-xxxhdpi/ic_launcher.png
放内测图标即可。
3.6 不同渠道不同包名
productFlavors {
create("huawei") { applicationId = "com.xxx.huawei" }
create("xiaomi") { applicationId = "com.xxx.xiaomi" }
}
3.7 自动填充版本信息(语义化 + 自增)
// buildSrc/src/main/kotlin/Versioning.kt
object Versioning {
val major = 3
val minor = 2
val patch = gitCommitCount() // git rev-list --count HEAD
val versionName = "$major.$minor.$patch"
val versionCode = major * 10000 + minor * 100 + patch
}
android.defaultConfig {
versionCode = Versioning.versionCode
versionName = Versioning.versionName
}
4 远程依赖(Maven)
4.1 配置私有 Maven
repositories {
maven {
url = uri("https://nexus.xxx.com/repository/maven-releases/")
credentials {
username = findProperty("NEXUS_USER") as String? ?: System.getenv("NEXUS_USER")
password = findProperty("NEXUS_PASS") as String? ?: System.getenv("NEXUS_PASS")
}
}
}
4.2 依赖相关 API 速查
配置名 |
含义 |
implementation |
编译 & 运行期都参与打包,但不传递 |
api |
编译 & 运行期都参与,且传递 |
compileOnly |
仅编译,不打包(如 Provided) |
runtimeOnly |
仅运行期 |
testImplementation |
单测 |
androidTestImplementation |
插桩测 |
4.3 组合依赖(Bundles)
见 1.4 Version Catalogs 的 bundles.network
。
4.4 依赖传递 & 禁用
implementation(libs.okhttp) {
isTransitive = false // 关闭传递
}
4.5 动态版本号(慎用)
implementation("com.facebook.soloader:soLoader:0.10.+")
每次构建都可能变,CI 必须
--refresh-dependencies
才能复现,建议锁住版本。
4.6 强制版本号(统一 BOM)
// 先导入 BOM
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.12.0"))
// 再写依赖,无需版本
implementation("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:logging-interceptor")
4.7 exclude 关键字(解决冲突)
implementation(libs.facebook.react) {
exclude(group = "com.android.support", module = "support-annotations")
}
4.8 依赖管理(锁版本)
./gradlew dependencies --write-locks // 生成 gradle.lockfile
CI 开启:
// root/gradle.properties
dependency.verification=strict
5 本地依赖(非 Maven 网络)
5.1 引用 AAR(单文件)
把 xxx.aar
放到 libs/
目录:
dependencies {
implementation(files("libs/xxx.aar"))
}
多 AAR 循环:
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar"))))
5.2 依赖 Module / Jar
implementation(project(":base-lib"))
implementation(files("libs/legacy.jar"))
5.3 自建本地 Maven 仓库(发布到目录)
// library/build.gradle.kts
plugins {
`maven-publish`
}
publishing {
repositories {
maven {
url = uri("${rootProject.projectDir}/repo")
}
}
publications {
create<MavenPublication>("release") {
from(components["release"])
groupId = "com.xxx"
artifactId = "base-lib"
version = "1.0.0"
}
}
}
其他工程:
repositories {
maven(uri("${rootProject.projectDir}/repo"))
}
implementation("com.xxx:base-lib:1.0.0")
5.4 本地依赖 React Native(源码集成)
// settings.gradle.kts
include(":react-native")
project(":react-native").projectDir = file("../node_modules/react-native/android")
dependencies {
implementation(project(":react-native"))
}
5.5 重新打包第三方 Jar(改名 / 移类 / shade)
// buildSrc 插件,使用 Shadow 插件
plugins {
id("com.github.johnrengelman.shadow") version "8.1.1"
}
tasks.shadowJar {
archiveClassifier.set("")
relocate("com.google.gson", "com.xxx.shaded.gson")
}
6 资源管理(精简 / 白牌 / 多语言)
只打包指定语言:
android { resourceConfigurations += listOf("zh", "en") }
移除无用资源(与 ProGuard 联动):
buildTypes.getByName("release") { isShrinkResources = true isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") }
多 DPI 白牌:
productFlavors { create("lite") { ndk { abiFilters += listOf("armeabi-v7a") } } }
7 总结 & 常见问题速查
需求 |
一句话答案 |
自动 versionCode/versionName |
用 git commit count + 语义化脚本(见 3.7) |
强制统一某个库版本 |
用 BOM + |
管理签名 |
把 |
引入本地 Maven |
|
本地依赖写法 |
|
制作本地库 |
|
Exclude 冲突 |
|
两个库类冲突 |
① 用 |
8 附录:速查脚本(直接复制)
一键清理所有中间产物 + 重新生成:
./gradlew clean assembleDebug --refresh-dependencies --no-build-cache --no-configuration-cache
输出所有依赖到文件:
./gradlew :app:dependencies > deps.txt
查看构建扫描(需同意条款):
./gradlew assembleDebug --scan
至此,从“全局 UTF-8”到“动态版本号”到“本地 Maven”再到“依赖冲突”的完整链路全部覆盖。
把本文示例按需粘贴到你的项目,即可在 30 分钟内拥有“可维护、可追踪、可 CI”的 Gradle 工程骨架。祝编译极速、依赖清爽!
参考链接:
https://developer.android.com/build/gradle-build-overview?hl=zh-cn