Expo v52升级后CI中EXPO_PUBLIC_ENV缓存致生产环境异常求助
问题:Expo v52升级后生产环境指向Staging服务器
我们使用GitHub Action自托管Runner自动编译应用,配置如下:
name: Build jobs: deploy-ios: runs-on: [ self-hosted, macOS ] env: LANG: en_US.UTF-8 MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} P8_AUTH_KEY: ${{ secrets.P8_AUTH_KEY }} APPSTORE_KEY_ID: ${{ secrets.APPSTORE_KEY_ID }} APPSTORE_ISSUER_ID: ${{ secrets.APPSTORE_ISSUER_ID }} steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 - uses: webfactory/ssh-agent@v0.5.0 with: ssh-private-key: ${{ secrets.MATCH_REPO_KEY }} - name: Set up node environment uses: actions/setup-node@v3 with: node-version: '18' - name: Install dependencies run: npm install && npm install typescript -g && npx expo prebuild && bundle install - name: Install iOS dependencies run: cd ios && pod install - name: Setup keys run: | echo "${{ secrets.ENV_FILE }}" > .env echo "${{ secrets.P8_AUTH_KEY }}" | base64 -d > fastlane/key.p8 - name: Build and deploy (STAGING) env: EXPO_PUBLIC_ENV: staging run: bundle exec fastlane ios staging - name: Build and deploy (PRODUCTION) env: EXPO_PUBLIC_ENV: production run: bundle exec fastlane ios production
原本EXPO_PUBLIC_ENV运行完全正常,但升级Expo到v52后,生产环境出现故障,原因是它指向了staging服务器。我们在TypeScript中通过process.env.EXPO_PUBLIC_ENV读取该环境变量,这部分逻辑没有问题。
以下是fastlane配置:
platform :ios do lane :staging do distribute(app_identifier: "bundle_id.staging") end lane :production do distribute(app_identifier: "bundle_id") end lane :distribute do |options| app_identifier = options[:app_identifier] scheme = "Scheme" xcodeproj = "ios/App.xcodeproj" workspace = "ios/App.xcworkspace" plist = "App/Info.plist" fullPlist = "ios/App/Info.plist" setup_ci api_key = app_store_connect_api_key( key_id: ENV["APPSTORE_KEY_ID"], issuer_id: ENV["APPSTORE_ISSUER_ID"], key_filepath: "fastlane/key.p8" ) update_app_identifier( xcodeproj: xcodeproj, plist_path: plist, app_identifier: app_identifier ) increment_build_number( build_number: number_of_commits, xcodeproj: xcodeproj ) update_plist( plist_path: fullPlist, block: proc do |plist| plist[:ITSAppUsesNonExemptEncryption] = false end ) match update_code_signing_settings( use_automatic_signing: false, team_id: "TEAM_ID", profile_name: "match AppStore #{app_identifier}", code_sign_identity: "iPhone Distribution", path: xcodeproj ) build_app( clean: true, scheme: scheme, workspace: workspace, xcargs: "-allowProvisioningUpdates" ) upload_to_testflight( api_key: api_key, app_identifier: app_identifier, skip_waiting_for_build_processing: true ) clean_build_artifacts end end
问题根源
Expo v52调整了EXPO_PUBLIC_*环境变量的处理逻辑:
- v51及之前,这类变量会在构建阶段由Webpack动态注入
- v52开始,
expo prebuild会直接将EXPO_PUBLIC_*变量写入原生项目配置文件(如Info.plist),后续构建不再读取环境变量
你的原流程中expo prebuild只执行一次,且执行时未设置EXPO_PUBLIC_ENV;后续staging构建时设置的变量被写入配置后,production构建未重新执行prebuild,导致沿用了staging的变量值。
修复方案
方案1:拆分Staging与Production构建流程
将两个环境的构建拆分为独立Job,各自完整执行prebuild、依赖安装和构建步骤,彻底隔离环境变量:
name: Build jobs: deploy-ios-staging: runs-on: [ self-hosted, macOS ] env: LANG: en_US.UTF-8 MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} P8_AUTH_KEY: ${{ secrets.P8_AUTH_KEY }} APPSTORE_KEY_ID: ${{ secrets.APPSTORE_KEY_ID }} APPSTORE_ISSUER_ID: ${{ secrets.APPSTORE_ISSUER_ID }} EXPO_PUBLIC_ENV: staging steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 - uses: webfactory/ssh-agent@v0.5.0 with: ssh-private-key: ${{ secrets.MATCH_REPO_KEY }} - name: Set up node environment uses: actions/setup-node@v3 with: node-version: '18' - name: Install dependencies run: npm install && npm install typescript -g && npx expo prebuild && bundle install - name: Install iOS dependencies run: cd ios && pod install - name: Setup keys run: | echo "${{ secrets.ENV_FILE }}" > .env echo "${{ secrets.P8_AUTH_KEY }}" | base64 -d > fastlane/key.p8 - name: Build and deploy (STAGING) run: bundle exec fastlane ios staging deploy-ios-production: runs-on: [ self-hosted, macOS ] env: LANG: en_US.UTF-8 MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} P8_AUTH_KEY: ${{ secrets.P8_AUTH_KEY }} APPSTORE_KEY_ID: ${{ secrets.APPSTORE_KEY_ID }} APPSTORE_ISSUER_ID: ${{ secrets.APPSTORE_ISSUER_ID }} EXPO_PUBLIC_ENV: production steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 - uses: webfactory/ssh-agent@v0.5.0 with: ssh-private-key: ${{ secrets.MATCH_REPO_KEY }} - name: Set up node environment uses: actions/setup-node@v3 with: node-version: '18' - name: Install dependencies run: npm install && npm install typescript -g && npx expo prebuild && bundle install - name: Install iOS dependencies run: cd ios && pod install - name: Setup keys run: | echo "${{ secrets.ENV_FILE }}" > .env echo "${{ secrets.P8_AUTH_KEY }}" | base64 -d > fastlane/key.p8 - name: Build and deploy (PRODUCTION) run: bundle exec fastlane ios production
方案2:每个构建步骤前重新执行Prebuild
如果不想拆分Job,可在每个构建步骤前清理并重新执行prebuild,确保环境变量正确注入:
# 前面步骤保持不变 - name: Setup keys run: | echo "${{ secrets.ENV_FILE }}" > .env echo "${{ secrets.P8_AUTH_KEY }}" | base64 -d > fastlane/key.p8 - name: Build and deploy (STAGING) env: EXPO_PUBLIC_ENV: staging run: | npx expo prebuild --clean cd ios && pod install bundle exec fastlane ios staging - name: Clean staging artifacts run: | rm -rf ios rm -rf node_modules/.cache - name: Build and deploy (PRODUCTION) env: EXPO_PUBLIC_ENV: production run: | npx expo prebuild --clean cd ios && pod install bundle exec fastlane ios production
方案3:通过XCArgs传递环境变量
修改fastlane的build_app步骤,通过xcargs直接传递环境变量,覆盖prebuild阶段的配置:
build_app( clean: true, scheme: scheme, workspace: workspace, xcargs: "-allowProvisioningUpdates EXPO_PUBLIC_ENV=#{ENV['EXPO_PUBLIC_ENV']}" )
内容的提问来源于stack exchange,提问作者Nathan Fallet
相关产品推荐
相关产品推荐

