Flutter 3.44 插件内置 Kotlin (KGP) 双向兼容适配指南

欢迎关注微信公众号:FSA全栈行动 👋

一、简述

最近升级到 Flutter 3.44.x 及以上版本的朋友,想必在编译项目时都被控制台这行显眼的警告刷过屏:

WARNING: Your app uses the following plugins that apply Kotlin Gradle Plugin (KGP)...

Future versions of Flutter will fail to build if your app uses plugins that apply KGP.

万恶的 KGP(Kotlin Gradle Plugin)要被"抛弃"了!

原来,从 Android Gradle Plugin (AGP) 9.0 开始,对 Kotlin 的支持被彻底收归"内置"(Built-in Kotlin)。任何在插件中单方面显式声明的 apply plugin: 'kotlin-android',在未来的 Flutter 编译环境中都会直接导致构建崩溃。

官方指引(Built-in Kotlin migration for plugin authors)中给的路线非常直接:只要把插件的最低 Flutter 版本限制一刀切升到 3.44,然后删掉 apply plugin: 'kotlin-android',收工!

但是,在实际开源组件的维护中,如果我们作为维护者强行把最低版本拔高到 Flutter 3.44,这就相当于与那些还在坚守 Flutter 3.x 早期版本(甚至 Flutter 3.0)的用户们"割袍断义"了!所以,本篇指南就带各位朋友搞一套新旧 Flutter 双向兼容的适配秘籍

二、新旧版本对比

在开整之前,我们先用一张表直观对比一下新旧两种编译环境下的机制差异。知己知彼,才好"对症下药":

维度 旧版 Flutter 构建体系 (< 3.44) 新版 Flutter 构建体系 (>= 3.44 / AGP 9+)
Kotlin 加载机制 依赖插件通过 kotlin-android 显式激活 由 AGP 9.0+ 内置处理,插件手动 apply 会与内置逻辑产生冲突
Kotlin 插件配置 必须在 buildscript.dependencies 中引入 KGP 依赖 移交至主 App 项目或由 Flutter 构建链管理,子插件中无需重复声明
JVM Target 设置 必须在 android 内部通过 kotlinOptions {} 指定 引入了外层的 kotlin { compilerOptions {} } 新型 DSL

三、动态兼容方案

这里以我们维护的 chat_bottom_container 插件为例,为了让插件在旧版 Flutter (AGP < 9.0) 环境下能正常编译,而在新版 Built-in Kotlin (AGP >= 9.0) 下又不会因 KGP 冲突报错,我们需要在 chat_bottom_container/android/build.gradle 中采取"动态嗅探"策略。

1、动态应用 kotlin-android 插件

我们通过解析 AGP 实际的版本号以及检查宿主工程是否开启了内置 Kotlin,来决定是否手动 apply 插件:

groovy 复制代码
// 1. 获取当前编译环境中 Android Gradle 插件的主版本号
def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize(".")[0] as int

// 2. 判断当前内置 Kotlin 是否生效(要求 AGP 版本 >= 9 且未被显式禁用)
def builtInKotlinActive = agpMajor >= 9 &&
    (!project.hasProperty("android.builtInKotlin") ||
        Boolean.parseBoolean(project.property("android.builtInKotlin").toString()))

// 3. 仅在内置 Kotlin 不生效的旧版构建环境下,才手动应用旧版 kotlin-android 插件
if (!builtInKotlinActive) {
    apply plugin: "kotlin-" + "android"
}
  1. 在 Gradle 配置阶段,从 com.android.Version 中获取当前的 AGP 主版本号(例如:8 或 9)。
  2. 结合 agpMajorandroid.builtInKotlin 属性,计算出 builtInKotlinActive 布尔值,用于判定当前内置 Kotlin 是否处于活动状态。
  3. 如果宿主工程依旧没有启用 Built-in Kotlin,我们就打上"补丁",通过动态拼接字符串的方式手动执行 apply plugin,在保持向后兼容的同时避免被 Flutter 误判。

