mirror of
https://github.com/fankes/unmeta-gradle-plugin.git
synced 2025-09-04 01:55:16 +08:00
Support android builds via AGP
This commit is contained in:
@@ -4,15 +4,17 @@ kotlin = "1.8.21"
|
||||
ktlintGradle = "11.3.2"
|
||||
pluginPublish = "1.2.0"
|
||||
versionCheck = "0.46.0"
|
||||
androidGradlePlugin = "7.3.0"
|
||||
|
||||
[plugins]
|
||||
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt"}
|
||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin"}
|
||||
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlintGradle"}
|
||||
pluginPublish = { id = "com.gradle.plugin-publish", version.ref = "pluginPublish"}
|
||||
versionCheck = { id = "com.github.ben-manes.versions", version.ref = "versionCheck"}
|
||||
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
|
||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlintGradle" }
|
||||
pluginPublish = { id = "com.gradle.plugin-publish", version.ref = "pluginPublish" }
|
||||
versionCheck = { id = "com.github.ben-manes.versions", version.ref = "versionCheck" }
|
||||
|
||||
[libraries]
|
||||
junit = "junit:junit:4.13.2"
|
||||
truth = "com.google.truth:truth:1.1.3"
|
||||
asm = "org.ow2.asm:asm:9.4"
|
||||
androidGradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }
|
||||
|
@@ -10,6 +10,7 @@ dependencies {
|
||||
implementation(kotlin("stdlib"))
|
||||
implementation(gradleApi())
|
||||
implementation(libs.asm)
|
||||
implementation(libs.androidGradlePlugin)
|
||||
|
||||
testImplementation(libs.junit)
|
||||
testImplementation(libs.truth)
|
||||
|
@@ -1,35 +1,25 @@
|
||||
package com.axzae.unmeta
|
||||
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.objectweb.asm.AnnotationVisitor
|
||||
import org.objectweb.asm.ClassVisitor
|
||||
import org.objectweb.asm.Opcodes
|
||||
|
||||
class UnmetaClassVisitor(
|
||||
private val path: String,
|
||||
val path: String,
|
||||
classVisitor: ClassVisitor,
|
||||
private val logger: Logger,
|
||||
) : ClassVisitor(Opcodes.ASM7, classVisitor), Opcodes {
|
||||
|
||||
var modified = false
|
||||
|
||||
override fun visitAnnotation(desc: String?, visible: Boolean): AnnotationVisitor? {
|
||||
return when (desc) {
|
||||
"Lkotlin/Metadata;" -> {
|
||||
logger.debug("Removed @Metadata annotation from $path")
|
||||
modified = true
|
||||
null
|
||||
}
|
||||
var isModified = false
|
||||
private set
|
||||
|
||||
override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? {
|
||||
return when (descriptor) {
|
||||
"Lkotlin/coroutines/jvm/internal/DebugMetadata;" -> {
|
||||
logger.debug("Removed @DebugMetadata annotation from $path")
|
||||
modified = true
|
||||
isModified = true
|
||||
null
|
||||
}
|
||||
|
||||
else -> {
|
||||
super.visitAnnotation(desc, visible)
|
||||
}
|
||||
else -> super.visitAnnotation(descriptor, visible)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,13 @@
|
||||
package com.axzae.unmeta
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import javax.inject.Inject
|
||||
|
||||
const val DEFAULT_IS_ENABLED = true
|
||||
const val DEFAULT_VERBOSE = false
|
||||
const val DEFAULT_OUTPUT_FILE = "outputs/logs/unmeta.txt"
|
||||
|
||||
@Suppress("UnnecessaryAbstractClass")
|
||||
abstract class UnmetaExtension @Inject constructor(project: Project) {
|
||||
@@ -13,4 +16,10 @@ abstract class UnmetaExtension @Inject constructor(project: Project) {
|
||||
|
||||
val isEnabled: Property<Boolean> = objects.property(Boolean::class.java)
|
||||
.convention(DEFAULT_IS_ENABLED)
|
||||
|
||||
val verbose: Property<Boolean> = objects.property(Boolean::class.java)
|
||||
.convention(DEFAULT_VERBOSE)
|
||||
|
||||
val outputFile: RegularFileProperty = objects.fileProperty()
|
||||
.convention(project.layout.buildDirectory.file(DEFAULT_OUTPUT_FILE))
|
||||
}
|
||||
|
@@ -1,17 +1,25 @@
|
||||
package com.axzae.unmeta
|
||||
|
||||
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
const val EXTENSION_NAME = "unmeta"
|
||||
const val TASK_NAME = "unmetaTask"
|
||||
import org.gradle.configurationcache.extensions.capitalized
|
||||
|
||||
abstract class UnmetaPlugin : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
val extension = project.extensions.create(EXTENSION_NAME, UnmetaExtension::class.java, project)
|
||||
|
||||
project.tasks.register(TASK_NAME, UnmetaTask::class.java) {
|
||||
it.isEnabled = extension.isEnabled.get()
|
||||
val extension = project.extensions.create("unmeta", UnmetaExtension::class.java, project)
|
||||
val androidComponents = project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
|
||||
androidComponents.onVariants(androidComponents.selector().withBuildType("release")) { variant ->
|
||||
val compileKotlinTaskName = "compile${variant.name.capitalized()}Kotlin"
|
||||
val unmetaTask = project.tasks.create("unmeta${variant.name.capitalized()}", UnmetaTask::class.java).apply {
|
||||
isEnabled = extension.isEnabled.get()
|
||||
verbose.set(extension.verbose.get())
|
||||
variantName.set(variant.name)
|
||||
outputFile.set(extension.outputFile)
|
||||
}
|
||||
project.afterEvaluate {
|
||||
project.tasks.findByName(compileKotlinTaskName)?.finalizedBy(unmetaTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,17 @@
|
||||
package com.axzae.unmeta
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.options.Option
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.ClassWriter
|
||||
import java.io.File
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
abstract class UnmetaTask : DefaultTask() {
|
||||
|
||||
@@ -14,27 +20,54 @@ abstract class UnmetaTask : DefaultTask() {
|
||||
group = BasePlugin.BUILD_GROUP
|
||||
}
|
||||
|
||||
@get:Input
|
||||
@get:Option(option = "variantName", description = "Android variant (flavor + buildType)")
|
||||
abstract val variantName: Property<String>
|
||||
|
||||
@get:Input
|
||||
@get:Option(option = "verbose", description = "Enable verbose logging")
|
||||
abstract val verbose: Property<Boolean>
|
||||
|
||||
@get:OutputFile
|
||||
abstract val outputFile: RegularFileProperty
|
||||
|
||||
private val fileLogger by lazy { outputFile.get().asFile }
|
||||
|
||||
@TaskAction
|
||||
fun unmetaAction() {
|
||||
if (!isEnabled) {
|
||||
logger.warn("unmeta is disabled")
|
||||
log("unmeta is disabled")
|
||||
return
|
||||
}
|
||||
|
||||
logger.info("Start dropping @Metadata & @DebugMetadata from kotlin classes")
|
||||
project.buildDir.listFiles()?.forEach { file -> if (file.isDirectory) dropMetadata(file) }
|
||||
log("Start dropping @DebugMetadata from kotlin classes")
|
||||
val executionMs = measureTimeMillis {
|
||||
val kotlinClassesPath = project.buildDir.absolutePath + "/tmp/kotlin-classes/${variantName.get()}"
|
||||
File(kotlinClassesPath).listFiles()?.forEach { file ->
|
||||
if (file.isDirectory) removeAnnotation(file)
|
||||
}
|
||||
}
|
||||
log("Unmeta Total Time: ${executionMs}ms")
|
||||
}
|
||||
|
||||
private fun dropMetadata(directory: File) {
|
||||
private fun log(message: String) {
|
||||
when (verbose.get()) {
|
||||
true -> logger.lifecycle(message)
|
||||
else -> logger.debug(message)
|
||||
}
|
||||
fileLogger.appendText(message + System.lineSeparator(), Charsets.UTF_8)
|
||||
}
|
||||
|
||||
private fun removeAnnotation(directory: File) {
|
||||
directory.walk()
|
||||
.filter { it.path.contains("classes") && it.path.endsWith(".class") && it.isFile }
|
||||
.forEach {
|
||||
val sourceClassBytes = it.readBytes()
|
||||
val classReader = ClassReader(sourceClassBytes)
|
||||
val classWriter = ClassWriter(classReader, ClassWriter.COMPUTE_MAXS)
|
||||
val unmetaClassVisitor = UnmetaClassVisitor(it.absolutePath, classWriter, logger)
|
||||
val unmetaClassVisitor = UnmetaClassVisitor(it.absolutePath, classWriter)
|
||||
classReader.accept(unmetaClassVisitor, ClassReader.SKIP_DEBUG)
|
||||
if (unmetaClassVisitor.modified) {
|
||||
if (unmetaClassVisitor.isModified) {
|
||||
log("Removed @DebugMetadata annotation from ${unmetaClassVisitor.path}")
|
||||
it.writeBytes(classWriter.toByteArray())
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,4 @@ gradleEnterprise {
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = ("com.axzae.unmeta")
|
||||
|
||||
include(":plugin")
|
||||
|
@@ -2,6 +2,7 @@ pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user