Last active
April 5, 2022 23:34
-
-
Save droidchef/64c249db574836046d0a11dee96c9865 to your computer and use it in GitHub Desktop.
Transform Plugin to add functionality to a Fragment class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.android.SdkConstants | |
import com.android.build.api.transform.* | |
import com.android.build.gradle.BaseExtension | |
import com.android.build.gradle.internal.plugins.AppPlugin | |
import com.android.build.gradle.internal.plugins.LibraryPlugin | |
import javassist.ClassPool | |
import org.apache.commons.io.FileUtils | |
import org.apache.commons.io.IOUtils | |
import org.gradle.api.Plugin | |
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 | |
class LingoTransformPlugin: Plugin<Project> { | |
override fun apply(project: Project) { | |
val isAndroid = project.plugins.hasPlugin(AppPlugin::class.java) | |
|| project.plugins.hasPlugin(LibraryPlugin::class.java) | |
if( !isAndroid) { | |
throw error("'com.android.application' or 'com.android.library' plugin required.") | |
} | |
val daggerTrackExtension = project.extensions.create("lingoTransform", LingoTransformExtension::class.java) | |
val android = project.extensions.findByName("android") as BaseExtension | |
android.registerTransform(LingoTransform(project, android, daggerTrackExtension)) | |
} | |
open class LingoTransformExtension { | |
var applyFor: Array<String> = emptyArray() | |
} | |
} | |
class LingoTransform( | |
private val project: Project, | |
private val android: BaseExtension, | |
private val lingoTransformExtension: LingoTransformPlugin.LingoTransformExtension | |
): Transform() { | |
override fun getName(): String { | |
return "LingoTransform" | |
} | |
override fun getInputTypes(): Set<QualifiedContent.DefaultContentType> { | |
return setOf(QualifiedContent.DefaultContentType.CLASSES) | |
} | |
override fun getScopes(): MutableSet<in QualifiedContent.Scope> { | |
return mutableSetOf(QualifiedContent.Scope.EXTERNAL_LIBRARIES) | |
} | |
override fun isIncremental(): Boolean { | |
return true | |
} | |
override fun transform(transformInvocation: TransformInvocation) { | |
transformInvocation.inputs.forEach { transformInput -> | |
transformInput.jarInputs.forEach { | |
val jarName = it.name | |
val src = it.file | |
val dest = transformInvocation.outputProvider.getContentLocation( | |
jarName, it.contentTypes, it.scopes, Format.JAR | |
) | |
if (src.toString().contains("fragment-1.3.6")) { | |
val androidJar = "${android.sdkDirectory.absolutePath}/platforms/${android.compileSdkVersion}/android.jar" | |
val pool = ClassPool() | |
pool.insertClassPath(src.absolutePath) | |
pool.insertClassPath(androidJar) | |
val fragmentClass = pool.get("androidx.fragment.app.Fragment") | |
val methods = fragmentClass.getDeclaredMethods("getString") | |
methods.forEach { method -> | |
method.insertAfter("java.lang.System.out.println(\"THIS IS WHERE THE MAGIC HAPPENS\");") | |
} | |
val byteCode = fragmentClass.toBytecode() | |
val ip = JarFile(src) | |
val op = JarOutputStream(FileOutputStream(dest)) | |
for (entry in ip.entries()) { | |
if (!entry.name.equals("androidx/fragment/app/Fragment.class")) { | |
val s = ip.getInputStream(entry) | |
op.putNextEntry(JarEntry(entry.name)) | |
IOUtils.copy(s, op) | |
s.close() | |
} | |
} | |
op.putNextEntry(JarEntry("androidx/fragment/app/Fragment.class")) | |
op.write(byteCode) | |
op.close() | |
} else { | |
FileUtils.copyFile(src, dest) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment