app-config
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFlavor Architecture
构建风味架构
- Define three flavors: ,
dev,stagingprod - Use a single entry point for all flavors
main.dart - Pass flavor-specific configuration via :
--dart-define-from-filebashflutter run --flavor dev --dart-define-from-file=config/dev.json flutter run --flavor staging --dart-define-from-file=config/staging.json flutter run --flavor prod --dart-define-from-file=config/prod.json - NEVER create separate ,
main_dev.dart,main_staging.dartentry pointsmain_prod.dart
- 定义三种构建风味:、
dev、stagingprod - 所有构建风味共用**单一**作为入口文件
main.dart - 通过参数传入对应风味的配置:
--dart-define-from-filebashflutter run --flavor dev --dart-define-from-file=config/dev.json flutter run --flavor staging --dart-define-from-file=config/staging.json flutter run --flavor prod --dart-define-from-file=config/prod.json - 绝对不要为不同构建风味单独创建、
main_dev.dart、main_staging.dart这类入口文件main_prod.dart
Config JSON Structure
配置JSON结构
- Store per-flavor JSON config files in a directory at project root:
config/config/ ├── dev.json ├── staging.json └── prod.json - Example :
config/dev.jsonjson{ "FLAVOR": "dev", "BASE_URL": "https://api-dev.example.com", "APP_NAME": "MyApp Dev", "ENABLE_LOGGING": "true", "ENABLE_CRASHLYTICS": "false" } - NEVER put secrets (API keys, signing credentials) in these JSON files — use CI-injected env vars or
flutter_secure_storage - Add to
config/*.jsonif they contain any environment-specific secrets; otherwise commit them for team convenience.gitignore
- 各风味对应的JSON配置文件统一存放在项目根目录的文件夹下:
config/config/ ├── dev.json ├── staging.json └── prod.json - 示例:
config/dev.jsonjson{ "FLAVOR": "dev", "BASE_URL": "https://api-dev.example.com", "APP_NAME": "MyApp Dev", "ENABLE_LOGGING": "true", "ENABLE_CRASHLYTICS": "false" } - 绝对不要在这些JSON文件中存放密钥(API密钥、签名凭证等),请使用CI注入的环境变量或者存储敏感信息
flutter_secure_storage - 如果文件包含任意环境专属的密钥,请将其加入
config/*.json;否则可以提交到代码仓库方便团队成员使用.gitignore
Entry Point Pattern
入口文件模式
dart
// lib/main.dart
void main() {
const flavor = String.fromEnvironment('FLAVOR', defaultValue: 'dev');
AppConfig.init(flavor: Flavor.fromString(flavor));
runApp(const App());
}- Read all compile-time values via or
String.fromEnvironment('KEY')bool.fromEnvironment('KEY') - Use a sealed enum:
Flavorsealed class Flavor { dev, staging, prod } - is a singleton holding flavor, base URL, feature flags, and Firebase config
AppConfig
dart
// lib/main.dart
void main() {
const flavor = String.fromEnvironment('FLAVOR', defaultValue: 'dev');
AppConfig.init(flavor: Flavor.fromString(flavor));
runApp(const App());
}- 通过或者
String.fromEnvironment('KEY')读取所有编译期常量bool.fromEnvironment('KEY') - 使用密封类枚举:
Flavorsealed class Flavor { dev, staging, prod } - 是一个单例类,用于存储构建风味、基础请求地址、功能开关和Firebase配置
AppConfig
Environment Configuration
环境配置
- Store per-flavor config in a centralized class:
AppConfig- — API endpoint per environment
baseUrl - — verbose logging for dev only
enableLogging - — disabled in dev
enableCrashlytics - — display name per flavor (e.g., "MyApp Dev", "MyApp")
appName
- All values come from the JSON file via — NO hardcoded per-flavor logic in Dart code
--dart-define-from-file - NEVER put secrets in the JSON config files — use or CI-injected env vars
flutter_secure_storage
- 各构建风味的配置统一存放在中心化的类中:
AppConfig- — 对应环境的API接口地址
baseUrl - — 仅开发环境开启详细日志
enableLogging - — 开发环境关闭崩溃上报
enableCrashlytics - — 对应构建风味的App显示名称(例如:"MyApp Dev"、"MyApp")
appName
- 所有配置值都通过参数从JSON文件中读取,Dart代码中绝对不要硬编码任何和构建风味相关的逻辑
--dart-define-from-file - 绝对不要在JSON配置文件中存放密钥,请使用或者CI注入的环境变量
flutter_secure_storage
Platform-Specific Flavor Setup
各平台专属构建风味配置
Android
Android
- Define and
flavorDimensionsinproductFlavors:android/app/build.gradlegroovyflavorDimensions "environment" productFlavors { dev { dimension "environment"; applicationIdSuffix ".dev"; resValue "string", "app_name", "MyApp Dev" } staging { dimension "environment"; applicationIdSuffix ".staging"; resValue "string", "app_name", "MyApp Staging" } prod { dimension "environment"; resValue "string", "app_name", "MyApp" } }
- 在中定义
android/app/build.gradle和flavorDimensions:productFlavorsgroovyflavorDimensions "environment" productFlavors { dev { dimension "environment"; applicationIdSuffix ".dev"; resValue "string", "app_name", "MyApp Dev" } staging { dimension "environment"; applicationIdSuffix ".staging"; resValue "string", "app_name", "MyApp Staging" } prod { dimension "environment"; resValue "string", "app_name", "MyApp" } }
iOS
iOS
- Create Xcode schemes for each flavor (Dev, Staging, Prod)
- Use xcconfig files for per-flavor bundle ID, display name, and signing
- Map Flutter flavors to Xcode schemes in
ios/Runner.xcodeproj
- 为每个构建风味创建对应的Xcode scheme(开发、预发布、生产)
- 使用xcconfig文件配置各风味对应的包ID、App显示名称和签名信息
- 在中将Flutter构建风味和Xcode scheme做映射
ios/Runner.xcodeproj
Firebase Per-Flavor
多环境Firebase配置
- Use separate Firebase projects per flavor (dev, staging, prod)
- Place (Android) and
google-services.json(iOS) in flavor-specific directoriesGoogleService-Info.plist - Use with
flutterfire configureflag for each environment--project
- 每个构建风味使用独立的Firebase项目(开发、预发布、生产)
- 将Android端的和iOS端的
google-services.json存放到对应风味的专属目录下GoogleService-Info.plist - 针对每个环境使用命令加上
flutterfire configure参数进行配置--project
Build Commands
构建命令
bash
undefinedbash
undefinedDevelopment
开发环境
flutter run --flavor dev --dart-define-from-file=config/dev.json
flutter run --flavor dev --dart-define-from-file=config/dev.json
Staging
预发布环境
flutter run --flavor staging --dart-define-from-file=config/staging.json
flutter run --flavor staging --dart-define-from-file=config/staging.json
Production release
生产环境打包
flutter build appbundle --flavor prod --dart-define-from-file=config/prod.json --release
flutter build ipa --flavor prod --dart-define-from-file=config/prod.json --release
undefinedflutter build appbundle --flavor prod --dart-define-from-file=config/prod.json --release
flutter build ipa --flavor prod --dart-define-from-file=config/prod.json --release
undefinedRules
规范
- NEVER hardcode environment-specific values (URLs, API keys, feature flags)
- NEVER commit production secrets to the repository
- Every team member MUST be able to run any flavor locally with a single command
- CI/CD pipelines MUST specify both and
--flavorexplicitly--dart-define-from-file - Use a single — NEVER create separate entry points per flavor
main.dart
- 绝对不要硬编码和环境相关的配置值(接口地址、API密钥、功能开关等)
- 绝对不要将生产环境的密钥提交到代码仓库
- 所有团队成员必须可以通过单条命令在本地运行任意构建风味的App
- CI/CD流水线必须显式指定和
--flavor两个参数--dart-define-from-file - 仅使用单一作为入口,绝对不要为每个构建风味单独创建入口文件
main.dart