概述
build.gradle:
plugins {
id 'java'
//id 'groovy'
id 'org.jetbrains.kotlin.jvm' version '1.5.31'
id 'java-gradle-plugin'
}
repositories {
google()
mavenCentral()
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
compileKotlin {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
dependencies {
//implementation localGroovy()
//implementation gradleApi()
implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
implementation "com.android.tools.build:gradle:7.0.4"
implementation "com.android.tools.build:gradle-api:7.0.4"
implementation "commons-io:commons-io:2.9.0"
//implementation "commons-codec:commons-codec:1.15"
implementation "org.ow2.asm:asm:9.2"
implementation "org.ow2.asm:asm-tree:9.2"
}
XXXPlugin:
import com.android.build.gradle.BaseExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
/**
* @author ganmin.he
* @date 2022/1/5
*/
class XXXPlugin : Plugin<Project> {
override fun apply(project: Project) {
println("Welcome to xxx plugin...")
val ext = project.extensions.getByType(BaseExtension::class.java)
ext.registerTransform(XXXTransform(project))
}
}
BaseTransform:
import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import org.apache.commons.io.FileUtils
import org.gradle.api.Project
import java.io.File
/**
* @author ganmin.he
* @date 2022/1/5
*/
abstract class BaseTransform(protected val project: Project) : Transform() {
protected val tag = javaClass.simpleName
protected fun log(msg: String) {
project.logger.lifecycle("$tag: $msg")
}
abstract override fun getName(): String
override fun getInputTypes(): MutableSet<QualifiedContent.ContentType> {
return TransformManager.CONTENT_CLASS
}
override fun getScopes(): MutableSet<in QualifiedContent.Scope> {
return TransformManager.SCOPE_FULL_PROJECT
}
final override fun isIncremental(): Boolean = true
/**
* @return true if transformed jar has been written to destOutput, else false.
*/
abstract fun doTransformJar(jarInput: JarInput, destOutput: File): Boolean
/**
* @return true if transformed file has been written to destOutput, else false.
*/
abstract fun doTransformFile(fileInput: File, destOutput: File): Boolean
final override fun transform(transformInvocation: TransformInvocation) {
log("start transform")
val isIncremental = transformInvocation.isIncremental
// Consumer input, the jar and class directory path can be obtained from it,
// and it needs to be output to the next transformer.
val transformInputs = transformInvocation.inputs
// Reference input, no output required.
val referenceInputs = transformInvocation.referencedInputs
// outputProvider manage output paths.
// If transformInputs is empty, outputProvider will be null.
val outputProvider = transformInvocation.outputProvider
// The source file of the sub-module will also generate a jar during the compilation process
// and then be compiled into the main project.
transformInputs.forEach { input ->
input.jarInputs.forEach jarInputs@{ jarInput ->
//log("jarInput $jarInput")
val destJar = outputProvider.getContentLocation(
jarInput.name,
jarInput.contentTypes,
jarInput.scopes,
Format.JAR
)
if (isIncremental) {
when (jarInput.status) {
Status.REMOVED -> {
log("delete $destJar")
FileUtils.deleteQuietly(destJar)
return@jarInputs
}
Status.NOTCHANGED -> return@jarInputs
Status.ADDED, Status.CHANGED -> {}
}
}
if (!doTransformJar(jarInput, destJar)) {
// Copy the unmodified bytecode to dest.
FileUtils.copyFile(jarInput.file, destJar)
}
}
input.directoryInputs.forEach { directoryInput ->
//log("directoryInput ${directoryInput.file}")
val destDir = outputProvider.getContentLocation(
directoryInput.name,
directoryInput.contentTypes,
directoryInput.scopes,
Format.DIRECTORY
)
if (isIncremental) {
directoryInput.changedFiles.forEach changedFiles@{ (file, status) ->
val destFile = File(destDir, file.relativeTo(directoryInput.file).path)
when (status) {
Status.REMOVED -> {
log("delete $destFile")
FileUtils.deleteQuietly(destFile)
return@changedFiles
}
Status.NOTCHANGED -> return@changedFiles
Status.ADDED, Status.CHANGED -> {
if (!doTransformFile(file, destFile)) {
// Copy the unmodified bytecode to dest.
log("copy to $destFile")
FileUtils.copyFile(file, destFile)
}
}
}
}
} else {
FileUtils.deleteQuietly(destDir)
FileUtils.iterateFiles(directoryInput.file, null, true).forEach { file ->
val destFile = File(destDir, file.relativeTo(directoryInput.file).path)
if (!doTransformFile(file, destFile)) {
// Copy the unmodified bytecode to dest.
//log("copy to $destFile")
FileUtils.copyFile(file, destFile)
}
}
}
}
}
log("end transform")
}
}
XXXTransform:
import com.android.build.api.transform.*
import org.gradle.api.Project
import java.io.File
import java.io.FileOutputStream
import java.util.jar.JarEntry
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
/**
* @author ganmin.he
* @date 2022/1/5
*/
class TrackTransform(project: Project) : BaseTransform(project) {
companion object {
private const val TARGET = "a/b/c/Target.class"
private val TARGETS = arrayOf(TARGET)
}
override fun getName(): String = "xxx"
override fun doTransformJar(jarInput: JarInput, destOutput: File): Boolean {
JarFile(jarInput.file).use { jarFile ->
val entries = jarFile.entries().toList()
val filter = entries.filter {
TARGETS.contains(it.name)
}
if (filter.isEmpty()) return false
// Write the modified bytecode directly to destOutput.
JarOutputStream(FileOutputStream(destOutput)).use { jos ->
entries.forEach { other ->
if (filter.contains(other)) return@forEach
jos.putNextEntry(JarEntry(other.name))
jarFile.getInputStream(other).use {
jos.write(it.readAllBytes())
}
jos.closeEntry()
}
filter.forEach { targetEntry ->
log("found ${targetEntry.name} in ${jarInput.file}")
jos.putNextEntry(JarEntry(targetEntry.name))
jarFile.getInputStream(targetEntry).use {
when (targetEntry.name) {
TARGET -> ModifyTarget.modifyByteCode(it)
else -> it.readAllBytes()
}
}.let {
jos.write(it)
}
jos.closeEntry()
}
log("write to $destOutput")
}
return true
}
}
override fun doTransformFile(fileInput: File, destOutput: File): Boolean = false
}
最后
以上就是舒服外套为你收集整理的Android Gradle Transform 学习的全部内容,希望文章能够帮你解决Android Gradle Transform 学习所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复