All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.flyjingfish.android_aop_plugin.utils.ClassFileUtils.kt Maven / Gradle / Ivy

Go to download

Lightweight Aop for Android platform, you deserve it, action is worse than your heartbeat

There is a newer version: 2.2.8
Show newest version
package com.flyjingfish.android_aop_plugin.utils

import com.flyjingfish.android_aop_plugin.beans.InvokeClass
import com.flyjingfish.android_aop_plugin.scanner_visitor.WovenIntoCode
import com.flyjingfish.android_aop_plugin.utils.Utils.CONVERSIONS_CLASS
import javassist.CannotCompileException
import javassist.NotFoundException
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes.ACC_PUBLIC
import org.objectweb.asm.Opcodes.ALOAD
import org.objectweb.asm.Opcodes.DUP
import org.objectweb.asm.Opcodes.INVOKESPECIAL
import org.objectweb.asm.Opcodes.IRETURN
import org.objectweb.asm.Opcodes.NEW
import org.objectweb.asm.Opcodes.RETURN
import org.objectweb.asm.Opcodes.V1_8
import java.io.ByteArrayInputStream
import java.io.File
import java.io.FileOutputStream

object ClassFileUtils {
    var reflectInvokeMethod = false
    var debugMode = false
    lateinit var outputDir:File
    var outputCacheDir:File ?= null
    private val invokeClasses = mutableListOf()
    private const val INVOKE_METHOD = "invoke"
    private const val INVOKE_DESCRIPTOR = "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
    private const val INVOKE_CLASS = "com.flyjingfish.android_aop_annotation.utils.InvokeMethod"
    fun clear(){
        invokeClasses.clear()
    }
    fun wovenInfoInvokeClass(newClasses: MutableList) :MutableList {
        val cacheFiles = mutableListOf()
        if (reflectInvokeMethod){
            return cacheFiles
        }
        for (invokeClass in invokeClasses) {

            val className = invokeClass.packageName
            val invokeBody = invokeClass.invokeBody
            val path = outputDir.absolutePath + File.separatorChar +Utils.dotToSlash(className).adapterOSPath()+".class"
            val outFile = File(path)
            if (outputCacheDir != null && outFile.exists()){
                continue
            }
//            println("invokeClass.methodName="+invokeClass.methodName)
            val cp = ClassPoolUtils.getNewClassPool()
            outputCacheDir?.let {
                cp.appendClassPath(it.absolutePath)
            }
            newClasses.forEach {
                cp.makeClass(ByteArrayInputStream(it))
            }
            cp.importPackage(CONVERSIONS_CLASS)
            val ctClass = cp.get(className)
            try {
                val ctMethod =
                    WovenIntoCode.getCtMethod(ctClass, INVOKE_METHOD, INVOKE_DESCRIPTOR)
                ctMethod?.setBody(invokeBody)
            } catch (e: NotFoundException) {
                throw RuntimeException(e)
            } catch (e: CannotCompileException) {
                printLog("invokeBody=$invokeBody")
                throw RuntimeException(e)
            }
            val classByteData = ctClass.toBytecode()
//            //把类数据写入到class文件,这样你就可以把这个类文件打包供其他的人使用
            outFile.checkExist()
            classByteData.saveFile(outFile)
            cacheFiles.add(path)
            ctClass.detach()
        }
        return cacheFiles
    }

    fun createInvokeClass(className:String, invokeBody:String, methodName:String) {
        if (reflectInvokeMethod){
            return
        }
        invokeClasses.add(InvokeClass(className,invokeBody,methodName))
        if (File(outputDir.absolutePath + File.separatorChar +Utils.dotToSlash(className).adapterOSPath()+".class").exists()){
            return
        }
        val cacheOutFir = outputCacheDir
        val outFile = if (cacheOutFir != null){
            File(cacheOutFir.absolutePath + File.separatorChar +Utils.dotToSlash(className).adapterOSPath()+".class")
        }else{
            File(outputDir.absolutePath + File.separatorChar +Utils.dotToSlash(className).adapterOSPath()+".class")
        }
        if (outFile.exists()){
            return
        }

        outFile.checkExist()
//        val className = "$packageName.Invoke${UUID.randomUUID()}"
        //新建一个类生成器,COMPUTE_FRAMES,COMPUTE_MAXS这2个参数能够让asm自动更新操作数栈
        val cw = ClassWriter(ClassWriter.COMPUTE_FRAMES or ClassWriter.COMPUTE_MAXS)
        //生成一个public的类,类路径是com.study.Human
        cw.visit(
            V1_8,
            ACC_PUBLIC, Utils.dotToSlash(className), null, "java/lang/Object", arrayOf(Utils.dotToSlash(INVOKE_CLASS))
        )

        //生成默认的构造方法: public Human()
        var mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)
        mv.visitVarInsn(ALOAD, 0)
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false)
        mv.visitInsn(RETURN)
        mv.visitMaxs(0, 0) //更新操作数栈
        mv.visitEnd() //一定要有visitEnd


        //生成静态方法
        mv = cw.visitMethod(ACC_PUBLIC, INVOKE_METHOD, INVOKE_DESCRIPTOR, null, null)
        mv.visitCode();

        //创建StringBuilder对象
        mv.visitTypeInsn(NEW, "java/lang/Object")
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false)

        mv.visitInsn(IRETURN)
        mv.visitMaxs(0, 0)
        mv.visitEnd()

        cw.toByteArray().saveFile(outFile)
    }

    fun deleteInvokeClass(className:String) {
        if (reflectInvokeMethod){
            return
        }
        val iterator = invokeClasses.iterator()
        while (iterator.hasNext()){
            val item = iterator.next();
            if (item.packageName == className){
                iterator.remove()
                break
            }
        }
        outputCacheDir?.let {
            val file = File(it.absolutePath +File.separatorChar +Utils.dotToSlash(className).adapterOSPath()+".class")
            if (file.exists()){
                file.delete()
            }
        }
        val file = File(outputDir.absolutePath + File.separatorChar +Utils.dotToSlash(className).adapterOSPath()+".class")
        if (file.exists()){
            file.delete()
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy