-
Notifications
You must be signed in to change notification settings - Fork 193
/
build.gradle.kts
115 lines (104 loc) · 4.31 KB
/
build.gradle.kts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
plugins {
id("com.android.application")
kotlin("android")
}
import com.android.build.api.variant.ScopedArtifacts
import com.android.build.api.artifact.ScopedArtifact
import org.gradle.api.DefaultTask
import org.gradle.api.file.Directory
import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.TaskAction
import javassist.ClassPool
import javassist.CtClass
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.BufferedOutputStream
import java.io.File
import java.util.jar.JarFile
import java.util.jar.JarEntry
import java.util.jar.JarOutputStream
abstract class ModifyClassesTask: DefaultTask() {
@get:InputFiles
abstract val allJars: ListProperty<RegularFile>
@get:InputFiles
abstract val allDirectories: ListProperty<Directory>
@get:OutputFile
abstract val output: RegularFileProperty
@TaskAction
fun taskAction() {
val pool = ClassPool(ClassPool.getDefault())
val jarOutput = JarOutputStream(BufferedOutputStream(FileOutputStream(
output.get().asFile
)))
allJars.get().forEach { file ->
println("handling " file.asFile.getAbsolutePath())
val jarFile = JarFile(file.asFile)
jarFile.entries().iterator().forEach { jarEntry ->
println("Adding from jar ${jarEntry.name}")
jarOutput.putNextEntry(JarEntry(jarEntry.name))
jarFile.getInputStream(jarEntry).use {
it.copyTo(jarOutput)
}
jarOutput.closeEntry()
}
jarFile.close()
}
allDirectories.get().forEach { directory ->
println("handling " directory.asFile.getAbsolutePath())
directory.asFile.walk().forEach { file ->
if (file.isFile) {
if (file.name.endsWith("SomeSource.class")) {
println("Found $file.name")
val interfaceClass = pool.makeInterface("com.android.api.tests.SomeInterface");
println("Adding $interfaceClass")
jarOutput.putNextEntry(JarEntry("com/android/api/tests/SomeInterface.class"))
jarOutput.write(interfaceClass.toBytecode())
jarOutput.closeEntry()
val ctClass = file.inputStream().use {
pool.makeClass(it);
}
ctClass.addInterface(interfaceClass)
val m = ctClass.getDeclaredMethod("toString");
if (m != null) {
m.insertBefore("{ System.out.println(\"Some Extensive Tracing\"); }");
val relativePath = directory.asFile.toURI().relativize(file.toURI()).getPath()
jarOutput.putNextEntry(JarEntry(relativePath.replace(File.separatorChar, '/')))
jarOutput.write(ctClass.toBytecode())
jarOutput.closeEntry()
} else {
val relativePath = directory.asFile.toURI().relativize(file.toURI()).getPath()
println("Adding from directory ${relativePath.replace(File.separatorChar, '/')}")
jarOutput.putNextEntry(JarEntry(relativePath.replace(File.separatorChar, '/')))
file.inputStream().use { inputStream ->
inputStream.copyTo(jarOutput)
}
jarOutput.closeEntry()
}
}
}
}
}
jarOutput.close()
}
}
android {
namespace = "com.android.build.example.minimal"
compileSdkVersion(29)
defaultConfig {
minSdkVersion(21)
}
}
androidComponents {
onVariants { variant ->
val taskProvider = project.tasks.register<ModifyClassesTask>("${variant.name}ModifyClasses")
variant.artifacts.forScope(ScopedArtifacts.Scope.PROJECT)
.use(taskProvider)
.toTransform(
ScopedArtifact.CLASSES,
ModifyClassesTask::allJars,
ModifyClassesTask::allDirectories,
ModifyClassesTask::output
)
}
}