记录一次 Flutter 升级遇到的问题

86 阅读3分钟

一、问题现象

最近将 Flutter SDK 从 3.29.x 升级到 3.38.10 版本
升级后发现:

📦 APK 打包体积变大了约 1.5 倍

随后定位到问题原因如下。


二、前提说明

升级前后以下配置均未发生变化:

  • Gradle 版本:8.14.2
  • AGP 版本:8.11.0(配置于 settings.gradle.kts
  • Flutter Gradle Plugin 版本:1.0.0(配置于 settings.gradle.kts
  • 打包命令:flutter build apk
  • build.gradle.kts 相关配置未变

原始 build.gradle.kts 配置

// 原 build.gradle.kts 部分配置如下

buildTypes {
  getByName("release") {
    ndk {
      abiFilters.addAll(listOf("arm64-v8a"))
    }
  }
}

原先通过修改 Gradle 配置,仅保留 arm64-v8a ABI,因此:

flutter build apk 只会生成 arm64-v8a 的 APK


升级后的异常现象

升级到 3.38.10 后,在其他配置未变的情况下:

  • x86_64
  • armeabi-v7a

也被打包进 APK。

随后开始排查原因。


修复方式

修改 build.gradle.kts

// 新 build.gradle.kts 部分配置如下

buildTypes {
  getByName("release") {
    ndk {
      abiFilters.clear()
      abiFilters.addAll(listOf("arm64-v8a"))
    }
  }
}

重新打包后恢复正常,仅包含 arm64-v8a


三、问题原因分析

通过 GPT 了解到:

Flutter 3.35+ 之后,Flutter SDK 内部的 Flutter Gradle Plugin 实现发生变化,默认构建所有支持的 ABI。

3.35 相关PR GitHub链接


官方默认 ABI

FlutterPluginConstants.kt 中可以看到:

@JvmStatic val DEFAULT_PLATFORMS =
  listOf(
    PLATFORM_ARM32,
    PLATFORM_ARM64,
    PLATFORM_X86_64
  )

对应架构映射:

@JvmStatic val PLATFORM_ARCH_MAP =
  mapOf(
    PLATFORM_ARM32 to "armeabi-v7a",
    PLATFORM_ARM64 to "arm64-v8a",
    PLATFORM_X86_64 to "x86_64"
  )

也就是说默认会构建:

  • armeabi-v7a
  • arm64-v8a
  • x86_64

四、插件内部逻辑

核心代码位于:

<flutter sdk>\packages\flutter_tools\gradle\src\main\kotlin

FlutterPlugin.kt 关键代码

FlutterPluginUtils.getAndroidExtension(project).buildTypes.forEach { buildType ->
  buildType.ndk.abiFilters.clear()
  FlutterPluginConstants.DEFAULT_PLATFORMS.forEach { platform ->
    val abiValue: String =
      FlutterPluginConstants.PLATFORM_ARCH_MAP[platform]
          ?: throw GradleException("Invalid platform: $platform")
    buildType.ndk.abiFilters.add(abiValue)
  }
}

关键点:

插件会对 abiFilters 先执行 clear(),然后写入默认 ABI。


五、关于官方注释的理解

源码中有一句:

If the user has specified abiFilters in their build.gradle file, those settings will take precedence over these defaults.

翻译:

如果用户在 build.gradle 中指定了 abiFilters,则用户配置优先。

但从实际构建结果来看,并未覆盖默认值。


实际原因:Gradle 生命周期 + 执行顺序

执行顺序如下:

  1. Flutter 插件执行

    • abiFilters.clear()
    • 写入默认 ABI
  2. 然后执行 build.gradle.kts 中的:

abiFilters.addAll(listOf("arm64-v8a"))

由于只是 addAll(),而不是 clear() 再添加,因此:

最终结果 = 默认 ABI + 配置的 ABI


更准确的理解

这句官方注释的真实含义应该是:

如果用户的配置能够在插件逻辑之后覆盖默认值(例如先 clear()addAll()),那么用户配置才会真正生效。


六、关于 Flutter Gradle Plugin 版本的疑问

虽然在 settings.gradle.kts 中声明:

Flutter Gradle Plugin 1.0.0

但:

这个版本号并不代表实际插件实现版本。

真正的实现逻辑:

  • 位于 Flutter SDK 内部
  • 随 Flutter SDK 升级而变化

七、为什么 Flutter 做这个调整?

可能原因包括:

  1. Play Store 强制 64 位支持
  2. 模拟器大量使用 x86_64
  3. CI 构建一致性
  4. 与 App Bundle 行为统一

八、后续方案选择

方式一:通过 abiFilters 控制

缺点:

  • Flutter 插件未来可能继续调整
  • Gradle 层和 Flutter 层逻辑可能冲突

方式二:推荐方式

flutter build apk --split-per-abi

优点:

  • 官方推荐方式
  • 构建逻辑清晰
  • 不依赖 Gradle hack

缺点:

  • 会生成多个 APK
  • 构建时间增加

方式三:更适合我的方案

由于目标平台非常明确,仅支持 arm64-v8a

flutter build apk --target-platform android-arm64

优点:

  • 只构建指定 ABI
  • 构建时间最短
  • 不依赖 Gradle 层配置
  • 不受 Flutter 插件实现影响

总结

本次问题本质是:

Flutter 3.35+ 修改了内部 Gradle 插件逻辑,默认构建所有 ABI,并在插件执行阶段重写 abiFilters

关键认知:

  • settings.gradle.kts 中声明的插件版本 ≠ 实际实现版本
  • addAll() 不会覆盖默认 ABI
  • 必须 clear() 后再添加
  • 更推荐使用 --target-platform--split-per-abi