AGP 8.0 废弃Transform了怎么办?

447 阅读2分钟

一、背景

经过Gradle升级踩坑经历(4.1.1->7.4.2)后,我们发现AGP 7.4.2依然支持各个插件使用regsterTransrom方法进行插桩

但根据官网文档和源码看,AGP 8.0以后会直接移除此api,因此在将来,各个插件将面临无法插桩的情况,因此需要寻求新的解决方案,我们将以Dilution插件作为改造对象进行尝试;

二、自定义插件改造

1、首先,根据AGP 7.4.2的源码观察,都采用了kotlin,所以第一步要将Dilution改造为kotlin(否则我们在编写新方案的时候会处处受阻)

将apply plugin: 'groovy'

改造为:

apply plugin: 'java-library'
apply plugin: 'groovy'
apply plugin: 'kotlin'

并新增依赖:
dependencies {

    implementation gradleApi()
    implementation localGroovy()
    implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0"
    implementation 'com.android.tools.build:gradle:7.4.2'
    implementation 'org.ow2.asm:asm:7.0'
    implementation 'org.ow2.asm:asm-commons:7.0'
    implementation 'org.apache.httpcomponents:httpclient:4.2.1'
    implementation 'commons-io:commons-io:2.6'
    implementation 'com.google.guava:guava:23.0-android'
}

classpath新增:
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21"

2、改造Plugin注册入口代码

2.1 原先代码是(groovy文件):

public class PluginImpl extends Transform implements Plugin<Project> ,Opcodes{
    ....
    void apply(Project project) {
        project.extensions.create("dilutionConfig", DilutionConfig.class)
        project.afterEvaluate {
            mDilutionConfig =(DilutionConfig) project.property("dilutionConfig")
            println("mDilutionConfig内容:"+mDilutionConfig.toString())
        }
        def android = project.extensions.getByType(AppExtension);
        android.registerTransform(this)
    }


改为:(kotlin文件)

public class DilutionPluginImp:Plugin<Project>{

    override fun apply(project: Project) {
        println("===>DilutionPlugin插件apply")
        project.extensions.create("dilutionConfig", DilutionConfig::class.java)
        var androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
        println("===>DilutionPlugin插件 get androidComponents")
        androidComponents.onVariants {
            variant ->
                println("===>执行Variant: ${variant.name}")//这里变种,release或者debug之类的,往每个变种注册一个任务,用于收集类和改造信息
                var dilutionConfig = project.extensions.getByType(DilutionConfig::class.java)
                println("===>dilutionConfig内容:${dilutionConfig.toString()}")
                variant.instrumentation.setAsmFramesComputationMode(
                    FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS)
                var taskProvider = project.tasks.register("${variant.name}DilutionModifyClasses",
                    DilutionModifyClassesTask::class.java)
                taskProvider.get().setDilutionoConfig(dilutionConfig)
                println("===>开始设置输入输出")
                variant.artifacts.forScope(ScopedArtifacts.Scope.ALL)
                    .use(taskProvider)
                    .toTransform(ScopedArtifact.CLASSES,DilutionModifyClassesTask::allJars,
                        DilutionModifyClassesTask::allDirectories,
                        DilutionModifyClassesTask::output)
            println("===>开始设置输入输出成功")
        }
    }

编写task 任务如下:

package com.meetyou.dilutions.pluginkt

import com.meetyou.dilutions.BlackhandClassVisitor
import com.meetyou.dilutions.DilutionConfig
import com.meetyou.dilutions.DilutionsMetasWriter
import org.gradle.api.DefaultTask
import org.gradle.api.file.Directory
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.util.jar.JarEntry
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry


abstract class DilutionModifyClassesTask : DefaultTask() {

    @get:InputFiles
    abstract val allJars: ListProperty<RegularFile>

    @get:InputFiles
    abstract val allDirectories: ListProperty<Directory>

    @get:OutputFile
    abstract val output: RegularFileProperty

