当老版本React Native遇到新版本Kotlin

180 阅读2分钟

遇到问题

最近开始在一个原有的Android项目中尝试引入React Native进行跨端开发,当按照官网文档的指引,修改好项目配置,信心满满的点下Sync后,却遭遇了当头一棒,一行红字映入了眼帘:Found interface org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension, but class was expected。

定位问题

这个报错的含义是 KotlinTopLevelExtension 在编译时是个class,但是在运行时实际获取到的变成了interface。打开这个类,发现它是Kotlin Gradle Plugin中的类,这个时候就想到是不是React Native Gradle Plugin里使用的Kotlin版本和主项目不一致,而KotlinTopLevelExtension这个类在这两个版本出现了类型变化。

经过确认,主项目用的Kotlin版本为2.1.21,KotlinTopLevelExtension这个类的申明如下:

interface KotlinTopLevelExtension : KotlinTopLevelExtensionConfig, KotlinSourceSetContainer

而React Native Gradle Plugin里用的Kotlin版本为1.9.25,KotlinTopLevelExtension这个类的申明如下:

abstract class KotlinTopLevelExtension(internal val project: Project) : KotlinTopLevelExtensionConfig

这下就验证了之前的猜想。

解决问题

问题的原因清楚了,下一步就是确认解决方案。可选的方向有两个:一个是将主项目的Kotlin版本降低,另一个就是将React Native Gradle Plugin里的Kotlin版本升高。

降低主项目的Kotlin版本并不是一个好选择,即使现在项目中没有用到新版本的特性,后续想使用时依旧需要重新解决这个问题。

所以最佳选择就是升级React Native Gradle Plugin里的Kotlin版本。将React Native Gradle Plugin里的Kotlin版本升级到和主项目一致后,顺利跑起了项目。

不过这个改动的文件是在 node_modules 中,而node_modules是被git忽略的,所以我本地修改后,其他人拉取项目后依然后遇到同样的问题。

经过调研,发现可以通过 patch-package 这个npm包来实现给npm依赖打补丁的功能。生成补丁并提交,这样就能一劳永逸的解决该问题了。

相关代码可以查看Github上Demo项目的kotlin-version分支