多环境配置与密钥管理实践

Created on

前言

当项目进入多环境阶段(开发/测试/预发/生产),最容易出问题的不是代码,而是配置与密钥管理。API Key、推送 AppKey、地图服务、归因 SDK、广告 ID,都可能因为配置混乱而导致线上故障。

本文结合真实项目实践,给出一套可落地的配置分层与密钥管理方案,重点解决“可切换、可追溯、可安全交付”。

设计目标

配置分层模型

建议把配置分成三层:

  1. 编译期配置:决定原生工程与打包结果
  2. 运行时配置:决定业务行为与服务地址
  3. 构建系统配置:决定环境变量注入与密钥存储

这三层需要独立又可组合,避免“某个 .env 控制一切”的混乱。

编译期: app.config.ts + Config Plugin

编译期配置影响原生工程,必须集中在 app.config.ts 中完成,并通过 Config Plugin 统一注入。典型例子:

推荐用环境变量驱动:

[
  "@repo/push-notification/plugin",
  {
    appKey: process.env.EXPO_PUBLIC_JPUSH_APPKEY,
    channel: process.env.EXPO_PUBLIC_JPUSH_CHANNEL,
  },
];

这样能确保 prebuild 与 EAS Build 一致,同时避免硬编码。

运行时: EXPOPUBLIC 与 config/extra

运行时配置用于 JS 逻辑,推荐统一走 EXPO_PUBLIC_ 前缀,再由 app.config.ts 注入 extra:

extra: {
  apiBaseUrl: process.env.EXPO_PUBLIC_API_BASE_URL,
  mapProvider: process.env.EXPO_PUBLIC_MAP_PROVIDER,
},

这样可以在运行时通过 expo-constants 读取,且不会与原生配置混用。

构建系统: .env + EAS Secrets

推荐两套来源:

原则是“密钥只进入构建环境,不进入仓库”。

环境切换策略

建议通过单一环境变量控制环境,例如:

EXPO_PUBLIC_APP_ENV=staging

然后在 app.config.ts 里映射不同配置:

const env = process.env.EXPO_PUBLIC_APP_ENV || "dev";
const apiBaseUrl =
  env === "prod" ? "https://api.xxx.com" : "https://staging.xxx.com";

这样能保证切换是“显式的”,避免隐式配置导致混乱。

密钥命名规范

推荐统一前缀与责任归属:

命名越明确,排错越快。

常见坑

小结

多环境配置的核心是“分层与一致性”。只要编译期配置集中在 Config Plugin,运行时配置走统一的 extra,密钥通过构建系统注入,就能最大程度降低配置事故,让环境切换变成日常操作而不是高风险动作。