RN 做多环境 + 多渠道打包,我比较推荐把它拆成两个维度:
- 环境 Environment :
dev / test / staging / prod - 渠道 Channel :
official / google / huawei / xiaomi / ...
最终组合成:
r
dev-official
test-official
staging-official
prod-official
prod-google
prod-huawei
prod-xiaomi
核心原则是:环境控制业务配置,渠道控制分发配置,二者不要混在一起。
1. 推荐的整体架构
例如项目:
bash
my-rn-app/
├── android/
├── ios/
├── src/
├── env/
│ ├── dev.ts
│ ├── test.ts
│ ├── staging.ts
│ └── prod.ts
├── scripts/
│ └── build.js
├── package.json
└── .env.*
定义环境:
bash
// env/dev.ts
export default {
env: 'dev',
apiUrl: 'https://dev-api.example.com',
appName: 'MyApp Dev',
}
bash
// env/test.ts
export default {
env: 'test',
apiUrl: 'https://test-api.example.com',
appName: 'MyApp Test',
}
bash
// env/prod.ts
export default {
env: 'prod',
apiUrl: 'https://api.example.com',
appName: 'MyApp',
}
然后:
javascript
import Config from './env'
fetch(`${Config.apiUrl}/user`)
2. Android:Flavor 是核心
Android 官方就非常适合做多环境、多渠道。
例如:
bash
android {
flavorDimensions "env", "channel"
productFlavors {
dev {
dimension "env"
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
}
test {
dimension "env"
applicationIdSuffix ".test"
versionNameSuffix "-test"
}
staging {
dimension "env"
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
}
prod {
dimension "env"
}
official {
dimension "channel"
}
google {
dimension "channel"
}
huawei {
dimension "channel"
}
}
}
这样 Gradle 会自动组合:
devOfficial
devGoogle
devHuawei
testOfficial
testGoogle
testHuawei
prodOfficial
prodGoogle
prodHuawei
比如:
bash
./gradlew assembleProdGoogleRelease
就是:
diff
生产环境
+
Google 渠道
+
Release
3. 更推荐:环境和渠道不要全部写死在 Flavor
如果渠道非常多,比如:
Google
Huawei
Xiaomi
Oppo
Vivo
Samsung
Official
不建议把所有配置都塞进 build.gradle。
可以把渠道配置抽出来:
css
android/
├── app/
│ ├── src/
│ │ ├── main/
│ │ ├── dev/
│ │ ├── test/
│ │ ├── prod/
│ │ ├── google/
│ │ ├── huawei/
│ │ └── xiaomi/
例如:
bash
android/app/src/google/
AndroidManifest.xml
android/app/src/huawei/
AndroidManifest.xml
渠道专属:
- App Name
- App Icon
- Scheme
- Push 配置
- 第三方 SDK
- Google Services
- Huawei HMS
- 渠道统计 SDK
- 渠道权限
都可以放进去。
4. iOS:Scheme + Configuration
iOS 没有 Android Flavor 这么直接,通常使用:
diff
Scheme
+
Build Configuration
例如:
rust
Debug
Release
Dev
Test
Staging
Prod
最终:
sql
Dev-Debug
Dev-Release
Test-Debug
Test-Release
Staging-Release
Prod-Release
然后创建:
Dev.xcconfig
Test.xcconfig
Staging.xcconfig
Prod.xcconfig
例如:
ini
// Dev.xcconfig
API_URL = https://dev-api.example.com
PRODUCT_BUNDLE_IDENTIFIER = com.example.app.dev
APP_NAME = MyApp Dev
生产:
ini
// Prod.xcconfig
API_URL = https://api.example.com
PRODUCT_BUNDLE_IDENTIFIER = com.example.app
APP_NAME = MyApp
5. React Native 层不要直接判断环境
这是一个非常重要的设计。
不建议:
ini
if (__DEV__) {
api = 'https://dev-api.com'
} else {
api = 'https://api.example.com'
}
因为:
markdown
__DEV__
只能很好地解决 Debug / Release,无法表达:
bash
test
staging
prod
更推荐:
arduino
const Config = {
env: process.env.APP_ENV,
apiUrl: process.env.API_URL,
channel: process.env.APP_CHANNEL,
}
然后:
bash
Config.apiUrl
Config.env
Config.channel
统一使用。
6. 可以使用 react-native-config
RN 项目里一个比较常见的方案是:
arduino
react-native-config
配置:
.env.development
.env.test
.env.staging
.env.production
例如:
ini
# .env.development
APP_ENV=development
API_URL=https://dev-api.example.com
ini
# .env.production
APP_ENV=production
API_URL=https://api.example.com
JS:
javascript
import Config from 'react-native-config'
console.log(Config.APP_ENV)
console.log(Config.API_URL)
这样:
RN JS
↓
Config
↓
Native Build Config
↓
不同环境
7. 我更推荐的配置模型
实际上最好把配置分成 3 层:
bash
┌──────────────┐
│ Environment │
│ dev/test/prod │
└───────┬──────┘
│
▼
┌──────────────┐
│ Channel │
│ google/huawei│
└───────┬──────┘
│
▼
┌──────────────┐
│ Build │
│ debug/release│
└──────────────┘
也就是说:
Environment
负责:
API
WebSocket
数据库环境
日志级别
Feature Flag
Sentry 环境
Channel
负责:
css
Application ID
App Name
Icon
Push SDK
第三方 SDK
渠道统计
渠道参数
Build Type
负责:
rust
Debug
Release
签名
混淆
日志
性能优化
8. 最终建议的目录
一个比较成熟的 RN 项目可以这样:
css
my-app/
│
├── src/
│ ├── config/
│ │ ├── index.ts
│ │ ├── env.ts
│ │ └── channel.ts
│ │
│ ├── api/
│ ├── components/
│ └── screens/
│
├── env/
│ ├── .env.dev
│ ├── .env.test
│ ├── .env.staging
│ └── .env.prod
│
├── android/
│ └── app/
│ └── src/
│ ├── main/
│ ├── dev/
│ ├── test/
│ ├── staging/
│ ├── prod/
│ ├── google/
│ ├── huawei/
│ └── xiaomi/
│
├── ios/
│ ├── Config/
│ │ ├── Dev.xcconfig
│ │ ├── Test.xcconfig
│ │ ├── Staging.xcconfig
│ │ └── Prod.xcconfig
│ │
│ └── Schemes/
│
└── scripts/
└── build.js
9. 最终打包命令
最好把复杂的 Gradle / Xcode 命令封装掉。
例如:
ini
{
"scripts": {
"android:dev": "ENV=dev CHANNEL=official react-native run-android",
"android:test": "ENV=test CHANNEL=official react-native run-android",
"android:staging": "ENV=staging CHANNEL=official react-native run-android",
"android:prod:google": "ENV=prod CHANNEL=google ./gradlew assembleProdGoogleRelease",
"android:prod:huawei": "ENV=prod CHANNEL=huawei ./gradlew assembleProdHuaweiRelease",
"ios:dev": "...",
"ios:test": "...",
"ios:prod": "..."
}
}
CI/CD 里面则直接:
ini
ENV=prod
CHANNEL=google
BUILD_TYPE=release
然后:
bash
Git
│
▼
CI/CD
│
┌──────┴──────┐
│ │
ENV CHANNEL
│ │
prod/test google/huawei
│ │
└──────┬──────┘
▼
React Native
│
┌──────┴──────┐
▼ ▼
Android iOS
│ │
▼ ▼
APK/AAB IPA
10. 一个容易踩坑的地方
不要把渠道当成 API 环境。
比如不要设计成:
.env-google
.env-huawei
.env-xiaomi
然后里面同时写:
ini
API_URL=xxx
PUSH_APP_ID=xxx
这样后面很容易出现:
r
prod-google
test-google
staging-google
配置大量复制。
应该是:
bash
Environment
├── dev
├── test
├── staging
└── prod
Channel
├── official
├── google
├── huawei
└── xiaomi
最终在 Build 阶段进行组合。
如果你现在是一个实际 RN 项目
我可以进一步直接给你一套可以落地的 RN 多环境 + 多渠道模板,包括:
arduino
React Native
├── react-native-config
├── Android Flavor
├── iOS Scheme + xcconfig
├── Google/Huawei/Xiaomi 渠道
├── Bundle ID / applicationId
├── App 图标
├── Firebase / HMS
├── 签名
├── Fastlane
└── GitLab/GitHub CI
并且可以按照 dev/test/staging/prod × official/google/huawei 给出完整目录和 build.gradle、xcconfig、package.json、CI 配置。