如何实现RN 多环境、多渠道打包

RN 做多环境 + 多渠道打包,我比较推荐把它拆成两个维度:

  • 环境 Environmentdev / test / staging / prod
  • 渠道 Channelofficial / 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.gradlexcconfigpackage.json、CI 配置。

相关推荐
●VON1 小时前
鸿蒙跨平台框架怎么选?从真实需求比较 Flutter、React Native、KMP/CMP 与 Web 路线
flutter·react native·harmonyos
闲坐含香咀翠1 小时前
百万行数据透视表,我是怎么把 Vue 响应式开销砍到零的
前端·vue.js·性能优化
xiaopang1 小时前
小红书小组件(miniwidget)开发实战:单页面viewState切换架构
前端
labixiong1 小时前
告别scroll 监听:CSS 滚动驱动动画,主线程堵死也仍跟手
前端·css·html
云析赢指标公式网42 小时前
文华WH6布林轨道均线强弱共振指标公式
前端·算法
许彰午2 小时前
34-安全复盘96个问题
前端·vue.js·安全
妙码生花2 小时前
PHP 各框架下和 Go 的性能比较
前端·后端·go
Csvn2 小时前
TypeScript 类型性能:让类型体操不再卡死编译器
前端
万少2 小时前
等不到 Apple 的折叠 iPhone,我用 DeepV4.1Flash + workBuddy 一句话自己造了一台
前端·javascript·后端