Q:为什么不直接用 apply plugin: "kotlin-android"

A:这是为了避免由于 Flutter CLI 静态正则扫描机制的局限性导致的误报。

在构建应用时,Flutter 构建工具(flutter_tools)并不会去真正解析并执行 Groovy 的 if-else 条件分支,它只是简单粗暴地使用静态正则表达式(RegExp)扫描依赖插件的 build.gradle 文本。只要文件里出现了 apply plugin: "kotlin-android"id "org.jetbrains.kotlin.android" 的字面量,不管这段代码处于什么禁用分支内,都会被判定为"手动应用了 KGP",从而抛出警告。

2、动态配置 JVM 目标版本 (jvmTarget)

由于 Kotlin 插件版本的不同,设置 JVM 目标的 DSL 语法也有两套。如果直接写新语法,老项目在老版本 KGP 下编译会报错(找不到属性);写旧语法,在新环境编译时又会抛出过时或不支持的错误。

因此,我们需要采用如下动态属性嗅探法:

groovy 复制代码
// 1. 获取 project 中的 kotlin 扩展配置对象
def kotlinExt = project.extensions.findByName("kotlin")

// 2. 判断该扩展对象中是否支持 compilerOptions 属性
if (kotlinExt?.hasProperty("compilerOptions")) {
    kotlin {
        compilerOptions {
            jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8
        }
    }
} else {
    // 3. 降级使用传统的 kotlinOptions 配置方式,防止老版 Kotlin Gradle 插件报错
    android.kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }
}
  1. 通过 extensions.findByName("kotlin") 安全获取 Kotlin 扩展对象,防止因项目未引入 Kotlin 导致直接报空指针异常。
  2. 如果该扩展包含了新的 compilerOptions,说明当前处于新版 KGP (1.9+) 或内置 Kotlin 环境,此时直接使用新语法 compilerOptions 配置 JVM 目标。
  3. 若为老版本,则降级使用传统的 android.kotlinOptions { jvmTarget = '1.8' } 语法,以保障老项目顺利编译通过。

四、最后

通过以上这两处 Gradle 动态判定以及巧妙的字面量拼接,插件就可以在不做任何 Breaking Change 的前提下,平滑兼容新旧版本的 Flutter 和 Kotlin 编译环境。

对于使用者来说,直接引入修改后的插件即可,无需在主项目的 gradle.properties 中强行添加 android.builtInKotlin=false 这类治标不治本的规避配置。

希望本篇秘籍能帮各位朋友少踩几个编译坑,下期再会!

如果文章对您有所帮助, 请不吝点击关注一下我的微信公众号:FSA全栈行动, 这将是对我最大的激励. 公众号不仅有Android技术, 还有iOS, Python等文章, 可能有你想要了解的技能知识点哦~

相关推荐
随遇丿而安6 小时前
第11周:Activity 跳转与传值 + 跳转优化
android
私人珍藏库7 小时前
[Android] BBLL 开源第三方B哩电视TV端
android·app·生活·工具·多功能
杉氧9 小时前
跨平台资源管理:一套代码如何搞定 Android、iOS 和 Web 的图片与多语言?
android·架构·android jetpack
安卓修改大师10 小时前
安卓修改大师实战:从反编译到定制的完整APK修改指南
android
柚鸥ASO优化11 小时前
安卓APP推广的“降本增效”密码:守好商店内,打好商店外
android·aso优化
我是一颗柠檬12 小时前
【Java项目技术亮点】EXPLAIN深度分析与慢查询治理
android·java·开发语言
Android-Flutter12 小时前
android compose shadow 阴影 使用
android·kotlin·compose
帅次12 小时前
Android 高级工程师面试:Java 多线程与并发 近1年高频追问 22 题
android·java·面试
2501_9437823512 小时前
【共创季稿事节】摩斯电码转换器:编码表与双向转换的实现
android·华为·鸿蒙·鸿蒙系统