Flutter Flavor 超全实战指南:一套代码多环境打包(Android+iOS 从零落地)
Flutter Flavor 超全实战指南:一套代码多环境打包(Android+iOS 从零落地)
适用人群:Flutter 开发者、移动端打包运维、CI/CD 自动化部署、需要多环境迭代的项目
最终实现效果:同一台手机同时安装 3 个版本 App(Dev 开发版、Staging 测试版、Prod 正式版),互不覆盖、独立图标、独立包名、独立接口域名。
一、Flutter Flavor 是什么?核心概念
1.1 官方定义
Flavor(风味/变体)是 Flutter 提供的多环境构建方案,本质是对 Android productFlavor 和 iOS Scheme 的统一封装。
简单一句话:一套代码,多套构建产物,多套环境配置。
1.2 为什么必须用 Flavor?解决什么痛点
绝大多数项目不用 Flavor 会出现这些致命问题:
-
开发、测试、生产包包名一致,安装直接覆盖,无法并行测试
-
每次打包手动改域名、密钥、开关,极易打错环境包
-
测试环境带调试日志、测试接口流入生产,线上事故风险极高
-
无法区分环境图标、应用名称,测试人员分不清安装的是哪个包
1.3 Flavor 能实现的能力
-
多环境独立:Dev / Staging / Prod 三套包共存手机
-
原生层隔离:独立包名、独立 BundleID、独立 App 名称、独立图标
-
业务层隔离:独立接口域名、独立 SDK 密钥、独立功能开关
-
打包命令隔离:一条命令打出对应环境 Release 包
二、Flavor 底层原理(彻底看懂,不再踩坑)
2.1 双端底层对应关系(核心)
Flutter 本身没有自创编译体系,Flavor 只是统一双端原生构建能力:
-
Android Flavor = Gradle ProductFlavor(Gradle 多风味构建)
-
iOS Flavor = Xcode Scheme + Build Configuration(编译方案隔离)
当你执行 flutter build --flavor dev:
-
Flutter 通知 Gradle 编译 dev 风味(Android)
-
Flutter 匹配同名 Xcode Scheme 编译(iOS)
-
结合
dart-define注入环境变量,实现 Dart 业务层环境区分
2.2 两个核心机制(90% 开发者混淆)
-
Flavor:管控原生层(包名、图标、签名、App 名称)
-
dart-define:管控 Dart 业务层(域名、开关、密钥、日志)
✅ 生产可用方案:两者必须搭配使用,缺一不可。
三、整体环境规划(行业标准三环境)
本文统一搭建三套环境,企业项目通用标准:
| 环境 | Flavor 名称 | 用途 | 包名示例 |
|---|---|---|---|
| 开发环境 | dev | 本地开发、联调、开启调试 | com.xxx.app.dev |
| 测试环境 | staging | QA 测试、预发验证 | com.xxx.app.staging |
| 生产环境 | prod | 上线、蒲公英、TestFlight、应用商店 | com.xxx.app |
四、Android 端完整 Flavor 配置(可直接复制)
4.1 修改 android/app/build.gradle
找到 android {} 节点,在 defaultConfig 同级添加如下代码:
groovy
// 风味维度声明(必须)
flavorDimensions "env"
productFlavors {
// 开发环境
dev {
dimension "env"
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
manifestPlaceholders = [
appName : "App-Dev"
]
}
// 测试预发环境
staging {
dimension "env"
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
manifestPlaceholders = [
appName : "App-Staging"
]
}
// 生产环境
prod {
dimension "env"
// 生产不加后缀,保持原包名
manifestPlaceholders = [
appName : "App"
]
}
}
4.2 修改 AndroidManifest.xml 动态应用名
打开 android/app/src/main/AndroidManifest.xml,替换 label 为占位符:
xml
<application
android:label="${appName}"
...
>
4.3 Android 额外能力(可选)
可针对不同 Flavor 配置独立图标、独立资源、独立权限,只需在android/app/src 新建对应风味资源文件夹即可。
【配图1:Android 多风味资源目录结构图(文字高清复刻)】
项目路径:android/app/src
目录结构如下,与默认 main 目录同级创建即可:
├── main(默认主工程资源)
├── dev(开发环境专属资源)
│ └── res(可配置dev专属图标、颜色、布局资源)
├── staging(测试预发环境专属资源)
│ └── res
└── prod(生产环境专属资源)
优势:不同环境可实现独立App图标、启动页、配色、静态资源,互不冲突。
五、iOS 端完整 Flavor 配置(最容易踩坑重点)
iOS 没有 Gradle 自动生成机制,必须手动创建 Scheme,且名称必须和 Android flavor 完全一致。
5.1 打开 Xcode 工程
打开 ios/Runner.xcworkspace
5.2 新建三套 Scheme
顶部 Scheme 选择器 → Manage Schemes → 新建:
新建三个 Scheme:dev / staging / prod
【配图2:Xcode 新建 Scheme 完整操作截图复刻】
1. 打开 ios/Runner.xcworkspace,Xcode 顶部左上角点击当前默认 Scheme(默认是 Runner)
2. 下拉选择 Manage Schemes...
3. 点击左下角+ 号新建 Scheme
4. Target 选择 Runner,依次创建三个 Scheme:dev、staging、prod
5. 勾选 Shared(共享Scheme),保证Git同步生效,团队统一配置
核心要求:Scheme名称必须和Android Flavor名称完全一致,否则打包无法匹配环境。
5.3 配置各 Scheme 独立 BundleID
选中对应 Scheme → Edit Scheme → Run / Archive → Build Configuration 分别配置 Bundle Identifier:
-
dev:com.xxx.app.dev
-
staging:com.xxx.app.staging
-
prod:com.xxx.app
【配图3:Xcode Scheme 配置独立BundleID完整流程】
1. 顶部选中对应 Scheme(例:dev)→ 选择 Edit Scheme
2. 左侧分别选中 Run、Archive 两个选项
3. 右侧 Info 面板,Build Configuration 统一选择 Release(关键:杜绝Debug包离线报错)
4. 选中项目 Target → Signing & Capabilities,对应配置Bundle ID:
- dev环境:com.xxx.app.dev
- staging环境:com.xxx.app.staging
- prod环境:com.xxx.app
配置后,各环境包完全独立,手机可同时安装不覆盖。
5.4 配置动态 App 名称(可选)
通过 Info.plist 变量或 Xcode Build Setting 配置不同环境应用名、图标,实现和 Android 一致的多环境展示。
六、Dart 业务层环境配置(dart-define 标准方案)
Flutter 官方推荐 dart-define 编译期注入环境变量,运行时不可篡改、安全、无硬编码。
6.1 新建环境配置类
dart
class AppEnv {
// 环境名称 dev/staging/prod
static const String env = String.fromEnvironment("ENV");
// 接口域名
static const String baseUrl = String.fromEnvironment("BASE_URL");
// 是否生产环境
static bool get isProd = env == "prod";
static bool get isDev = env == "dev";
static bool get isStaging = env == "staging";
}
6.2 全局使用示例
dart
// 网络请求基地址
dio.options.baseUrl = AppEnv.baseUrl;
// 调试开关
if(AppEnv.isDev){
// 开启日志、调试面板、抓包
}
if(AppEnv.isProd){
// 关闭调试、开启崩溃上报、正式埋点
}
七、完整运行/打包命令(可直接复制)
7.1 Android 命令
bash
# 开发环境运行
flutter run --flavor dev --dart-define=ENV=dev --dart-define=BASE_URL=https://dev-api.xxx.com
# 生产 Release 打包
flutter build apk --release --flavor prod --dart-define=ENV=prod --dart-define=BASE_URL=https://api.xxx.com
7.2 iOS 核心命令(适配你打包流程)
你日常使用的无签名打包流程,完美适配 Flavor:
bash
flutter clean
flutter pub get
cd ios && pod install && cd ..
# Release 无签名打包,后续 Xcode Archive
flutter build ios --release --flavor dev --no-codesign \
--dart-define=ENV=dev \
--dart-define=BASE_URL=https://dev-api.xxx.com
✅ 关键操作:打包后打开 Xcode,必须切换对应 Scheme 再 Archive,否则环境错乱!
【配图4:iOS打包最终归档正确操作流程】
1. 终端执行完 flutter build ios --flavor xxx --release --no-codesign 命令
2. 打开 Xcode 工程,必须手动切换顶部Scheme为对应打包环境(打dev包切dev,打prod包切prod)
3. 执行Shift+Cmd+K 清理缓存
4. 依次点击:Product → Archive 归档
5. 归档完成后 Distribute App,选择 Ad-Hoc 导出IPA
核心避坑:命令行仅编译源码,最终打包环境由Xcode当前Scheme决定,不切换必导致环境错乱。
八、Flavor 日常使用规范
8.1 目录规范
-
所有环境变量禁止硬编码,全部通过 dart-define 注入
-
原生包名、图标、名称由 Flavor 管控
-
业务逻辑、域名、开关由 dart-define 管控
8.2 团队协作规范
-
所有成员统一使用 flavor 命令运行项目,禁止直接 flutter run
-
打包必须携带 flavor + dart-define 参数,杜绝手动改配置
九、全网高频踩坑总结(99% 人遇到的问题)
坑1:iOS 打包 flavor 配置了,打出的包还是默认环境
原因:命令行指定 flavor 只是编译源码,Xcode Archive 必须手动切换对应 Scheme
解决:build 完成后,Xcode 左上角切换 dev/staging/prod Scheme 再归档
坑2:多环境包依然覆盖安装
原因:Android applicationId / iOS BundleID 未加后缀区分
解决:严格配置 applicationIdSuffix 和独立 BundleID
坑3:iOS Debug 包脱离电脑白屏报错
原因:Archive 时 Scheme 编译模式是 Debug
解决:Archive 必须设置为 Release,Flavor 只是环境区分,不控制编译模式
坑4:dart 读取不到环境变量
原因:热重载不刷新 dart-define,必须重新 run / build
解决:修改环境参数后重新编译,禁止热重载生效
十、FVM + Flavor 黄金组合(企业级最佳实践)
搭配 FVM 版本管理,实现 项目锁定 SDK + 多环境打包,彻底统一团队编译环境:
bash
fvm flutter build ios --release --flavor prod --no-codesign
十一、总结
1. Flavor 核心价值:一套代码隔离多环境,杜绝人工改配置出错
2. Android 靠 productFlavors、iOS 靠 Xcode Scheme,名称必须统一
3. Flavor 管原生包配置,dart-define 管业务配置,二者缺一不可
4. iOS 打包核心要点:命令行编译 + Xcode 切换对应 Scheme 归档
5. 企业项目必用:Dev/Staging/Prod 三套 Flavor 是标准工程规范
暂无评论,快来发表第一条评论吧