在 Android Gradle Plugin (AGP) 8.0+ 中,原有的 Transform API 被废弃,取而代之的是更现代的构建管道和组件 API。在开发 Android 插件时,特别是涉及字节码插桩(如 ASM 插码)时,我们常常需要处理 app 本身或第三方依赖(如 SDK)中的 class 文件。
本文对比 ArtifactTransform(也叫 TransformAction)与 variant.artifacts.use(...) 的使用场景和实现方式,避免常见误用和报错。
一、两种处理方式对比
| 功能 | 处理对象 | 推荐方式 |
|---|---|---|
| 处理 app 自身 class 文件(如插码) | 当前 module(App 或 Library) | variant.artifacts.use(...) + Task |
| 处理 SDK、第三方 AAR/JAR 中的 class 文件 | 所有依赖(包括远程、本地依赖) | dependencies.registerTransform(...) + TransformAction |
二、处理依赖 class:使用 ArtifactTransform
1. 注册 Transform(推荐写在插件中)
project.dependencies.registerTransform(HookJarTransform::class.java) {
it.from.attribute(ArtifactAttributes.ARTIFACT_FORMAT, ArtifactType.JAR.type)
it.to.attribute(ArtifactAttributes.ARTIFACT_FORMAT, "processed-classes-jar")
}
2. 实现 TransformAction
abstract class HookJarTransform : TransformAction<TransformParameters.None> {
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:OutputFile
abstract val outputJar: RegularFileProperty
override fun transform(outputs: TransformOutputs) {
val input = inputJar.get().asFile
val output = outputJar.get().asFile
// 用 ASM 插码或复制 class
}
}
3. 插件类中注册(无需使用 variant.artifacts.use)
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.dependencies.registerTransform(...) // 如上
}
}
✅ 这种方式适用于你要操作 SDK、依赖 AAR/JAR 包中的 class。
三、处理自身 class:使用 variant.artifacts.use
val transformTask = project.tasks.register("MyClassTransform", MyClassTransformTask::class.java)
androidComponents.onVariants { variant ->
variant.artifacts.use(transformTask)
.wiredWithFiles(MyClassTransformTask::inputDir, MyClassTransformTask::outputDir)
.toTransform(SingleArtifact.ALL_CLASSES_DIRS)
}
这种方式创建 Task 来处理构建产物,适合对当前 module 的 class 文件夹进行插码。
⚠️ 不适用于处理依赖的 AAR 或 JAR!
四、常见错误与解决
| 错误提示 | 原因 | 正确做法 |
|---|---|---|
type mismatch: expected TaskProvider | 你把 TransformAction 用到了 variant.artifacts.use(...) 中 | 用 registerTransform 注册 transform |
Could not generate decorated class | Transform 参数配置不完整或不可序列化 | 用 Gradle Property<T> 类型,避免非 Serializable 字段 |
Cannot query property | Gradle Property 没赋值 | 使用 .convention() 或 .set() 提前赋默认值 |
五、总结
- ✅ 要处理 SDK 依赖里的 class,用
project.dependencies.registerTransform() - ✅ 要处理本模块的 class,用
variant.artifacts.use()+ Task - ❌ 不要在
variant.artifacts.use(...)中传 TransformAction 类型(会报错) - ✅ 插件中也必须区分这两种处理方式