    //Method metas
    @Internal
    var mMetas = HashMap<String, ArrayList<String>>()

    //UI metas
    @Internal
    var mUIMetas = HashMap<String, ArrayList<String>>()

    @Internal
    private var dilutionConfig: DilutionConfig? = null

    open fun setDilutionoConfig(dilutionConfig: DilutionConfig?) {
        this.dilutionConfig = dilutionConfig
    }


    @TaskAction
    open fun taskAction() {
      ...

打包插件后重新编译,出现以下错误:

Task :app:debugDilutionModifyClasses FAILED


FAILURE: Build failed with an exception.

* What went wrong:  
Some problems were found with the configuration of task ':app:debugDilutionModifyClasses' (type 'DilutionModifyClassesTask').  
  - In plugin 'dilutions' type 'com.meetyou.dilutions.pluginkt.DilutionModifyClassesTask' field 'dilutionConfig' without corresponding getter has been annotated with @Internal.  
      
    Reason: Annotations on fields are only used if there's a corresponding getter for the field.  
      
    Possible solutions:  
      1. Add a getter for field 'dilutionConfig'.  
      2. Remove the annotations on 'dilutionConfig'.  
      
    Please refer to <https://docs.gradle.org/7.5/userguide/validation_problems.html#ignored_annotations_on_field> for more details about this problem.  
  - In plugin 'dilutions' type 'com.meetyou.dilutions.pluginkt.DilutionModifyClassesTask' field 'mMetas' without corresponding getter has been annotated with @Internal.  
      
    Reason: Annotations on fields are only used if there's a corresponding getter for the field.  
      
    Possible solutions:  
      1. Add a getter for field 'mMetas'.  
      2. Remove the annotations on 'mMetas'.  
      
    Please refer to <https://docs.gradle.org/7.5/userguide/validation_problems.html#ignored_annotations_on_field> for more details about this problem.  
  - In plugin 'dilutions' type 'com.meetyou.dilutions.pluginkt.DilutionModifyClassesTask' field 'mUIMetas' without corresponding getter has been annotated with @Internal.  
      
    Reason: Annotations on fields are only used if there's a corresponding getter for the field.  
      
    Possible solutions:  
      1. Add a getter for field 'mUIMetas'.  
      2. Remove the annotations on 'mUIMetas'.  
      
    Please refer to <https://docs.gradle.org/7.5/userguide/validation_problems.html#ignored_annotations_on_field> for more details about this problem.  
  - In plugin 'dilutions' type 'com.meetyou.dilutions.pluginkt.DilutionModifyClassesTask' property 'MMetas' is missing an input or output annotation.  
      
    Reason: A property without annotation isn't considered during up-to-date checking.  
      
    Possible solutions:  
      1. Add an input or output annotation.  
      2. Mark it as @Internal.  
      
    Please refer to <https://docs.gradle.org/7.5/userguide/validation_problems.html#missing_annotation> for more details about this problem.  
  - In plugin 'dilutions' type 'com.meetyou.dilutions.pluginkt.DilutionModifyClassesTask' property 'MUIMetas' is missing an input or output annotation.  
      
    Reason: A property without annotation isn't considered during up-to-date checking.  
      
    Possible solutions:  
      1. Add an input or output annotation.  
      2. Mark it as @Internal.  
      
    Please refer to <https://docs.gradle.org/7.5/userguide/validation_problems.html#missing_annotation> for more details about this problem.

* Try:  
> Run with --stacktrace option to g


* What went wrong:  
Execution failed for task ':app:debugDilutionModifyClasses'.  
> Cannot convert the provided notation to a File or URI: {}.  
  The following types/formats are supported:  
    - A String or CharSequence path, for example 'src/main/java' or '/usr/include'.  
    - A String or CharSequence URI, for example '[file:/usr/include](http://file/usr/include)'.  
    - A File instance.  
    - A Path instance.  
    - A Directory instance.  
    - A RegularFile instance.  
    - A URI or URL instance.  
    - A TextResource instance.
 

解决办法,将报错的变量都改为私有的,如下:

abstract class DilutionModifyClassesTask : DefaultTask() {

    @get:InputFiles
    abstract val allJars: ListProperty<RegularFile>

    @get:InputFiles
    abstract val allDirectories: ListProperty<Directory>

    @get:OutputFile
    abstract val output: RegularFileProperty

    //Method metas
    private var mMetas = HashMap<String, ArrayList<String>>()

    //UI metas
    private var mUIMetas = HashMap<String, ArrayList<String>>()

    private var dilutionConfig: DilutionConfig? = null

   ...
}  

2.2 继续编译插件报错:

==>[file.name](http://file.name/)  MainActivity.class

FAILURE: Build failed with an exception.

* What went wrong:  
Execution failed for task ':app:debugDilutionModifyClasses'.  
> class java.util.ArrayList cannot be cast to class java.lang.String (java.util.ArrayList and java.lang.String are in module java.base of loader 'bootstrap')

* Try:  
> Run with --stacktrace option to get the stack trace.

  

解决办法:

var protocol_name: String = cv.mActivityProtocolNode.values[1] as String

改为:

var protocol_name = cv.mActivityProtocolNode.values.get(1).toString()

2.3 继续编译,成功,但启动闪退:

  Process: com.meetyou.demo.dilutions, PID: 29138
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.meetyou.demo.dilutions/com.meetyou.demo.dilutions.MainActivity}: java.lang.ClassNotFoundException: Didn't find class "com.meetyou.demo.dilutions.MainActivity" on path: DexPathList[[zip file "/data/app/~~n-cXW_WoBQ3cdfBhdXLh8g==/com.meetyou.demo.dilutions-sGc7K3AANsDQCNn6QWJpJw==/base.apk"],nativeLibraryDirectories=[/data/app/~~n-cXW_WoBQ3cdfBhdXLh8g==/com.meetyou.demo.dilutions-sGc7K3AANsDQCNn6QWJpJw==/lib/arm64, /system/lib64, /system/system_ext/lib64, /hw_product/lib64, /system/lib64/module/multimedia]]
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4666)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4983)
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:123)
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:3059)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:117)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:205)
                                                                                                        at android.os.Looper.loop(Looper.java:293)
                                                                                                        at android.app.ActivityThread.loopProcess(ActivityThread.java:9934)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:9923)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:586)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1240)
                                                                                                    Caused by: java.lang.ClassNotFoundException: Didn't find class "com.meetyou.demo.dilutions.MainActivity" on path: DexPathList[[zip file "/data/app/~~n-cXW_WoBQ3cdfBhdXLh8g==/com.meetyou.demo.dilutions-sGc7K3AANsDQCNn6QWJpJw==/base.apk"],nativeLibraryDirectories=[/data/app/~~n-cXW_WoBQ3cdfBhdXLh8g==/com.meetyou.demo.dilutions-sGc7K3AANsDQCNn6QWJpJw==/lib/arm64, /system/lib64, /system/system_ext/lib64, /hw_product/lib64, /system/lib64/module/multimedia]]
                                                                                                        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:218)
                                                                                                        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
                                                                                                        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
                                                                                                        at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
                                                                                                        at android.app.Instrumentation.newActivity(Instrumentation.java:1288)
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4650)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4983) 
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:123) 
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149) 
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103) 
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:3059) 
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:117) 
                                                                                                        at android.os.Looper.loopOnce(Looper.java:205) 
                                                                                                        at android.os.Looper.loop(Looper.java:293) 
                                                                                                        at android.app.ActivityThread.loopProcess(ActivityThread.java:9934) 
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:9923) 
                                                                                                        at java.lang.reflect.Method.invoke(Native Method) 
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:586) 
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1240) 
                                                                                                        Suppressed: java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/appcompat/app/AppCompatActivity;
                                                                                                            at java.lang.VMClassLoader.findLoadedClass(Native Method)
                                                                                                            at java.lang.ClassLoader.findLoadedClass(ClassLoader.java:738)
                                                                                                            at java.lang.ClassLoader.loadClass(ClassLoader.java:363)
                                                                                                            ... 17 more
                                                                                                        Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.appcompat.app.AppCompatActivity" on path: DexPathList[[zip file "/data/app/~~n-cXW_WoBQ3cdfBhdXLh8g==/com.meetyou.demo.dilutions-sGc7K3AANsDQCNn6QWJpJw==/base.apk"],nativeLibraryDirectories=[/data/app/~~n-cXW_WoBQ3cdfBhdXLh8g==/com.meetyou.demo.dilutions-sGc7K3AANsDQCNn6QWJpJw==/lib/arm64, /system/lib64, /system/system_ext/lib64, /hw_product/lib64, /system/lib64/module/multimedia]]
                                                                                                            at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:218)
                                                                                                            at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
                                                                                                            at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
                                                                                                            ... 20 more
         I  RenderThread: progress

