Skip to content

10_Engineering/05 - 多环境配置

1. 为什么需要多环境配置

HarmonyOS 应用通常需要支持多种运行环境:

环境说明API Level签名
Dev(开发环境)本地开发调试API 12Debug 签名
Beta(测试环境)QA 测试、内部测试API 11/12测试签名
Release(生产环境)AppGallery 上架API 11+Release 签名
Staging(预发布)灰度发布API 11+预发布签名

不同环境需要不同的配置:

  • API Level(编译版本)
  • API 地址(开发/测试/生产接口)
  • 签名证书
  • 功能开关
  • Debug 日志开关
  • 第三方 SDK 配置

2. 多环境配置方案

2.1 方案一:products 配置(推荐)

json5
// build-profile.json5
{
  "app": {
    "signingConfigs": [
      {
        "name": "debug",
        "type": "HarmonyOS",
        "material": { "certpath": "debug.cer", "storeFile": "debug.p12", ... }
      },
      {
        "name": "release",
        "type": "HarmonyOS",
        "material": { "certpath": "release.cer", "storeFile": "release.p12", ... }
      }
    ],
    "products": [
      {
        "name": "dev",
        "signingConfig": "debug",
        "compatibleSdkVersion": "12",
        "runtimeOS": "HarmonyOS",
        "bundleName": "com.example.myapp.dev",
        "minAPIVersion": 12,
        "bundleType": "app",
        "debug": true
      },
      {
        "name": "beta",
        "signingConfig": "debug",
        "compatibleSdkVersion": "11",
        "runtimeOS": "HarmonyOS",
        "bundleName": "com.example.myapp.beta",
        "minAPIVersion": 11,
        "bundleType": "app",
        "debug": true
      },
      {
        "name": "release",
        "signingConfig": "release",
        "compatibleSdkVersion": "11",
        "runtimeOS": "HarmonyOS",
        "bundleName": "com.example.myapp",
        "minAPIVersion": 11,
        "bundleType": "app",
        "debug": false
      }
    ],
    "buildModeSet": [
      { "name": "debug" },
      { "name": "release" }
    ]
  }
}

2.2 方案二:多环境配置类

typescript
// common/src/main/ets/config/EnvironmentConfig.ets
/** 环境配置 - 通过编译期 define 注入 */
export class EnvironmentConfig {
  /** 当前环境 */
  static readonly ENV: string = 'DEV';  // DEV / BETA / RELEASE

  /** API 基础地址 */
  static readonly API_BASE_URL: string = this.getApiBaseUrl();

  /** 是否开启 Debug 日志 */
  static readonly DEBUG_LOG: boolean = this.ENV !== 'RELEASE';

  /** 是否开启 Mock 数据 */
  static readonly MOCK_ENABLED: boolean = this.ENV === 'DEV';

  /** 应用 ID(不同环境不同) */
  static readonly APP_ID: string = this.getAppId();

  private static getApiBaseUrl(): string {
    switch (this.ENV) {
      case 'DEV':   return 'https://dev-api.example.com';
      case 'BETA':  return 'https://beta-api.example.com';
      case 'RELEASE': return 'https://api.example.com';
      default:      return 'https://api.example.com';
    }
  }

  private static getAppId(): string {
    switch (this.ENV) {
      case 'DEV':     return 'app-dev-001';
      case 'BETA':    return 'app-beta-001';
      case 'RELEASE': return 'app-release-001';
      default:        return 'app-release-001';
    }
  }
}

2.3 方案三:编译期 define 注入

json5
// entry/build-profile.json5
{
  "buildOptionSet": [
    {
      "name": "dev",
      "arkOptions": {
        "arkFlags": [
          "--define=ENV:DEV",
          "--define=API_BASE_URL:https://dev-api.example.com"
        ]
      }
    },
    {
      "name": "beta",
      "arkOptions": {
        "arkFlags": [
          "--define=ENV:BETA",
          "--define=API_BASE_URL:https://beta-api.example.com"
        ]
      }
    },
    {
      "name": "release",
      "arkOptions": {
        "arkFlags": [
          "--define=ENV:RELEASE",
          "--define=API_BASE_URL:https://api.example.com"
        ]
      }
    }
  ]
}
typescript
// 通过 globalThis 访问编译期注入的配置
if (globalThis['ENV'] === 'DEV') {
  EnvironmentConfig.ENV = 'DEV';
  EnvironmentConfig.API_BASE_URL = 'https://dev-api.example.com';
} else if (globalThis['ENV'] === 'BETA') {
  EnvironmentConfig.ENV = 'BETA';
  EnvironmentConfig.API_BASE_URL = 'https://beta-api.example.com';
} else {
  EnvironmentConfig.ENV = 'RELEASE';
  EnvironmentConfig.API_BASE_URL = 'https://api.example.com';
}

