请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

无法生成 NavigationRegistry文件

代码:
class NavigationTransform(private val target: Project) : Transform() {
private val navigationDataList = mutableListOf()

companion object {
    const val NAV_RUNTIME_DESTINATION =
        "Lcom/ukm/stroke/guard/ai/navigation/plugin/runtime/NavigationDestination;"
    const val NAV_RUNTIME_NAV_TYPE =
        "Lcom/ukm/stroke/guard/ai/navigation/plugin/runtime/NavigationDestination\$NavigationType"

    private const val KEY_ROUTE = "route"
    private const val KEY_TYPE = "type"
    private const val KEY_STARTER = "asStarter"

    private const val NAV_RUNTIME_PKG_NAME: String = "com.ukm.stroke.guard.ai.navigation.plugin.runtime"
    private const val NAV_RUNTIME_REGISTRY_CLASS_NAME: String = "NavigationRegistry"
    private const val NAV_RUNTIME_NAV_DATA_CLASS_NAME: String = "NavigationData"
    private const val NAV_RUNTIME_NAV_LIST: String = "navigationList"
    private const val NAV_RUNTIME_MODULE_NAME: String = "navigation-plugin-runtime"
}

override fun getName(): String {
    println(" ||--NavigationTransform get name...")
    return "NavigationTransform"
}

override fun getInputTypes(): MutableSet<QualifiedContent.ContentType> {
    println(" ||--NavigationTransform get input types...")
    return TransformManager.CONTENT_CLASS
}

override fun getScopes(): MutableSet<in QualifiedContent.Scope> {
    println(" ||--NavigationTransform get scopes...")
    return TransformManager.SCOPE_FULL_PROJECT
}

override fun isIncremental(): Boolean {
    println(" ||--NavigationTransform is incremental...")
    return false
}

override fun transform(transformInvocation: TransformInvocation?) {
    println(" ||--NavigationTransform transform...")
    super.transform(transformInvocation)
    val inputs = transformInvocation?.inputs ?: return
    val outputProvider = transformInvocation.outputProvider
    outputProvider.deleteAll()
    inputs.forEach {
        // 1. 对 inputs -> directory -> class 文件进行遍历
        // 2 .对 inputs -> jar -> class 文件进行遍历
        it.directoryInputs.forEach { it ->
            handleDirectoryClasses(it.file)
            val outputDir = outputProvider.getContentLocation(
                it.name,
                it.contentTypes,
                it.scopes,
                Format.DIRECTORY
            )
            if (it.file.isFile) {
                FileUtils.copyFile(it.file, outputDir)
            } else {
                FileUtils.copyDirectory(it.file, outputDir)
            }
        }
        generateNavigationRegistry()
    }
}

private fun generateNavigationRegistry() {
    println(" ||--NavigationTransform generate navigation registry...")
    // 利用 kotlinPoet 生成 NavigationRegistry.kt 文件,存放在 nav-plugin-runtime 模块下;
    // 用于记录项目中所有的路由节点数据

    //1. 生成成员变量 val navList:ArrayList<NavData>
    val navData = ClassName(NAV_RUNTIME_PKG_NAME, NAV_RUNTIME_NAV_DATA_CLASS_NAME)
    val arrayList = ClassName("kotlin.collections", "ArrayList")

    //2.生成 get 方法返回值类型 List<NavData>
    val list = ClassName("kotlin.collections", "List")
    val arrayListOfNavData = arrayList.parameterizedBy(navData)
    val listOfNavData = list.parameterizedBy(navData)

    //3. 生成 object Class init{ 代码块 }
    val statements = java.lang.StringBuilder()
    navigationDataList.forEach {
        statements.append(
            String.format(
                "navList.add(NavigationData(\"%s\",\"%s\",%s))",
                it.route,
                it.className,
                it.type
            )
        )
        statements.append("\n")
    }

    // 4. 向 object class 添加成员属性 navList 并且进行初始化赋值
    val property =
        PropertySpec.builder(NAV_RUNTIME_NAV_LIST, arrayListOfNavData, KModifier.PRIVATE)
            .initializer(CodeBlock.builder().addStatement("ArrayList<NavData>()").build())
            .build()

    // 5.构建 get 方法 并且生成代码块
    val function = FunSpec.builder("get").returns(listOfNavData).addCode(
        CodeBlock.builder()
            .addStatement("val list = ArrayList<NavData>()\n list.addAll(navList)\n return list\n")
            .build()
    ).build()

    // 6. 构建 object NavRegistry class. 并且填充属性、int{}  get 方法
    val typeSpec = TypeSpec.objectBuilder(NAV_RUNTIME_REGISTRY_CLASS_NAME)
        .addProperty(property)
        .addInitializerBlock(CodeBlock.builder().addStatement(statements.toString()).build())
        .addFunction(function)
        .build()

    // 7. 生成文件、添加注释和导包
    val fileSpec = FileSpec.builder(NAV_RUNTIME_PKG_NAME, NAV_RUNTIME_REGISTRY_CLASS_NAME)
        .addComment("this file is generated by auto,please do not modify!!!")
        .addType(typeSpec)
        .addImport(NavigationDestination.NavigationType::class.java, "Fragment", "Dialog", "Activity", "None")
        .build()

    // 8. 写入文件
    val runtimeProject = target.rootProject.findProject(NAV_RUNTIME_MODULE_NAME)
    assert(runtimeProject == null) {
        throw GradleException("cant found $NAV_RUNTIME_MODULE_NAME")
    }
    val sourceSet = runtimeProject!!.extensions.findByName("sourceSets") as SourceSetContainer
    val outputFileDir = sourceSet.first().java.srcDirs.first().absoluteFile
    println("NavTransform outputFileDir:${outputFileDir.absolutePath}")
    fileSpec.writeTo(outputFileDir)
}

private fun handleDirectoryClasses(file: File) {
    println(" ||--NavigationTransform handle directory classes...")
    if (file.isDirectory) {
        file.listFiles()?.forEach {
            handleDirectoryClasses(it)
        }
    } else if (file.extension.endsWith("class")) {
        val inputStream = FileInputStream(file)
        println("NavigationTransform handleDirectoryClasses-zipEntry:${file.name}")
        visitClass(inputStream)
        inputStream.close()
    }
}

private fun handleJarClasses(file: File) {
    println(" ||--NavigationTransform handle jar classes...")
    var zipFile = ZipFile(file)
    zipFile.stream().forEach {
        if (it.name.endsWith("class")) {
            println("NavTransform handleJarClasses-zipEntry:${it.name}")
            val inputStream = zipFile.getInputStream(it)
            visitClass(inputStream)
            inputStream.close()
        }
    }
    zipFile.close()
}

private fun visitClass(inputStream: InputStream) {
    var classReader = ClassReader(inputStream)
    var classVisitor = object : ClassVisitor(Opcodes.ASM9) {
        override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor {
            // return super.visitAnnotation(descriptor, visible)

            if (descriptor != NAV_RUNTIME_DESTINATION) {
                return object : AnnotationVisitor(Opcodes.ASM9) {}
            }

            val annotationVisitor = object : AnnotationNode(Opcodes.ASM9, "") {
                var route = ""
                var asStarter = false
                var type = NavigationDestination.NavigationType.None
                override fun visit(name: String?, value: Any?) {
                    super.visit(name, value)
                    if (name == KEY_ROUTE) {
                        route = value as String
                    } else if (name == KEY_STARTER) {
                        asStarter = value as Boolean
                    }
                }

                override fun visitEnum(name: String?, descriptor: String?, value: String?) {
                    super.visitEnum(name, descriptor, value)
                    if (name == KEY_TYPE) {
                        assert(value == null) {
                            throw GradleException("NavigationDestination\$type must be one of Fragment,Activity,Dialog")
                        }
                        type = NavigationDestination.NavigationType.valueOf(value!!)
                    }
                }

                override fun visitEnd() {
                    super.visitEnd()
                    val navData = NavigationData(route, classReader.className.replace("/", "."), type)
                    navigationDataList.add(navData)
                }
            }

            return annotationVisitor
        }
    }
    classReader.accept(classVisitor, EXPAND_FRAMES)
}

}