解决办法是:

看了下插件代码是没把jar的class写入到输出里,因此加入如下代码:

allJars.get().forEach { file ->
    val jarFile = JarFile(file.asFile)
    jarFile.entries().iterator().forEach { jarEntry ->
      
        kotlin.runCatching {
            // 有重复的 META/INF 路径 就不管了
            jarOutput.putNextEntry(JarEntry(jarEntry.name))
            jarFile.getInputStream(jarEntry).use {
                it.copyTo(jarOutput)
            }
        }.let {
            if (it.isFailure) {
                logger.error("ModifyClassesTask copy file failed")
                logger.error("${it.exceptionOrNull()}")
            }
        }
        jarOutput.closeEntry()
    }
    jarFile.close()
}

重新编译插件后,可以应用成功。

2.4 完成插件Task代码如下:

package com.meetyou.dilutions.pluginkt

import com.meetyou.dilutions.BlackhandClassVisitor import com.meetyou.dilutions.DilutionConfig import com.meetyou.dilutions.DilutionsMetasWriter import org.gradle.api.DefaultTask import org.gradle.api.file.Directory import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.ListProperty import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Internal import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassWriter import org.objectweb.asm.Opcodes import java.io.BufferedOutputStream import java.io.File import java.io.FileOutputStream import java.io.InputStream import java.util.jar.JarEntry import java.util.jar.JarFile import java.util.jar.JarOutputStream import java.util.zip.ZipEntry

