add staging ios app build script
This commit is contained in:
@@ -1,12 +1,27 @@
|
||||
# 复制为 .env.development / .env.staging / .env.production 后填写(勿提交含密钥的副本)。
|
||||
# 环境模板在 app-expo/env/{development,staging,production}(勿在根目录放 .env.production)。
|
||||
# 本地:npm start 会通过 prestart 执行 `use-env development` 生成 .env;
|
||||
# 或手动 `npm run use-env -- staging` / `npm run use-env -- production`。
|
||||
# CI:GitHub Actions 在构建 APK 前会按分支调用 use-env(main → staging,tag → production)。
|
||||
#
|
||||
# 勿在 app-expo 根目录创建 .env.staging / .env.production:Release 构建时 Expo 会按
|
||||
# NODE_ENV=production 自动加载 .env.production,覆盖 use-env 写入的 .env。
|
||||
#
|
||||
# APP_VARIANT / EXPO_PUBLIC_APP_VARIANT:控制 Bundle ID 与「关于」页是否显示后端地址
|
||||
# development / staging → 显示版本 + API 地址;production → 仅版本号
|
||||
#
|
||||
# 变量在构建时注入;修改后需重新 prebuild/打包客户端。
|
||||
#
|
||||
# 助手朗读:无独立 EXPO_PUBLIC_* TTS 开关。会话页顶栏在每轮 WebSocket 中带 `tts_this_turn`;
|
||||
# 服务端是否具备合成能力见 api/.env 中 ENABLE_TTS 等(模板见 api/.env.example)。
|
||||
|
||||
# --- development(本地,关于页显示版本 + API)---
|
||||
# APP_VARIANT=development
|
||||
# EXPO_PUBLIC_APP_VARIANT=development
|
||||
# EXPO_PUBLIC_API_URL=http://127.0.0.1:8000
|
||||
# EXPO_PUBLIC_WS_URL=ws://127.0.0.1:8000
|
||||
|
||||
# --- staging ---
|
||||
# APP_VARIANT=staging
|
||||
# EXPO_PUBLIC_APP_VARIANT=staging
|
||||
EXPO_PUBLIC_API_URL=https://your-api.example.com
|
||||
EXPO_PUBLIC_WS_URL=wss://your-api.example.com
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# 仅 API/WS 基址;TTS 每轮开关由运行时 WS payload 与服务端 ENABLE_TTS 控制(见 api/.env.example)。
|
||||
EXPO_PUBLIC_API_URL=https://lifecho.worldsplats.com
|
||||
EXPO_PUBLIC_WS_URL=wss://lifecho.worldsplats.com
|
||||
@@ -1,2 +0,0 @@
|
||||
EXPO_PUBLIC_API_URL=http://1.15.29.57:8000/
|
||||
EXPO_PUBLIC_WS_URL=ws://1.15.29.57:8000/
|
||||
@@ -150,10 +150,10 @@ curl -Ls "https://get.maestro.mobile.dev" | bash
|
||||
|
||||
| 场景 | 构建命令 | 读取配置 |
|
||||
|------|---------|---------|
|
||||
| 普通开发 | `pnpm ios` / `pnpm android` | `.env.development` |
|
||||
| 普通开发 | `pnpm ios` / `pnpm android` | `env/development` |
|
||||
| 需要登录态的 E2E | `pnpm ios:e2e` / `pnpm android:e2e` | `.env.e2e`(staging backend + E2E 开关) |
|
||||
|
||||
正常 staging 构建继续使用 `.env.staging`,不注入 `EXPO_PUBLIC_E2E`。
|
||||
正常 staging 构建继续使用 `env/staging`(`use-env staging`),不注入 `EXPO_PUBLIC_E2E`。
|
||||
|
||||
### 现有 flow
|
||||
|
||||
|
||||
5
app-expo/env/development
vendored
Normal file
5
app-expo/env/development
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# 本地开发(npm start / prestart 默认 use-env development)
|
||||
APP_VARIANT=development
|
||||
EXPO_PUBLIC_APP_VARIANT=development
|
||||
EXPO_PUBLIC_API_URL=https://api.b102.org
|
||||
EXPO_PUBLIC_WS_URL=wss://api.b102.org
|
||||
6
app-expo/env/production
vendored
Normal file
6
app-expo/env/production
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# 正式:关于页仅显示版本号;iOS Bundle ID org.brighteng.lifecho
|
||||
# TTS 每轮开关由运行时 WS payload 与服务端 ENABLE_TTS 控制(见 api/.env.example)。
|
||||
APP_VARIANT=production
|
||||
EXPO_PUBLIC_APP_VARIANT=production
|
||||
EXPO_PUBLIC_API_URL=https://lifecho.worldsplats.com
|
||||
EXPO_PUBLIC_WS_URL=wss://lifecho.worldsplats.com
|
||||
5
app-expo/env/staging
vendored
Normal file
5
app-expo/env/staging
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# 预发:关于页显示版本 + 后端地址;iOS Bundle ID org.brighteng.lifecho.staging
|
||||
APP_VARIANT=staging
|
||||
EXPO_PUBLIC_APP_VARIANT=staging
|
||||
EXPO_PUBLIC_API_URL=http://1.15.29.57:8000
|
||||
EXPO_PUBLIC_WS_URL=ws://1.15.29.57:8000
|
||||
@@ -33,9 +33,17 @@ esac
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
echo "==> Switching to .env.${ENV}"
|
||||
echo "==> Switching to env/${ENV} → .env"
|
||||
npm run use-env -- "$ENV"
|
||||
|
||||
# Release Archive 时 NODE_ENV=production,Expo 会加载根目录 .env.production 并覆盖 .env
|
||||
for legacy in .env.production .env.staging .env.development; do
|
||||
if [[ -f "$legacy" ]]; then
|
||||
echo "::error::Found legacy $legacy — it overrides use-env on Release builds. Use app-expo/env/ templates only." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "==> expo prebuild --platform ios --clean"
|
||||
npx expo prebuild --platform ios --clean
|
||||
|
||||
|
||||
@@ -1,22 +1,39 @@
|
||||
/**
|
||||
* 将 app-expo/.env.<name> 复制为 .env,供 Metro/Expo 读取 EXPO_PUBLIC_*。
|
||||
* 将 app-expo/env/<name> 复制为 .env,供 Metro/Expo 读取 EXPO_PUBLIC_*。
|
||||
*
|
||||
* 环境模板放在 env/ 子目录,而非 .env.staging / .env.production:
|
||||
* Release 构建时 Expo 会按 NODE_ENV=production 自动加载根目录 .env.production,
|
||||
* 若与 use-env 写入的 .env 并存,production 会覆盖 staging(见 @expo/env getEnvFiles)。
|
||||
*
|
||||
* 参数 name → 源文件:
|
||||
* development → .env.development(仓库已提交;npm start / prestart 默认)
|
||||
* staging → .env.staging
|
||||
* production → .env.production
|
||||
* development → env/development
|
||||
* staging → env/staging
|
||||
* production → env/production
|
||||
*
|
||||
* CI:.github/workflows/app-expo-deploy.yml 按分支/tag 调用本脚本,与后端 env 策略对齐。
|
||||
* CI:.github/workflows/app-expo-deploy.yml 按分支/tag 调用本脚本。
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const env = process.argv[2] || 'development';
|
||||
const src = path.join(__dirname, '..', `.env.${env}`);
|
||||
const dest = path.join(__dirname, '..', '.env');
|
||||
if (fs.existsSync(src)) {
|
||||
fs.copyFileSync(src, dest);
|
||||
console.log(`Switched to .env.${env}`);
|
||||
} else {
|
||||
console.error(`Missing .env.${env}`);
|
||||
const root = path.join(__dirname, '..');
|
||||
const src = path.join(root, 'env', env);
|
||||
const dest = path.join(root, '.env');
|
||||
|
||||
/** @deprecated 旧路径;若仍存在会在 Release 构建中覆盖 .env */
|
||||
const legacyEnvFile = path.join(root, `.env.${env}`);
|
||||
|
||||
if (!fs.existsSync(src)) {
|
||||
console.error(`Missing env/${env} (expected ${src})`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
fs.copyFileSync(src, dest);
|
||||
console.log(`Switched to env/${env} → .env`);
|
||||
|
||||
if (fs.existsSync(legacyEnvFile)) {
|
||||
console.warn(
|
||||
`Warning: legacy ${path.basename(legacyEnvFile)} still exists. ` +
|
||||
'Remove it or Release builds may load production values over .env.',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,11 +12,21 @@ function resolveAppVariant(): AppVariant {
|
||||
if (__DEV__) {
|
||||
return 'development';
|
||||
}
|
||||
// Release 包若 env 未写入 APP_VARIANT(例如仅复制了 env/staging 到 .env 但变量缺失),
|
||||
// 仍按 API 是否为 http 推断预发,避免关于页误隐藏后端地址。
|
||||
const apiUrl = process.env.EXPO_PUBLIC_API_URL ?? '';
|
||||
if (apiUrl.startsWith('http://')) {
|
||||
return 'staging';
|
||||
}
|
||||
return 'production';
|
||||
}
|
||||
|
||||
/** Shown on About screen for dev/staging builds only. */
|
||||
/** Shown on About screen for dev/staging builds only (never production Release). */
|
||||
export function shouldShowAboutBackendUrl(variant: AppVariant = appVariant): boolean {
|
||||
// Metro / 调试包:始终显示,避免 .env 误用 production variant 时看不到实际 API
|
||||
if (__DEV__) {
|
||||
return true;
|
||||
}
|
||||
return variant === 'development' || variant === 'staging';
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,12 @@ describe('shouldShowAboutBackendUrl', () => {
|
||||
expect(shouldShowAboutBackendUrl('staging')).toBe(true);
|
||||
});
|
||||
|
||||
it('hides backend URL for production', () => {
|
||||
expect(shouldShowAboutBackendUrl('production')).toBe(false);
|
||||
it('hides backend URL for production when not in __DEV__', () => {
|
||||
if (__DEV__) {
|
||||
expect(shouldShowAboutBackendUrl('production')).toBe(true);
|
||||
} else {
|
||||
expect(shouldShowAboutBackendUrl('production')).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('matches config.showAboutBackendUrl for current build', () => {
|
||||
|
||||
Reference in New Issue
Block a user