构建日志:

Configure project :app
||–NavigationPlugin apply…
||–NavigationPlugin Register transform ‘NavigationTransform’…

Task :navigation-plugin:generatePomFileForNavigationPluginPluginMarkerMavenPublication
Task :navigation-plugin:publishNavigationPluginPluginMarkerMavenPublicationToMavenLocal
Task :navigation-plugin:pluginDescriptors UP-TO-DATE
Task :navigation-plugin:processResources UP-TO-DATE
Task :navigation-plugin:sourcesJar UP-TO-DATE
Task :navigation-plugin:generatePomFileForPluginMavenPublication

Task :navigation-plugin:compileKotlin
w: file:///F:/Projects/Master/StrokeGuard-AI-App/navigation-plugin/src/main/java/com/ukm/stroke/guard/ai/navigation/plugin/NavigationPlugin.kt:20:27 ‘registerTransform(Transform, vararg Any): Unit’ is deprecated. The transform API is planned to be removed in Android Gradle plugin 8.0.
w: file:///F:/Projects/Master/StrokeGuard-AI-App/navigation-plugin/src/main/java/com/ukm/stroke/guard/ai/navigation/plugin/NavigationTransform.kt:78:42 Name shadowed: it

Task :navigation-plugin:compileJava NO-SOURCE
Task :navigation-plugin:classes UP-TO-DATE
Task :navigation-plugin:jar UP-TO-DATE
Task :navigation-plugin:javadoc NO-SOURCE
Task :navigation-plugin:javadocJar UP-TO-DATE
Task :navigation-plugin:generateMetadataFileForPluginMavenPublication
Task :navigation-plugin:publishPluginMavenPublicationToMavenLocal
Task :navigation-plugin:publishToMavenLocal

BUILD SUCCESSFUL in 6s
11 actionable tasks: 6 executed, 5 up-to-date

Build Analyzer results available

正在回答 回答被采纳积分+3

1回答

LovelyChubby 2023-10-20 13:16:36
你这个是执行的什么任务呢?要执行打包安装才会编译时生成
0 回复 有任何疑惑可以回复我~
  • 提问者 智能麻花 #1
    我已经执行过 publishToMavenLocal,且已经将插件打包到 .m2 目录下。但是再次执行 Build 无法生成 NavigationRegistry文件。看日志的话应该是代码没进入 class NavigationTransform。
    回复 有任何疑惑可以回复我~ 2023-11-16 21:32:47
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信