com.dingyi.groovy.android.GroovyScriptFactory.kt Maven / Gradle / Ivy
package com.dingyi.groovy.android
import android.util.Log
import com.android.tools.r8.*
import com.android.tools.r8.origin.Origin
import dalvik.system.DexFile
import groovy.lang.GrooidClassLoader
import groovy.lang.Script
import org.codehaus.groovy.control.CompilerConfiguration
import java.io.File
class GroovyScriptFactory(
private val compileDir: File = AppDataDirGuesser().guess(),
) {
private fun calculateMd5(bytes: ByteArray): String {
val md5 = java.security.MessageDigest.getInstance("MD5")
md5.update(bytes)
val digest = md5.digest()
val hexString = StringBuilder()
for (b in digest) {
var temp = Integer.toHexString(b.toInt() and 0xFF)
if (temp.length == 1) {
temp = "0$temp"
}
hexString.append(temp)
}
return hexString.toString()
}
private fun createScriptClassLoader(
scriptText: String, outputFile: File,
fileName: String = "AnonymousGroovyScript",
classLoader: ClassLoader = this.javaClass.classLoader
): EvalResult>> {
val dexBuilder = D8Command.builder()
.apply {
disableDesugaring = true
minApiLevel = 26
setOutput(
outputFile.toPath(),
OutputMode.DexIndexed
)
}
val groovyCompilerConfiguration = CompilerConfiguration()
val groovyClassLoader = GrooidClassLoader(classLoader, groovyCompilerConfiguration)
val classNameList = mutableListOf()
groovyCompilerConfiguration.apply {
setBytecodePostprocessor { className, classByte ->
Log.d("GroovyScriptFactory", "className: $className classByte: $classByte")
dexBuilder.addClassProgramData(classByte, Origin.unknown())
classNameList.add(className)
classByte
}
}
groovyClassLoader
.parseClass(scriptText, fileName)
D8.run(dexBuilder.build())
return kotlin.runCatching {
EvalResult.successWithType(
DexClassLoader(
outputFile
.absolutePath, null, null, classLoader
) to classNameList
)
}.getOrElse {
EvalResult.failureWithType(it)
}
}
fun createScript(
scriptText: String, outputFile: File,
fileName: String = "AnonymousGroovyScript",
classLoader: ClassLoader = this.javaClass.classLoader
): EvalResult