3. 环境变量使用

3.1 网络请求配置

typescript
// common/src/main/ets/http/BaseHttpClient.ets
import { EnvironmentConfig } from '../config/EnvironmentConfig';

export class BaseHttpClient {
  private baseUrl: string;

  constructor() {
    this.baseUrl = EnvironmentConfig.API_BASE_URL;
  }

  async get<T>(path: string, params?: object): Promise<T> {
    const url = `${this.baseUrl}${path}`;
    // ... 实际请求实现
    return fetch(url, { method: 'GET', headers: {
      'X-App-Id': EnvironmentConfig.APP_ID,
      'X-Env': EnvironmentConfig.ENV,
    } }) as Promise<T>;
  }

  async post<T>(path: string, body?: object): Promise<T> {
    const url = `${this.baseUrl}${path}`;
    return fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Env': EnvironmentConfig.ENV,
      },
      body: JSON.stringify(body),
    }) as Promise<T>;
  }
}

3.2 功能开关(Feature Flag)

typescript
// common/src/main/ets/config/FeatureFlags.ets
export class FeatureFlags {
  /** 开发环境 */
  static readonly DEV = {
    DEBUG_LOG: true,
    MOCK_DATA: true,
    NEW_UI: true,
    BETA_FEATURES: true,
    ANIMATIONS: true,
  };

  /** 测试环境 */
  static readonly BETA = {
    DEBUG_LOG: true,
    MOCK_DATA: false,
    NEW_UI: true,
    BETA_FEATURES: true,
    ANIMATIONS: true,
  };

  /** 生产环境 */
  static readonly RELEASE = {
    DEBUG_LOG: false,
    MOCK_DATA: false,
    NEW_UI: false,
    BETA_FEATURES: false,
    ANIMATIONS: true,
  };

  static get(): typeof this.DEV {
    switch (EnvironmentConfig.ENV) {
      case 'DEV':   return this.DEV;
      case 'BETA':  return this.BETA;
      default:      return this.RELEASE;
    }
  }
}

// 使用
if (FeatureFlags.get().MOCK_DATA) {
  const mockUser = { id: 1, name: 'MockUser' };
  console.log('使用 Mock 数据:', mockUser);
}

4. 多环境构建命令

bash
# 构建开发环境
hvigorw assembleApp --product=dev --mode=DEBUG

# 构建测试环境
hvigorw assembleApp --product=beta --mode=DEBUG

# 构建生产环境
hvigorw assembleApp --product=release --mode=RELEASE

# 仅编译
hvigorw compileApp --product=release

5. 环境变量 vs 资源文件方案对比

方案优点缺点适用场景
编译期 define零运行时开销,可 tree-shake需重新编译切换大多数场景
配置类 + 枚举代码可读性好需手动切换快速切换环境
资源文件运行时切换,无需重新编译需要运行时读取用户可切换环境
运行时配置最灵活需要网络请求动态配置中心

6. 面试高频考点

Q1: 如何在 HarmonyOS 中管理多环境配置?

回答要点

  • 通过 build-profile.json5products 配置定义多环境
  • 使用 ArkTS arkFlags 注入编译期 define
  • 运行时通过配置类读取环境变量
  • 推荐编译期 define + 配置类结合

Q2: 编译期 define 和运行时配置的区别?

回答要点

  • 编译期 define 在构建时注入,零运行时开销,可 tree-shake 死代码
  • 运行时配置更灵活,但不需要重新编译
  • 编译期 define 适合 API 地址、环境标识
  • 运行时配置适合用户可调节的参数(如主题色)

Q3: 如何管理不同环境的 API 地址?

回答要点

  • build-profile.json5arkFlags 中 define
  • 通过 EnvironmentConfig 类统一管理
  • 使用工厂模式或策略模式切换不同环境
  • 注意签名、BundleName 也要随环境变化

7. Android 对比

概念AndroidHarmonyOS
多环境build.gradle flavorDimensionsbuild-profile.json5 products
BuildConfig自动生成的 BuildConfig.javaarkFlags define
签名配置signingConfigs (Gradle)signingConfigs (JSON5)
资源限定符res/values-en/resources/en_US/
构建变体buildTypes + productFlavorsproducts + buildModeSet