Android构建流程与Hook点详解
Gradle构建生命周期
三大阶段
1. 初始化阶段(Initialization Phase)
执行内容:
- 解析
settings.gradle - 确定哪些项目参与构建
- 为每个项目创建
Project实例
Hook点:
// settings.gradle
gradle.settingsEvaluated { settings ->
println "Settings evaluated"
}
gradle.projectsLoaded { gradle ->
println "Projects loaded"
}
2. 配置阶段(Configuration Phase)
执行内容:
- 执行所有项目的
build.gradle脚本 - 构建任务依赖关系图(Task Graph)
- 评估所有项目配置
Hook点:
// build.gradle
// 1. beforeEvaluate - 项目配置评估之前
project.beforeEvaluate {
println "Before project evaluation"
}
// 2. afterEvaluate - 项目配置评估之后(最常用)
project.afterEvaluate {
println "After project evaluation"
// 此时所有配置已完成,可以安全访问所有属性和任务
}
// 3. gradle.projectsEvaluated - 所有项目评估完成
gradle.projectsEvaluated {
println "All projects evaluated"
}
// 4. gradle.taskGraph.whenReady - 任务图构建完成
gradle.taskGraph.whenReady { taskGraph ->
println "Task graph ready"
}
3. 执行阶段(Execution Phase)
执行内容:
- 按照任务依赖关系执行任务
- 执行任务的 action
Hook点:
// 任务执行前后
tasks.all { task ->
task.doFirst {
println "Before executing ${task.name}"
}
task.doLast {
println "After executing ${task.name}"
}
}
// 构建完成
gradle.buildFinished { result ->
println "Build finished: ${result.failure ? FAILED : SUCCESS }"
}
project.afterEvaluate 执行时机详解
执行时机
project.afterEvaluate 在 配置阶段 的以下时刻执行:
- 当前项目的
build.gradle脚本执行完毕后 - 所有插件的
apply方法执行完毕后 - 在任务执行图构建之前
时序图
初始化阶段
↓
settings.gradle 执行
↓
创建 Project 实例
↓
配置阶段开始
↓
project.beforeEvaluate { } ←- Hook点1
↓
build.gradle 脚本执行
↓
插件 apply 方法执行
↓
project.afterEvaluate { } ←- Hook点2(重大!)
↓
gradle.projectsEvaluated { } ←- Hook点3
↓
gradle.taskGraph.whenReady { } ←- Hook点4
↓
执行阶段开始
↓
执行任务
↓
gradle.buildFinished { } ←- Hook点5
为什么常用 afterEvaluate?
// ❌ 错误示例:直接访问可能为空
android.applicationVariants.all { variant ->
// 此时 android 插件可能还未完全配置
}
// ✅ 正确示例:使用 afterEvaluate
project.afterEvaluate {
android.applicationVariants.all { variant ->
// 此时 android 插件已完全配置,可以安全访问
println "Variant: ${variant.name}"
}
}
Android构建大阶段
1. 准备阶段(Preparation)
- 初始化构建环境
- 解析依赖
- 合并资源
2. 编译阶段(Compilation)
- 编译 Java/Kotlin 代码
- 处理 AIDL
- 处理 RenderScript
- 处理 NDK
3. 打包阶段(Packaging)
- 打包资源
- 打包 DEX
- 生成 APK/AAB
4. 签名阶段(Signing)
- APK 对齐
- APK 签名
Android构建小阶段详解
完整构建流程(以 assembleDebug 为例)
阶段1:资源处理(Resource Processing)
1.1 生成 BuildConfig
Task: generateDebugBuildConfig
Hook: variant.outputs.all { output ->
output.processResources.doFirst { }
}
1.2 生成 ResValues
Task: generateDebugResValues
作用: 生成 resValue 配置的资源
1.3 合并资源(Merge Resources)
Task: mergeDebugResources
作用: 合并所有模块和依赖的资源文件
Hook: android.applicationVariants.all { variant ->
variant.mergeResourcesProvider.configure {
doFirst { println "Merging resources" }
}
}
1.4 编译资源(Process Resources)
Task: processDebugResources
作用: 使用 AAPT2 编译资源,生成 R.java 和编译后的资源
Hook: variant.outputs.all { output ->
output.processResourcesProvider.configure {
doFirst { println "Processing resources" }
}
}
阶段2:AIDL处理
Task: compileDebugAidl
作用: 编译 AIDL 文件生成 Java 接口
Hook: android.applicationVariants.all { variant ->
variant.aidlCompileProvider.configure {
doFirst { println "Compiling AIDL" }
}
}
阶段3:Java/Kotlin编译
3.1 合并 Java 资源
Task: mergeDebugJavaResource
作用: 合并所有 Java 资源文件
3.2 编译 Java 代码
Task: compileDebugJavaWithJavac
作用: 编译 Java 源代码
Hook: android.applicationVariants.all { variant ->
variant.javaCompileProvider.configure {
doFirst { println "Compiling Java" }
doLast { println "Java compilation finished" }
}
}
3.3 编译 Kotlin 代码
Task: compileDebugKotlin
作用: 编译 Kotlin 源代码
阶段4:字节码转换
4.1 Transform 阶段
作用: 字节码插桩、混淆等
Hook: android.registerTransform(new CustomTransform())
4.2 生成 DEX
Task: dexBuilderDebug
作用: 将 .class 文件转换为 .dex 文件
Hook: android.applicationVariants.all { variant ->
variant.packageApplicationProvider.configure {
doFirst { println "Dexing" }
}
}
4.3 合并 DEX
Task: mergeDebugDex
作用: 合并多个 DEX 文件(MultiDex)
阶段5:Native库处理
Task: mergeDebugNativeLibs
作用: 合并所有 .so 文件
Hook: android.applicationVariants.all { variant ->
variant.mergeNativeLibsProvider.configure {
doFirst { println "Merging native libs" }
}
}
阶段6:打包
6.1 打包资源
Task: packageDebugResources
作用: 打包资源到 APK
6.2 合并清单文件
Task: processDebugManifest
作用: 合并所有 AndroidManifest.xml
Hook: android.applicationVariants.all { variant ->
variant.outputs.all { output ->
output.processManifestProvider.configure {
doFirst { println "Processing manifest" }
}
}
}
6.3 打包 APK
Task: packageDebug
作用: 将所有资源、DEX、Native库打包成 APK
Hook: android.applicationVariants.all { variant ->
variant.packageApplicationProvider.configure {
doFirst { println "Packaging APK" }
}
}
阶段7:签名和对齐
7.1 签名
Task: signDebugBundle / signReleaseApk
作用: 使用密钥对 APK 签名
7.2 对齐
Task: zipalignDebug
作用: 优化 APK 文件结构
所有可Hook的方法
1. Gradle生命周期Hook
// ==================== settings.gradle ====================
gradle.settingsEvaluated { settings ->
// Settings 评估完成
}
gradle.projectsLoaded { gradle ->
// 所有项目加载完成
}
// ==================== build.gradle ====================
// 1. 项目评估前
project.beforeEvaluate {
println "Before project ${project.name} evaluation"
}
// 2. 项目评估后(最常用)
project.afterEvaluate {
println "After project ${project.name} evaluation"
}
// 3. 所有项目评估完成
gradle.projectsEvaluated {
println "All projects evaluated"
}
// 4. 任务图准备完成
gradle.taskGraph.whenReady { graph ->
println "Task graph ready with ${graph.allTasks.size()} tasks"
}
// 5. 任务执行前后
gradle.taskGraph.beforeTask { task ->
println "Before task ${task.name}"
}
gradle.taskGraph.afterTask { task, state ->
println "After task ${task.name}, success: ${!state.failure}"
}
// 6. 构建完成
gradle.buildFinished { result ->
if (result.failure) {
println "Build failed: ${result.failure.message}"
} else {
println "Build succeeded"
}
}
// 7. 任务添加监听
tasks.whenTaskAdded { task ->
println "Task added: ${task.name}"
}
// 8. 所有任务配置
tasks.all { task ->
task.doFirst {
println "Executing ${task.name}"
}
task.doLast {
println "Finished ${task.name}"
}
}
2. Android插件Hook点
android {
// ==================== Variant Hook ====================
applicationVariants.all { variant ->
// Variant 创建时
println "Variant: ${variant.name}"
// 访问输出
variant.outputs.all { output ->
// 修改输出文件名
outputFileName = "app-${variant.name}-${variant.versionName}.apk"
}
}
// ==================== Product Flavor Hook ====================
productFlavors.all { flavor ->
println "Flavor: ${flavor.name}"
}
// ==================== Build Type Hook ====================
buildTypes.all { buildType ->
println "Build type: ${buildType.name}"
}
}
// ==================== 在 afterEvaluate 中使用 ====================
project.afterEvaluate {
android.applicationVariants.all { variant ->
// 1. Manifest 处理
variant.outputs.all { output ->
output.processManifestProvider.configure {
doFirst {
println "Processing manifest for ${variant.name}"
}
}
}
// 2. 资源合并
variant.mergeResourcesProvider.configure {
doFirst {
println "Merging resources for ${variant.name}"
}
}
// 3. 资源处理
variant.outputs.all { output ->
output.processResourcesProvider.configure {
doFirst {
println "Processing resources for ${variant.name}"
}
}
}
// 4. Java 编译
variant.javaCompileProvider.configure {
doFirst {
println "Compiling Java for ${variant.name}"
}
}
// 5. AIDL 编译
variant.aidlCompileProvider.configure {
doFirst {
println "Compiling AIDL for ${variant.name}"
}
}
// 6. Native 库合并
variant.mergeNativeLibsProvider.configure {
doFirst {
println "Merging native libs for ${variant.name}"
}
}
// 7. 打包
variant.packageApplicationProvider.configure {
doFirst {
println "Packaging APK for ${variant.name}"
}
}
// 8. 组装任务
variant.assembleProvider.configure {
doFirst {
println "Assembling ${variant.name}"
}
doLast {
println "Assembly complete for ${variant.name}"
}
}
}
}
3. Transform API Hook
// 自定义 Transform(用于字节码插桩)
import com.android.build.api.transform.*
class CustomTransform extends Transform {
@Override
String getName() {
return "CustomTransform"
}
@Override
Set<QualifiedContent.ContentType> getInputTypes() {
return TransformManager.CONTENT_CLASS
}
@Override
Set<? super QualifiedContent.Scope> getScopes() {
return TransformManager.SCOPE_FULL_PROJECT
}
@Override
boolean isIncremental() {
return true
}
@Override
void transform(TransformInvocation transformInvocation) {
println "Custom Transform executing"
// 字节码处理逻辑
}
}
// 注册 Transform
android.registerTransform(new CustomTransform())
4. AGP 7.0+ 新版 Variant API
// build.gradle (AGP 7.0+)
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
androidComponents {
// 在 Variant 创建前
beforeVariants { variantBuilder ->
println "Before variant ${variantBuilder.name}"
// 可以禁用某些 variant
if (variantBuilder.name == "debug") {
variantBuilder.enable = false
}
}
// 在 Variant 创建后
onVariants { variant ->
println "Variant ${variant.name}"
// Artifact API
variant.artifacts.use(taskProvider)
.wiredWith { it.inputFile }
.toTransform(SingleArtifact.MERGED_MANIFEST)
}
// 在所有 Variant 创建后
finalizeDsl { extension ->
println "DSL finalized"
}
}
5. Task依赖Hook
project.afterEvaluate {
// 获取特定任务
def assembleTask = tasks.findByName("assembleDebug")
// 在任务之前执行
assembleTask?.doFirst {
println "About to assemble debug"
}
// 在任务之后执行
assembleTask?.doLast {
println "Debug assembly completed"
}
// 添加任务依赖
assembleTask?.dependsOn("customTask")
// 任务必须在某任务之后
assembleTask?.mustRunAfter("preBuild")
// 任务应该在某任务之后
assembleTask?.shouldRunAfter("clean")
}
6. 依赖解析Hook
configurations.all { configuration ->
// 依赖解析前
configuration.incoming.beforeResolve {
println "Before resolving ${configuration.name}"
}
// 依赖解析后
configuration.incoming.afterResolve {
println "After resolving ${configuration.name}"
}
}
// 强制依赖版本
configurations.all {
resolutionStrategy {
force com.google.code.gson:gson:2.8.9
}
}
构建流程图
完整构建流程图(含Hook点)
┌─────────────────────────────────────────────────────────────────┐
│ 初始化阶段 (Initialization) │
└─────────────────────────────────────────────────────────────────┘
↓
settings.gradle 执行
↓
🎯 Hook: gradle.settingsEvaluated { }
↓
🎯 Hook: gradle.projectsLoaded { }
↓
创建 Project 实例
↓
┌─────────────────────────────────────────────────────────────────┐
│ 配置阶段 (Configuration) │
└─────────────────────────────────────────────────────────────────┘
↓
🎯 Hook: project.beforeEvaluate { }
↓
build.gradle 脚本执行
↓
插件 apply 执行
↓
🎯 Hook: project.afterEvaluate { } ⭐ 最常用
↓
🎯 Hook: gradle.projectsEvaluated { }
↓
构建 Task Graph
↓
🎯 Hook: gradle.taskGraph.whenReady { }
↓
┌─────────────────────────────────────────────────────────────────┐
│ 执行阶段 (Execution) │
└─────────────────────────────────────────────────────────────────┘
↓
┌────────────────────── 1. 准备阶段 ──────────────────────┐
│ │
│ preBuild │
│ ↓ │
│ 🎯 Hook: beforeTask/afterTask │
│ ↓ │
│ preDebugBuild │
│ │
└─────────────────────────────────────────────────────────┘
↓
┌────────────────────── 2. 资源处理阶段 ──────────────────┐
│ │
│ generateDebugBuildConfig │
│ ↓ │
│ generateDebugResValues │
│ ↓ │
│ mergeDebugResources │
│ 🎯 Hook: variant.mergeResourcesProvider.configure { } │
│ ↓ │
│ processDebugResources (AAPT2) │
│ 🎯 Hook: output.processResourcesProvider.configure { } │
│ ↓ │
│ 生成 R.java │
│ │
└─────────────────────────────────────────────────────────┘
↓
┌────────────────────── 3. 代码处理阶段 ──────────────────┐
│ │
│ compileDebugAidl │
│ 🎯 Hook: variant.aidlCompileProvider.configure { } │
│ ↓ │
│ compileDebugRenderscript │
│ ↓ │
│ mergeDebugJavaResource │
│ ↓ │
│ compileDebugJavaWithJavac │
│ 🎯 Hook: variant.javaCompileProvider.configure { } │
│ ↓ │
│ compileDebugKotlin (如果有 Kotlin) │
│ │
└─────────────────────────────────────────────────────────┘
↓
┌────────────────────── 4. 字节码转换阶段 ────────────────┐
│ │
│ transformClassesWithDexBuilderForDebug │
│ 🎯 Hook: registerTransform(new CustomTransform()) │
│ ↓ │
│ 字节码插桩 (Transform API) │
│ ↓ │
│ dexBuilderDebug (.class → .dex) │
│ ↓ │
│ mergeDebugDex (合并 DEX) │
│ │
└─────────────────────────────────────────────────────────┘
↓
┌────────────────────── 5. Native库处理 ──────────────────┐
│ │
│ mergeDebugNativeLibs │
│ 🎯 Hook: variant.mergeNativeLibsProvider.configure { } │
│ ↓ │
│ stripDebugDebugSymbols (可选) │
│ │
└─────────────────────────────────────────────────────────┘
↓
┌────────────────────── 6. 清单处理阶段 ──────────────────┐
│ │
│ processDebugManifest │
│ 🎯 Hook: output.processManifestProvider.configure { } │
│ ↓ │
│ 合并所有 AndroidManifest.xml │
│ │
└─────────────────────────────────────────────────────────┘
↓
┌────────────────────── 7. 打包阶段 ──────────────────────┐
│ │
│ packageDebug │
│ 🎯 Hook: variant.packageApplicationProvider.configure │
│ ↓ │
│ 合并资源、DEX、Native库、资源等 │
│ ↓ │
│ 生成未签名的 APK │
│ │
└─────────────────────────────────────────────────────────┘
↓
┌────────────────────── 8. 签名和对齐 ────────────────────┐
│ │
│ signDebugApk (Debug签名) │
│ ↓ │
│ zipalignDebug (对齐优化) │
│ ↓ │
│ assembleDebug │
│ 🎯 Hook: variant.assembleProvider.configure { } │
│ │
└─────────────────────────────────────────────────────────┘
↓
🎯 Hook: gradle.buildFinished { }
↓
构建完成 ✅
Variant处理流程图
┌──────────────────────────────────────────────────────┐
│ Android Plugin Apply │
└──────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────┐
│ 读取 android { } DSL 配置 │
│ - buildTypes (debug, release, ...) │
│ - productFlavors (free, paid, ...) │
│ - defaultConfig │
└──────────────────────────────────────────────────────┘
↓
🎯 Hook: androidComponents.beforeVariants { }
↓
┌──────────────────────────────────────────────────────┐
│ 生成 Variant 组合 │
│ │
│ 例如: │
│ - freeDebug = free + debug │
│ - freeRelease = free + release │
│ - paidDebug = paid + debug │
│ - paidRelease = paid + release │
└──────────────────────────────────────────────────────┘
↓
🎯 Hook: android.applicationVariants.all { }
↓
┌──────────────────────────────────────────────────────┐
│ 为每个 Variant 创建 Task │
│ │
│ 例如 freeDebug: │
│ - mergeFreeDebugResources │
│ - processFreeDebugResources │
│ - compileFreeDebugJavaWithJavac │
│ - packageFreeDebug │
│ - assembleFreeDebug │
└──────────────────────────────────────────────────────┘
↓
🎯 Hook: androidComponents.onVariants { }
↓
🎯 Hook: project.afterEvaluate { }
↓
执行构建任务
实践示例
示例1:修改APK输出文件名
android {
applicationVariants.all { variant ->
variant.outputs.all { output ->
def buildType = variant.buildType.name
def versionName = variant.versionName
def versionCode = variant.versionCode
def date = new Date().format( yyyyMMdd )
outputFileName = "MyApp-${buildType}-v${versionName}-${versionCode}-${date}.apk"
}
}
}
示例2:在编译前检查代码规范
project.afterEvaluate {
android.applicationVariants.all { variant ->
variant.javaCompileProvider.configure {
doFirst {
// 执行代码检查
println "Running code quality checks..."
exec {
commandLine checkstyle , src/main/java
}
}
}
}
}
示例3:自动生成版本信息文件
project.afterEvaluate {
android.applicationVariants.all { variant ->
def generateVersionTask = task("generate${variant.name.capitalize()}VersionFile") {
doLast {
def versionFile = new File(buildDir, "generated/version.txt")
versionFile.parentFile.mkdirs()
versionFile.text = """
Version: ${variant.versionName}
Build: ${variant.versionCode}
Variant: ${variant.name}
Date: ${new Date()}
""".trim()
}
}
variant.assembleProvider.configure {
dependsOn(generateVersionTask)
}
}
}
示例4:统计构建时间
class BuildTimeListener implements TaskExecutionListener, BuildListener {
private Clock clock
private times = []
@Override
void beforeExecute(Task task) {
clock = new Clock()
}
@Override
void afterExecute(Task task, TaskState taskState) {
def ms = clock.timeInMs
times.add([ms, task.path])
task.project.logger.warn "${task.path} took ${ms}ms"
}
@Override
void buildFinished(BuildResult result) {
println "Task timings:"
times.sort { it[0] }.reverse().each {
printf "%7sms %s
", it
}
}
@Override
void buildStarted(Gradle gradle) {}
@Override
void projectsEvaluated(Gradle gradle) {}
@Override
void projectsLoaded(Gradle gradle) {}
@Override
void settingsEvaluated(Settings settings) {}
}
class Clock {
long start
Clock() {
start = System.currentTimeMillis()
}
long getTimeInMs() {
System.currentTimeMillis() - start
}
}
gradle.addListener new BuildTimeListener()
示例5:Resource Shrinking Hook
project.afterEvaluate {
android.applicationVariants.all { variant ->
if (variant.buildType.shrinkResources) {
def shrinkTask = tasks.findByName("shrink${variant.name.capitalize()}Resources")
shrinkTask?.doLast {
println "Resources shrunk for ${variant.name}"
// 分析删除的资源
}
}
}
}
示例6:自动上传APK到服务器
project.afterEvaluate {
android.applicationVariants.all { variant ->
if (variant.buildType.name == "release") {
variant.assembleProvider.configure {
doLast {
variant.outputs.all { output ->
def apkFile = output.outputFile
println "Uploading ${apkFile.name} to server..."
// 上传逻辑
exec {
commandLine curl , -F , "file=@${apkFile}",
https://your-server.com/upload
}
}
}
}
}
}
}
示例7:AGP 7.0+ Artifacts API
import com.android.build.api.artifact.SingleArtifact
import com.android.build.api.variant.BuiltArtifactsLoader
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.TaskAction
abstract class DisplayApksTask extends DefaultTask {
@InputFiles
abstract DirectoryProperty getApkFolder()
@TaskAction
void taskAction() {
def loader = project.objects.newInstance(BuiltArtifactsLoader)
def artifacts = loader.load(apkFolder.get())
artifacts?.elements?.each { artifact ->
println "APK: ${artifact.outputFile}"
println "Variant: ${artifact.variantName}"
}
}
}
androidComponents {
onVariants { variant ->
def displayTask = project.tasks.register(
"display${variant.name.capitalize()}Apks",
DisplayApksTask
)
variant.artifacts
.use(displayTask)
.wiredWith { it.apkFolder }
.toGet(SingleArtifact.APK)
}
}
常见问题和最佳实践
1. afterEvaluate vs onVariants
afterEvaluate(传统方式):
// 适用于 AGP < 7.0
project.afterEvaluate {
android.applicationVariants.all { variant ->
// 配置 variant
}
}
onVariants(新方式):
// 适用于 AGP >= 7.0
androidComponents {
onVariants { variant ->
// 配置 variant
}
}
2. Hook时机选择
| Hook点 | 时机 | 适用场景 |
|---|---|---|
| beforeEvaluate | 项目配置前 | 修改配置、添加插件 |
| afterEvaluate | 项目配置后 | 访问任务、修改variant |
| taskGraph.whenReady | 任务图准备完成 | 分析任务依赖 |
| doFirst | 任务执行前 | 准备环境、检查条件 |
| doLast | 任务执行后 | 清理、上传产物 |
3. 性能优化提议
- 避免在配置阶段执行耗时操作
- 使用增量编译和缓存
- 合理使用 Task 依赖而非 doFirst/doLast
- 使用 Provider API 延迟配置
4. 调试技巧
// 打印所有任务
gradle.taskGraph.whenReady { graph ->
graph.allTasks.each { task ->
println "Task: ${task.path}"
}
}
// 打印任务依赖
tasks.all { task ->
task.doFirst {
println "${task.name} depends on: ${task.taskDependencies.getDependencies(task)*.name}"
}
}
// 启用详细日志
gradle.startParameter.logLevel = LogLevel.INFO
总结
本文档详细介绍了:
- ✅ Gradle三大构建阶段:初始化、配置、执行
- ✅ project.afterEvaluate执行时机:配置阶段结束时
- ✅ Android构建流程:从资源处理到APK签名的完整流程
- ✅ 所有Hook点:生命周期、Variant、Task、Transform等
- ✅ 可视化流程图:清晰展示构建流程和Hook时机
- ✅ 实践示例:7个真实场景的Hook应用
关键要点:
-
afterEvaluate是最常用的Hook点,在配置阶段结束时执行 - AGP 7.0+ 推荐使用
androidComponentsAPI - 合理选择Hook时机可以提高构建效率
- Transform API 适合字节码插桩场景
参考资料:
- Gradle Build Lifecycle
- Android Gradle Plugin API
- Variant API Guide
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...
