Skip to content

Commit daf48cd

Browse files
committed
Switch iOS CI to automatic code signing with App Store Connect API key
Replaced manual provisioning profile with an App Store Connect API key for CI, enabling Xcode to manage profiles via `-allowProvisioningUpdates` and simplifying the process by removing manual profile rotation. Local builds remain compatible with automatic signing.
1 parent 4dffc38 commit daf48cd

4 files changed

Lines changed: 34 additions & 28 deletions

File tree

.github/workflows/ios-build-test-macos.yml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,18 @@ jobs:
6767
path: /tmp/bazel_cache
6868
key: ${{ runner.os }}-bazel_cache-${{ hashFiles('**/BUILD', '**/WORKSPACE') }}
6969
restore-keys: ${{ runner.os }}-bazel_cache-
70-
- name: Install the Apple certificate and provisioning profile
70+
- name: Install the Apple certificate and API key
7171
env:
7272
IOS_BUILD_CERTIFICATE_BASE64: ${{ secrets.IOS_BUILD_CERTIFICATE_BASE64 }}
7373
IOS_BUILD_CERTIFICATE_PASSWORD: ${{ secrets.IOS_BUILD_CERTIFICATE_PASSWORD }}
74-
IOS_BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.IOS_BUILD_PROVISION_PROFILE_BASE64 }}
7574
IOS_KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }}
75+
APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }}
7676
run: |
7777
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
78-
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
7978
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
8079
8180
echo -n "$IOS_BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
82-
echo -n "$IOS_BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
81+
echo -n "$APP_STORE_CONNECT_API_KEY_BASE64" | base64 --decode -o $RUNNER_TEMP/AuthKey.p8
8382
8483
security create-keychain -p "$IOS_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
8584
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
@@ -88,9 +87,6 @@ jobs:
8887
security import $CERTIFICATE_PATH -P "$IOS_BUILD_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
8988
security set-key-partition-list -S apple-tool:,apple: -k "$IOS_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
9089
security list-keychain -d user -s $KEYCHAIN_PATH
91-
92-
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
93-
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
9490
- name: Build iOS app
9591
env:
9692
BAZEL_OUTPUT_ROOT_ARG: "--output_user_root=/tmp/bazel_output"
@@ -103,6 +99,9 @@ jobs:
10399
- name: Build iOS test package
104100
env:
105101
DEVELOPMENT_TEAM: ${{ secrets.APPLE_DEVELOPMENT_TEAM }}
102+
APP_STORE_CONNECT_API_KEY_PATH: ${{ runner.temp }}/AuthKey.p8
103+
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
104+
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
106105
run: |
107106
make flutter/ios/test-package
108107
- name: Upload test package artifact
@@ -112,11 +111,11 @@ jobs:
112111
path: output/ios-test-package/*.zip
113112
retention-days: 28
114113
if-no-files-found: error
115-
- name: Clean up keychain and provisioning profile
114+
- name: Clean up keychain and API key
116115
if: ${{ always() }}
117116
run: |
118117
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
119-
rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.mobileprovision
118+
rm -f $RUNNER_TEMP/AuthKey.p8
120119
121120
test-ios-browserstack:
122121
name: ${{ matrix.backend }}-${{ matrix.device }}

docs/browserstack-testing.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,11 @@ make flutter/ios/test-package
6767
This produces `output/ios-test-package/ios_tests.zip` containing the
6868
`Release-iphoneos/` directory and `*.xctestrun` file.
6969

70-
**Note:** `build-for-testing` requires code signing. By default it uses
71-
`CODE_SIGN_IDENTITY="Apple Development"` and the team configured in the
72-
Xcode project. Override via environment variables if needed:
70+
**Note:** `build-for-testing` requires code signing. The build uses automatic
71+
signing with `-allowProvisioningUpdates`. Locally, Xcode resolves profiles
72+
using your Apple account. In CI, an App Store Connect API key is passed via
73+
`-authenticationKeyPath` so Xcode can download profiles automatically.
74+
Override the team via environment variables if needed:
7375

7476
```bash
7577
DEVELOPMENT_TEAM=XXXXXXXXXX make flutter/ios/test-package

docs/github-workflows-setup/ios-browserstack-workflow-setup.md

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ for a detailed walkthrough.
3535

3636
| Secret | Where to get it |
3737
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
38-
| `IOS_BUILD_CERTIFICATE_BASE64` | Export a Development certificate (.p12) from Keychain Access or Xcode app, then base64-encode it: `base64 -i build_certificate.p12 \| pbcopy` |
39-
| `IOS_BUILD_CERTIFICATE_PASSWORD` | The password you set when exporting the .p12 certificate. |
40-
| `IOS_BUILD_PROVISION_PROFILE_BASE64` | Download the provisioning profile (.mobileprovision) from [Apple Developer > Profiles](https://developer.apple.com/account/resources/profiles/list). It must include the app's bundle ID (`com.mlcommons.inference`). Base64-encode it: `base64 -i profile.mobileprovision \| pbcopy` |
41-
| `IOS_KEYCHAIN_PASSWORD` | Any random password for the temporary CI keychain. Generate one with: `openssl rand -base64 32` |
42-
| `APPLE_DEVELOPMENT_TEAM` | Your 10-character Apple Team ID. Find it at [Apple Developer > Membership details](https://developer.apple.com/account#MembershipDetailsCard) or in Xcode under **Signing & Capabilities**. |
38+
| `IOS_BUILD_CERTIFICATE_BASE64` | Export a Development certificate (.p12) from Keychain Access or Xcode app, then base64-encode it: `base64 -i build_certificate.p12 \| pbcopy` |
39+
| `IOS_BUILD_CERTIFICATE_PASSWORD` | The password you set when exporting the .p12 certificate. |
40+
| `IOS_KEYCHAIN_PASSWORD` | Any random password for the temporary CI keychain. Generate one with: `openssl rand -base64 32` |
41+
| `APPLE_DEVELOPMENT_TEAM` | Your 10-character Apple Team ID. Find it at [Apple Developer > Membership details](https://developer.apple.com/account#MembershipDetailsCard) or in Xcode under **Signing & Capabilities**. |
42+
| `APP_STORE_CONNECT_API_KEY_BASE64` | Base64-encoded App Store Connect API key (.p8 file). See steps below. |
43+
| `APP_STORE_CONNECT_API_KEY_ID` | The Key ID shown in App Store Connect when creating the API key. |
44+
| `APP_STORE_CONNECT_API_KEY_ISSUER_ID` | The Issuer ID from [App Store Connect > Users and Access > Integrations > App Store Connect API](https://appstoreconnect.apple.com/access/integrations/api). |
4345

4446
### Firebase
4547

@@ -64,7 +66,7 @@ under **Project Settings > General > Your apps > iOS app**.
6466
|---|---|
6567
| `FLUTTER_BUILD_NUMBER_OFFSET` | Optional offset added to `GITHUB_RUN_NUMBER` to compute the build number. Set this if you need to align build numbers across workflows. Default: `0`. |
6668

67-
## Step-by-step: Creating the Apple certificate and provisioning profile
69+
## Step-by-step: Creating the Apple certificate and API key
6870

6971
### 1. Create a certificate signing request (CSR)
7072

@@ -88,19 +90,20 @@ under **Project Settings > General > Your apps > iOS app**.
8890
```
8991
- Save the base64 string as `IOS_BUILD_CERTIFICATE_BASE64` and the password as `IOS_BUILD_CERTIFICATE_PASSWORD`
9092

91-
### 4. Create a provisioning profile
93+
### 4. Create an App Store Connect API key
9294

93-
- Go to [Apple Developer > Profiles](https://developer.apple.com/account/resources/profiles/list)
94-
- Click **+**, select **iOS App Development**
95-
- Select the App ID matching `com.mlcommons.inference`
96-
- Select the certificate created in step 2
97-
- Select the devices to test on (or select all)
98-
- Download the `.mobileprovision` file
99-
- Base64-encode it:
95+
- Go to [App Store Connect > Users and Access > Integrations > App Store Connect API](https://appstoreconnect.apple.com/access/integrations/api)
96+
- Click **+** to generate a new key
97+
- Give it a name (e.g. `CI Signing`) and select the **Developer** role
98+
- Download the `.p8` file (you can only download it once)
99+
- Note the **Key ID** and **Issuer ID** shown on the page
100+
- Base64-encode the key:
100101
```bash
101-
base64 -i profile.mobileprovision | pbcopy
102+
base64 -i AuthKey_XXXXXXXXXX.p8 | pbcopy
102103
```
103-
- Save as `IOS_BUILD_PROVISION_PROFILE_BASE64`
104+
- Save the base64 string as `APP_STORE_CONNECT_API_KEY_BASE64`
105+
- Save the Key ID as `APP_STORE_CONNECT_API_KEY_ID`
106+
- Save the Issuer ID as `APP_STORE_CONNECT_API_KEY_ISSUER_ID`
104107

105108
### 5. Set the keychain password
106109

flutter/ios/ios.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ flutter/ios/test-package/build:
6767
-config Flutter/Release.xcconfig \
6868
-derivedDataPath ../build/ios_integration \
6969
-sdk iphoneos \
70+
-allowProvisioningUpdates \
7071
CODE_SIGN_IDENTITY="$${CODE_SIGN_IDENTITY:-Apple Development}" \
7172
$$(if [ -n "$${DEVELOPMENT_TEAM}" ]; then echo "DEVELOPMENT_TEAM=$${DEVELOPMENT_TEAM}"; fi) \
73+
$$(if [ -n "$${APP_STORE_CONNECT_API_KEY_PATH}" ]; then echo "-authenticationKeyPath $${APP_STORE_CONNECT_API_KEY_PATH} -authenticationKeyID $${APP_STORE_CONNECT_API_KEY_ID} -authenticationKeyIssuerID $${APP_STORE_CONNECT_API_KEY_ISSUER_ID}"; fi) \
7274
build-for-testing
7375

7476
FLUTTER_IOS_TEST_PACKAGE?=ios_tests-${FLUTTER_BUILD_NUMBER}.zip

0 commit comments

Comments
 (0)