|
| 1 | +# iOS Deployment (TestFlight and App Store) |
| 2 | + |
| 3 | +This project now supports one-command iOS deployment through Fastlane. |
| 4 | + |
| 5 | +## Local deployment |
| 6 | + |
| 7 | +1. Install Ruby dependencies once: |
| 8 | + ```bash |
| 9 | + npm run ios:fastlane:install |
| 10 | + ``` |
| 11 | +2. Create local env vars file and load it: |
| 12 | + ```bash |
| 13 | + cp .env.example .env |
| 14 | + set -a; source .env; set +a |
| 15 | + ``` |
| 16 | +3. From repo root, run one of: |
| 17 | + ```bash |
| 18 | + npm run ios:deploy:testflight |
| 19 | + npm run ios:deploy:appstore |
| 20 | + ``` |
| 21 | + |
| 22 | +The commands build web assets, sync the Capacitor iOS project, archive the app, and upload to App Store Connect. |
| 23 | + |
| 24 | +## Required environment variables |
| 25 | + |
| 26 | +Set these for both local runs and GitHub Actions: |
| 27 | + |
| 28 | +- `APP_STORE_CONNECT_KEY_ID` |
| 29 | +- `APP_STORE_CONNECT_ISSUER_ID` |
| 30 | +- `APP_STORE_CONNECT_API_KEY` (base64-encoded `.p8` contents) |
| 31 | + |
| 32 | +Set these for GitHub Actions: |
| 33 | + |
| 34 | +- `IOS_DISTRIBUTION_CERTIFICATE_BASE64` (base64-encoded `.p12`) |
| 35 | +- `IOS_DISTRIBUTION_CERTIFICATE_PASSWORD` (password used when exporting `.p12`) |
| 36 | +- `IOS_APPSTORE_PROVISIONING_PROFILE_BASE64` (base64-encoded `.mobileprovision`) |
| 37 | +- `IOS_PROVISIONING_PROFILE_NAME` (profile name from Apple Developer) |
| 38 | +- `KEYCHAIN_PASSWORD` (any strong password used in CI keychain setup) |
| 39 | + |
| 40 | +Optional: |
| 41 | + |
| 42 | +- `APP_IDENTIFIER` (default: `ch.michaelschoenbaechler.parlwatch`) |
| 43 | +- `APPLE_TEAM_ID` (default: `65DUBW68Z2`) |
| 44 | + |
| 45 | +Local note: |
| 46 | + |
| 47 | +- Local deploy expects signing certificate/profile to already be available in your login keychain. |
| 48 | + |
| 49 | +## GitHub Actions deployment |
| 50 | + |
| 51 | +Use the `iOS Deploy` workflow (`.github/workflows/ios-deploy.yml`) and choose: |
| 52 | + |
| 53 | +- `testflight` to upload a build for testers |
| 54 | +- `appstore` to upload a build for App Store submission |
| 55 | + |
| 56 | +Add these repository secrets before running the workflow: |
| 57 | + |
| 58 | +- `APP_STORE_CONNECT_KEY_ID` |
| 59 | +- `APP_STORE_CONNECT_ISSUER_ID` |
| 60 | +- `APP_STORE_CONNECT_API_KEY` |
| 61 | +- `IOS_DISTRIBUTION_CERTIFICATE_BASE64` |
| 62 | +- `IOS_DISTRIBUTION_CERTIFICATE_PASSWORD` |
| 63 | +- `IOS_APPSTORE_PROVISIONING_PROFILE_BASE64` |
| 64 | +- `IOS_PROVISIONING_PROFILE_NAME` |
| 65 | +- `KEYCHAIN_PASSWORD` |
| 66 | + |
| 67 | +## Prepare values for GitHub secrets |
| 68 | + |
| 69 | +### 1) Create App Store Connect API key |
| 70 | + |
| 71 | +1. Open App Store Connect > Users and Access > Keys > App Store Connect API. |
| 72 | +2. Create a key with at least `App Manager` access. |
| 73 | +3. Save: |
| 74 | + - `Key ID` -> `APP_STORE_CONNECT_KEY_ID` |
| 75 | + - `Issuer ID` -> `APP_STORE_CONNECT_ISSUER_ID` |
| 76 | +4. Download `AuthKey_<KEYID>.p8` (only downloadable once). |
| 77 | +5. Convert to base64: |
| 78 | + ```bash |
| 79 | + base64 -i AuthKey_<KEYID>.p8 | tr -d '\n' |
| 80 | + ``` |
| 81 | +6. Use output as `APP_STORE_CONNECT_API_KEY`. |
| 82 | + |
| 83 | +### 2) Export distribution certificate as .p12 |
| 84 | + |
| 85 | +1. On a Mac where the iOS Distribution certificate is installed, open `Keychain Access`. |
| 86 | +2. In `My Certificates`, find your `Apple Distribution` certificate with private key. |
| 87 | +3. Right-click > Export > save as `.p12`. |
| 88 | +4. Set an export password. |
| 89 | +5. Convert `.p12` to base64: |
| 90 | + ```bash |
| 91 | + base64 -i distribution.p12 | tr -d '\n' |
| 92 | + ``` |
| 93 | +6. Use output as `IOS_DISTRIBUTION_CERTIFICATE_BASE64`. |
| 94 | +7. Use the export password as `IOS_DISTRIBUTION_CERTIFICATE_PASSWORD`. |
| 95 | + |
| 96 | +### 3) Download App Store provisioning profile |
| 97 | + |
| 98 | +1. Open Apple Developer > Certificates, IDs & Profiles > Profiles. |
| 99 | +2. Open your App Store profile for bundle id `ch.michaelschoenbaechler.parlwatch`. |
| 100 | +3. Download the `.mobileprovision` file. |
| 101 | +4. Copy profile name exactly (for `IOS_PROVISIONING_PROFILE_NAME`). |
| 102 | +5. Convert profile to base64: |
| 103 | + ```bash |
| 104 | + base64 -i profile.mobileprovision | tr -d '\n' |
| 105 | + ``` |
| 106 | +6. Use output as `IOS_APPSTORE_PROVISIONING_PROFILE_BASE64`. |
| 107 | + |
| 108 | +### 4) Choose keychain password for CI |
| 109 | + |
| 110 | +1. Generate any strong random value. |
| 111 | +2. Save it as `KEYCHAIN_PASSWORD`. |
| 112 | + |
| 113 | +## Add secrets in GitHub |
| 114 | + |
| 115 | +1. Open GitHub repository > `Settings` > `Secrets and variables` > `Actions`. |
| 116 | +2. Add these repository secret names exactly: |
| 117 | + - `APP_STORE_CONNECT_KEY_ID` |
| 118 | + - `APP_STORE_CONNECT_ISSUER_ID` |
| 119 | + - `APP_STORE_CONNECT_API_KEY` |
| 120 | + - `IOS_DISTRIBUTION_CERTIFICATE_BASE64` |
| 121 | + - `IOS_DISTRIBUTION_CERTIFICATE_PASSWORD` |
| 122 | + - `IOS_APPSTORE_PROVISIONING_PROFILE_BASE64` |
| 123 | + - `IOS_PROVISIONING_PROFILE_NAME` |
| 124 | + - `KEYCHAIN_PASSWORD` |
| 125 | +3. Trigger workflow: `Actions` > `iOS Deploy` > `Run workflow`. |
| 126 | +4. Select target: `testflight` or `appstore`. |
0 commit comments