ARTICLE

Flutter Flavor 超全实战指南:一套代码多环境打包(Android+iOS 从零落地)

原创文章
声明:作者声明此文章为原创,未经作者同意,请勿转载,若转载,务必注明本站出处,本平台保留追究侵权法律责任的权利。
全栈老韩
全栈工程师,擅长iOS App开发、前端(vue、react、nuxt、小程序&Taro)开发、Flutter、React Native、后端(midwayjs、golang、express、koa)开发、docker容器、seo优化等。

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:

  1. Flutter 通知 Gradle 编译 dev 风味(Android)

  2. Flutter 匹配同名 Xcode Scheme 编译(iOS)

  3. 结合 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 是标准工程规范

写下你的想法
分享观点,友善交流
请保持友善,理性讨论
0 字

暂无评论,快来发表第一条评论吧