We have a GitHub Action self-hosted runner compiler our app automatically, with a configuration looking like this:
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
Everything was working perfectly with EXPO_PUBLIC_ENV
, until we updated Expo from v51 to v52, and discovered a few days later that production was broken since it was pointing to staging server...
Any way to fix this?
We are consuming the EXPO_PUBLIC_ENV
env variable in typescript with process.env. EXPO_PUBLIC_ENV
, so nothing wrong on this side.
Also, here is the fastlane config:
platform :ios do
lane :staging do
distribute(app_identifier: "bundle_id.staging")
end
lane :production do
distribute(app_identifier: "bundle_id.staging")
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
I made a script to clean the cache manually. It's a bit hacky but it's the only way to clean the cache apparently (there is not way to do it without starting the app)
#! /bin/bash
set -m
# To clean the cache, we start with reset cache and kill it after 5 seconds
kill $(lsof -t -i:8081)
npm start -- --reset-cache &
sleep 5
kill -9 %1
I call the script in the Fastlane script before building the app.
I regret native development where everything was easy, you just read Info.plist or android flavor. No other middle software that breaks production.