Android
1 - Flutter Android 构建的版本地狱:为什么改一个版本要改一堆?
前言
如果你在构建 Flutter Android 应用时遇到过这样的错误:
Could not resolve all files for configuration ':surface:androidJdkImage'.
Error while executing process jlink with arguments...
然后按照提示升级了 AGP(Android Gradle Plugin),结果又报错说找不到仓库,再加上仓库后又说 Gradle 版本不对,再升级 Gradle 后又说 Kotlin 版本太旧…
恭喜你,欢迎来到 Flutter Android 构建的版本地狱 🔥
本文将深入解析这背后的原因,以及如何优雅地解决这类问题。
一、问题的本质:多层依赖链
Flutter Android 项目的构建涉及一条复杂的依赖链:
Flutter (Google Flutter 团队)
↓
Android Gradle Plugin / AGP (Google Android 团队)
↓
Gradle (Gradle Inc.)
↓
Kotlin (JetBrains)
↓
Java/JDK (Oracle/OpenJDK)
关键问题:这些工具由不同的组织开发,各自独立发版,但又必须相互兼容。
典型的版本兼容矩阵
| AGP 版本 | 最低 Gradle 版本 | 推荐 Kotlin 版本 | 最低 Java 版本 |
|---|---|---|---|
| 7.4.0 | 7.5 | 1.8.0+ | 11 |
| 8.0.0 | 8.0 | 1.8.10+ | 17 |
| 8.1.0 | 8.0 | 1.8.22+ | 17 |
| 8.2.1 | 8.2 | 1.9.0+ | 17 |
| 8.3.0 | 8.4 | 1.9.20+ | 17 |
一旦某一层不兼容,整个构建就会失败。
二、真实案例分析
案例:Java 21 + AGP 8.1.0 的灾难
场景:
- 你的电脑升级到了 Java 21(可能是 Android Studio 自动更新的)
- 项目使用 AGP 8.1.0
- 尝试构建 Release 版本
错误信息:
Error while executing process jlink with arguments
{--module-path ... --add-modules java.base ...}
根本原因:
AGP 8.1.0 及以下版本在处理 Java 模块系统时有一个已知 bug(Issue 294137077),当遇到 Java 21 的新特性时会失败。
解决方案:
| |
但这只是开始…
连锁反应
升级 AGP 后,你会遇到:
问题 1:找不到依赖
Cannot resolve external dependency com.android.tools.build:gradle:8.2.1
because no repositories are defined.
原因:忘记配置仓库
解决:
| |
问题 2:Gradle 版本太旧
AGP 8.2.1 requires Gradle 8.2 or higher.
Current version is 7.6.
解决:升级 gradle-wrapper.properties
| |
问题 3:Kotlin 版本不兼容
This version of Gradle requires Kotlin Gradle plugin version 1.9.0 or higher.
解决:
| |
一个简单的构建错误,最终需要修改 4-5 个配置文件!
三、为什么会这么复杂?
1. 历史包袱
2008 年 - Android 发布
2012 年 - Gradle 成为 Android 官方构建工具
2017 年 - Kotlin 成为 Android 官方语言
2018 年 - Flutter 1.0 发布
2023 年 - Java 21 发布(LTS 版本)
每个工具都有 10+ 年的历史,必须保持向后兼容。
2. 独立团队的协调成本
- Google Flutter 团队:关注跨平台体验
- Google Android 团队:关注 Android 生态
- Gradle Inc.:构建工具公司,服务多个平台
- JetBrains:Kotlin 语言开发商
- Oracle/OpenJDK:Java 语言维护者
这些团队发版节奏不同,优先级也不同。
3. 构建工具的特殊性
Gradle 是个自举系统(bootstrap system):
问:用什么下载 Gradle?
答:用 Gradle Wrapper
问:Gradle Wrapper 从哪来?
答:从 Gradle 仓库下载
问:怎么配置仓库?
答:写在 Gradle 配置文件里
问:Gradle 还没下载,怎么读配置文件?
答:...这就是鸡生蛋蛋生鸡的问题
这导致版本协调必须在多个层次手动配置。
四、新版 vs 旧版项目结构
Flutter 在 3.16 版本引入了新的项目结构来简化配置。
旧版结构(Flutter 3.15 及以下)
android/build.gradle:
| |
android/settings.gradle:
| |
新版结构(Flutter 3.16+)
android/settings.gradle:
| |
android/build.gradle:
| |
新版结构的优势
- 集中管理插件版本:所有插件版本在
settings.gradle中 - 更清晰的职责分离:
settings.gradle:插件和仓库配置build.gradle:项目级配置app/build.gradle:应用级配置
- 符合 Gradle 最佳实践:使用
pluginManagement
五、如何判断项目结构版本
快速判断法
检查 android/settings.gradle:
新版结构:
| |
旧版结构:
| |
判断矩阵
| 特征 | 新版 | 旧版 |
|---|---|---|
settings.gradle 有 plugins 块 | ✅ | ❌ |
build.gradle 有 buildscript 块 | ❌ | ✅ |
包含 flutter-plugin-loader | ✅ | ❌ |
| Flutter 版本 | 3.16+ | 3.15- |
六、终极解决方案
方案 A:推荐的稳定版本组合(2024-2025)
| |
配置文件:
android/settings.gradle(新版结构):
| |
android/gradle/wrapper/gradle-wrapper.properties:
| |
android/app/build.gradle:
| |
方案 B:旧版结构迁移到新版
步骤:
- 备份项目
- 升级 Flutter:
flutter upgrade - 重新生成 Android 配置:
1 2 3 4cd android rm -rf build.gradle settings.gradle cd .. flutter create --platforms=android . - 恢复自定义配置(如私有仓库)
七、预防措施和最佳实践
1. 版本锁定
在项目根目录创建 VERSIONS.md:
| |
2. 使用 FVM 管理 Flutter 版本
| |
3. Docker 化构建环境
| |
4. CI/CD 配置示例
| |
5. 团队协作规范
强制使用相同环境:
| |
pre-commit hook:
| |
八、常见错误速查表
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
jlink error with Java 21 | AGP < 8.2.1 不支持 Java 21 | 升级 AGP 到 8.2.1+ |
Cannot resolve dependency | 缺少仓库配置 | 在 pluginManagement 添加仓库 |
Gradle version too old | AGP 需要更新的 Gradle | 升级 gradle-wrapper.properties |
Kotlin plugin version | Kotlin 版本与 Gradle 不兼容 | 升级 Kotlin 到 1.9.0+ |
namespace not specified | AGP 8.0+ 需要 namespace | 在 app/build.gradle 添加 namespace |
Unsupported class file major version | Java 版本太新 | 降级到 Java 17 或升级 AGP |
九、未来展望
Flutter 和 Android 团队正在努力改进:
已实现的改进
- ✅ 新版项目结构(Flutter 3.16+)
- ✅ 更友好的错误提示(Flutter Fix)
- ✅ 自动版本检测警告
计划中的改进
- 🚧 自动依赖版本协调
- 🚧 统一的版本管理工具
- 🚧 更详细的兼容性文档
社区期望
- 🔮 一键升级命令:
flutter upgrade android-deps - 🔮 版本冲突自动修复
- 🔮 可视化依赖管理界面
十、总结
Flutter Android 构建的版本地狱源于:
- 多个独立组织的工具链整合
- 历史包袱和向后兼容性要求
- 构建系统的自举特性
- 缺乏统一的版本协调机制
应对策略:
- ✅ 使用稳定的版本组合
- ✅ 锁定开发环境版本
- ✅ 理解依赖关系链
- ✅ 保持配置文件简洁
- ✅ 记录和分享工作配置
虽然现状不完美,但理解了这些依赖关系后,你就能快速定位和解决问题,而不是在错误信息中迷失方向。
版本推荐:
- Flutter 版本:3.24.x
- 推荐 AGP:8.2.1
- 推荐 Java:17 最后的建议:如果配置正常工作,就不要随意升级 — 这不是保守,而是务实 😉
参考资源:
2 - Flutter macOS 代码签名问题解决指南
问题背景
在使用 Flutter 开发 macOS 应用时,经常会遇到以下错误:
error: Signing for "Runner" requires a development team.
Select a development team in the Signing & Capabilities editor.
或者:
error: "Runner" requires a provisioning profile.
Select a provisioning profile in the Signing & Capabilities editor.
这是因为 macOS 应用默认需要代码签名才能构建和运行。本文将介绍几种解决方案及其适用场景。
解决方案对比
方案一:使用 Apple ID 签名(推荐用于正式开发)
适用场景:
- 准备发布到 App Store 或进行 TestFlight 测试
- 需要分发给其他开发者
- 长期 macOS 开发
优点:
- ✅ 最标准、最官方的做法
- ✅ 可以使用完整的 macOS 权限和功能
- ✅ 应用可以正常分发和安装
- ✅ 免费 Apple ID 即可(无需付费开发者账号)
缺点:
- ❌ 需要 Xcode(约 10-15 GB)
- ❌ 配置相对繁琐
- ❌ 需要网络验证
操作步骤:
安装 Xcode(从 App Store)
在 Xcode 中添加 Apple ID:
- 打开 Xcode → Settings → Accounts
- 点击 + 添加 Apple ID
- 登录后会自动创建开发证书
配置项目签名:
1open macos/Runner.xcworkspace- 选择 Runner 项目 → Runner target
- 进入 Signing & Capabilities
- 勾选 “Automatically manage signing”
- 选择你的团队
构建运行:
1flutter run -d macos
方案二:创建自签名证书
适用场景:
- 不想使用 Apple ID
- 只在自己电脑上开发测试
- 已安装 Xcode Command Line Tools
优点:
- ✅ 不需要 Apple ID
- ✅ 无需网络验证
- ✅ 支持基本的应用功能
缺点:
- ❌ 应用无法分发给他人
- ❌ 某些系统功能可能受限
- ❌ 需要手动管理证书
操作步骤:
创建自签名证书:
- 打开"钥匙串访问"(应用程序 → 实用工具)
- 钥匙串访问 → 证书助理 → 创建证书
- 名称:
Mac Developer - 身份类型:自签名根证书
- 证书类型:代码签名
- 勾选"让我覆盖这些默认值"
- 一路继续,最后点击创建
验证证书:
1xcrun security find-identity -v -p codesigning在 Xcode 中配置项目使用该证书(步骤同方案一)
方案三:完全禁用代码签名(推荐用于本地开发)
适用场景:
- 纯本地开发测试
- 不需要分发应用
- 不想安装 Xcode
- 快速迭代开发
优点:
- ✅ 无需任何证书或 Apple ID
- ✅ 无需安装 Xcode
- ✅ 配置简单快速
- ✅ 适合 CI/CD 环境
缺点:
- ❌ 应用无法分发(需要用户手动处理权限)
- ❌ 某些系统功能可能受限
- ❌ 不符合 Apple 官方规范
操作步骤:
| |
应用分发说明
如果选择方案三(禁用签名)进行开发,在分发应用时用户需要执行以下操作才能运行:
方法 1:移除隔离属性(推荐)
| |
注意:不需要使用 sudo,普通用户权限即可。
方法 2:右键打开
- 右键点击应用
- 选择"打开"
- 在弹出的对话框中点击"打开"
这种方法可以绕过 Gatekeeper 的检查,但只需要操作一次。
推荐方案总结
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 本地快速开发 | 方案三(禁用签名) | 配置简单,开发效率高 |
| 团队协作开发 | 方案一(Apple ID) | 标准流程,便于协作 |
| 准备发布应用 | 方案一(Apple ID) | 必须使用正式签名 |
| 无 Xcode 环境 | 方案三(禁用签名) | 不依赖 Xcode |
| CI/CD 自动化 | 方案三(禁用签名) | 减少外部依赖 |
常见问题
Q: 为什么会出现 “0 valid identities found”?
A: 这表示系统中没有可用的代码签名证书。可以选择:
- 在 Xcode 中登录 Apple ID 自动创建
- 手动创建自签名证书
- 完全禁用签名(方案三)
Q: entitlements 文件的作用是什么?
A: entitlements 文件定义了应用的权限,例如:
app-sandbox: 是否启用沙盒allow-jit: 是否允许 JIT 编译(Flutter 需要)network.client/server: 网络访问权限
Q: 禁用签名后应用安全吗?
A: 对于本地开发完全安全。但分发给用户时:
- 用户需要手动信任应用
- 系统会显示"来自身份不明开发者"的警告
- 不适合公开分发
Q: 如何在开发和发布之间切换?
A:
- 开发时使用方案三(禁用签名)
- 发布前切换到方案一(Apple ID 签名)
- 可以通过 Git 管理不同配置
结论
对于日常开发,方案三(完全禁用签名) 是最高效的选择,无需额外工具,配置简单。当需要正式发布时,再切换到方案一(Apple ID 签名)。
选择合适的方案可以大大提升开发效率,避免在签名问题上浪费时间。
参考资源:
3 - 解决 Flutter 插件在 Android Studio 中的 Gradle 版本冲突
问题现象
在 Android Studio 中打开 Flutter 插件的 Android 目录时,遇到以下错误:
Build file '~/libpag/flutter-ext/android/build.gradle' line: 23
A problem occurred evaluating root project 'libpag_flutter'.
> 'org.gradle.api.artifacts.Dependency org.gradle.api.artifacts.dsl.DependencyHandler.module(java.lang.Object)'
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
Deprecated Gradle features were used in this build, making it incompatible with Gradle 10.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
For more on this, please refer to https://docs.gradle.org/9.0-milestone-1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
问题原因
这是典型的 Gradle 版本与 Android Gradle Plugin (AGP) 版本不兼容问题。
在 Android 项目中,有两个关键版本需要匹配:
Gradle 版本:构建工具本身(如 7.5, 8.0, 9.0)
- 定义在
gradle/wrapper/gradle-wrapper.properties
- 定义在
AGP 版本:Android 专用插件
- 定义在
build.gradle的classpath 'com.android.tools.build:gradle:x.x.x'
- 定义在
版本兼容关系:
| Gradle 版本 | AGP 版本 |
|---|---|
| 7.4 - 7.6 | 7.3.0 - 7.4.2 |
| 8.0 - 8.3 | 8.0.0 - 8.1.4 |
| 8.4+ | 8.2.0+ |
Flutter 插件的特殊性
Flutter 插件项目通常没有 gradle-wrapper.properties 文件,因为它依赖宿主应用的 Gradle 配置。
但在 Android Studio 中直接打开插件的 android 目录时,IDE 会将其视为独立项目,使用默认 Gradle 版本(可能是 9.0),导致与旧版 AGP 冲突。
解决方案
方案一:创建 gradle-wrapper.properties(推荐)
在 android/gradle/wrapper/ 目录下创建 gradle-wrapper.properties:
| |
方案二:升级 AGP 版本
修改 android/build.gradle:
| |
方案三:在 Android Studio 中配置
- 打开 File → Settings → Build Tools → Gradle
- 选择 Use Gradle from: ‘specified location’
- 指定或下载 Gradle 7.5
建议
对于 Flutter 插件开发,推荐方案一,改动最小且不影响插件在实际 Flutter 项目中的使用。
执行任一方案后,点击 Android Studio 的 Sync Now 重新同步项目即可。