abstract class DilutionModifyClassesTask : DefaultTask() {

@get:InputFiles
abstract val allJars: ListProperty<RegularFile>

@get:InputFiles
abstract val allDirectories: ListProperty<Directory>

@get:OutputFile
abstract val output: RegularFileProperty

//Method metas
private var mMetas = HashMap<String, ArrayList<String>>()

//UI metas
private var mUIMetas = HashMap<String, ArrayList<String>>()

private var dilutionConfig: DilutionConfig? = null



open fun setDilutionoConfig(dilutionConfig: DilutionConfig?) {
    this.dilutionConfig = dilutionConfig
    println("===>setDilutionoConfig内容:${dilutionConfig.toString()}")
}


@TaskAction
open fun taskAction() {
    println("==>dilution DilutionModifyClassesTask do taskAction")
    val jarOutput = JarOutputStream(
        BufferedOutputStream(
            FileOutputStream(
                output.get().asFile,
            ),
        ),
    )
    println("==>dilution DilutionModifyClassesTask do taskAction allJars")
    println("===>setDilutionoConfig内容:${dilutionConfig.toString()}")
    // 这一步只查找 不做任何写入
    allJars.get().forEach { file ->
        val jarFile = JarFile(file.asFile)
        // 遍历jar包里的文件 找到想要判定的class文件
        jarFile.entries().iterator().forEach { jarEntry ->
            if (jarEntry.name.endsWith(".class")) {
                if(dilutionConfig!=null
                    && (dilutionConfig!!.isExcludeJar(jarEntry.name))){
                    println("==>jarEntry.name 被排除 ${jarEntry.name}")
                }else{
                    println("==>jarEntry.name  ${jarEntry.name}")
                    val inputStream = jarFile.getInputStream(jarEntry)
                    scanClassForGatherClass(inputStream)
                    inputStream.close()
                }
            }
        }
        jarFile.close()
    }
    println("==>dilution DilutionModifyClassesTask do taskAction allDirectories")
    // 这一步 除了要查找当前app-module的代码是否有关键信息以外
    // 还要负责把当前的类 拷贝到 最终task的输出中
    allDirectories.get().forEach { directory ->
        println("====>>handling allDirectories " + directory.asFile.absolutePath)
        directory.asFile.walk().forEach { file ->
            println("====>>handling directory.asFile " + file.absolutePath)
            if (file.isFile) {
                // 只扫描class文件
                if (file.name.endsWith(".class") && file.isDirectory.not()) {
                    if(dilutionConfig!=null && dilutionConfig!!.isExcludeJar(file.name)){
                        println("==>file.name 被排除 ${file.name}")
                    }else{
                        println("==>file.name  ${file.name}")
                        scanClassForGatherClass(file.inputStream())
                    }
                }
                val relativePath = directory.asFile.toURI().relativize(file.toURI()).path
                // 写入到jaroutput中
                jarOutput.putNextEntry(JarEntry(relativePath.replace(File.separatorChar, '/')))
                file.inputStream().use { inputStream ->
                    inputStream.copyTo(jarOutput)
                }
                jarOutput.closeEntry()
            }
        }
    }
    println("==>dilution DilutionModifyClassesTask do taskAction allJars Input")
    allJars.get().forEach { file ->
        val jarFile = JarFile(file.asFile)
        jarFile.entries().iterator().forEach { jarEntry ->
           /* if (jarEntry.name == "com/alibaba/android/arouter/core/LogisticsCenter.class") {
                val inputStream = jarFile.getInputStream(jarEntry)
                val cr = ClassReader(inputStream)
                val cw = ClassWriter(cr, 0)
                val cv = ModifyClassVisitor(Opcodes.ASM5, cw)
                cr.accept(cv, ClassReader.EXPAND_FRAMES)
                val byte = cw.toByteArray()
                jarOutput.putNextEntry(JarEntry(jarEntry.name))
                jarOutput.write(byte)
                inputStream.close()
                return@forEach
            }*/
            kotlin.runCatching {
                // 有重复的 META/INF 路径 就不管了
                jarOutput.putNextEntry(JarEntry(jarEntry.name))
                jarFile.getInputStream(jarEntry).use {
                    it.copyTo(jarOutput)
                }
            }.let {
                if (it.isFailure) {
                    logger.error("ModifyClassesTask copy file failed")
                    logger.error("${it.exceptionOrNull()}")
                }
            }
            jarOutput.closeEntry()
        }
        jarFile.close()
    }

    println("==>dilution DilutionModifyClassesTask start writeDilutionClass")
    writeDilutionClass(jarOutput)
    jarOutput.close()
    println("==>dilution DilutionModifyClassesTask taskAction end !!")
}

private  fun writeDilutionClass(jarOutputStream: JarOutputStream){
    val metasWriter = DilutionsMetasWriter()

    var addEntry: ZipEntry? = null

    addEntry = ZipEntry("com/meetyou/dilutions/inject/support/DilutionsInjectMetas.class")
    jarOutputStream.putNextEntry(addEntry)
    jarOutputStream.write(
        metasWriter.makeMetas(
            "com/meetyou/dilutions/inject/support/DilutionsInjectMetas",
            mMetas
        )
    )
    jarOutputStream.closeEntry()

    addEntry = ZipEntry("com/meetyou/dilutions/inject/support/DilutionsInjectUIMetas.class")
    jarOutputStream.putNextEntry(addEntry)
    jarOutputStream.write(
        metasWriter.makeMetas(
            "com/meetyou/dilutions/inject/support/DilutionsInjectUIMetas",
            mUIMetas
        )
    )
    jarOutputStream.closeEntry()
}
private  fun scanClassForGatherClass(inputStream: InputStream) {
    val cr = ClassReader(inputStream)
    val cw = ClassWriter(cr, ClassWriter.COMPUTE_MAXS)
    val cv = BlackhandClassVisitor(Opcodes.ASM7, cw)
    cr.accept(cv, ClassReader.EXPAND_FRAMES)
    processMetas(cv)
}

private fun processMetas(cv: BlackhandClassVisitor) {
    if (cv.mActivityProtocolNode != null) {
        //UI跳转
        if (cv.mActivityProtocolNode.values != null && cv.mActivityProtocolNode.values.size > 1) {
            println("====>as String1 ")
            var protocol_name = cv.mActivityProtocolNode.values.get(1).toString()
            //var protocol_name: String = cv.mActivityProtocolNode.values[1] as String
            println("====>as String1 end")
            protocol_name = protocol_name.substring(1, protocol_name.length - 1)
            if (!protocol_name.isEmpty()) {
                //动画添加
                var enterAnim = "0"
                var exitAnim = "0"
                if (cv.mAnimActivityProtocolNode != null && cv.mAnimActivityProtocolNode.values != null && cv.mAnimActivityProtocolNode.values.size > 1) {
                    try {
                        //进入动画设置
                        println("====>as String2 ")
                        enterAnim = cv.mAnimActivityProtocolNode.values.get(1).toString()
                        println("====>as String2 end")
                    } catch (e: Exception) {
                    }
                    try {
                        //进入动画设置
                        println("====>as String3")
                        exitAnim = cv.mAnimActivityProtocolNode.values.get(3).toString()
                        println("====>as String3 end")
                    } catch (e: Exception) {
                    }
                    println ("找到针对" + protocol_name + "的UI动画Enter:" + enterAnim + ",exit:" + exitAnim)
                }
                println("====>as String3 ")
                val protocols =
                    protocol_name.split(",".toRegex()).dropLastWhile { it.isEmpty() }
                        .toTypedArray()
                println("====>as String3 end")
                for (s in protocols) {
                    val strings = java.util.ArrayList<String>()
                    //添加对应的跳转类index=0
                    strings.add(cv.mClazzName)
                    //添加对应的enter动画index=1
                    strings.add(enterAnim)
                    //添加对应的exit动画index = 2
                    strings.add(exitAnim)
                    //将序列放入metas
                    mUIMetas[s.trim { it <= ' ' }] = strings
                }
            }
            println ("找到UI协议:$protocol_name")
        }
        //            mUIMetas.put()
    }
    if (cv.mProtocols != null) {
        //类名
        val clazz = cv.mClazzName
        println(" ==>clazz:${clazz}")
        for (entry in cv.mProtocols){
            var key = entry.key
            var value = entry.value
            //协议
            var protocol_name = ""
            if (key.values != null && key.values.size > 1) {
                println("====>as String4")
                protocol_name = key.values.get(1).toString()
                println("====>as String4 end")
                println("找到协议:$protocol_name")
            } else {
                println ("没有找到协议,这有问题!")
                continue
            }
            val strings = java.util.ArrayList<String>()
            strings.add(clazz)
            //方法名
            val medhodname = value.methodName
            println("==>methodName:${medhodname}")
            strings.add(medhodname)
            //方法参数类型
            val javaMethodParams = value.javaMethodParams
            println("==>javaMethodParams:${javaMethodParams}")
            strings.add(javaMethodParams)
            //参数以及其index
            for (info in value.mMethodAnnotations) {
                strings.add(info.index.toString() + "=" + info.paramName)
                println("==>getIndex:${info.index}-> paramName:${info.paramName}")
            }
            mMetas[protocol_name] = strings
        }
    }
}

}