iOS Certificates, Identifiers & Profiles Explained|Fastlane Match for Unified Certificate Management in CI/CD
Discover how to streamline iOS certificate issuance and management using Fastlane Match, integrating Certificates, Identifiers & Profiles seamlessly into your CI/CD pipeline for efficient app deployment.
This post was translated with AI assistance — let me know if anything sounds off!
Table of Contents
What are iOS Certificates, Identifiers & Profiles and Some Notes on Unified Management of Certificates and CI/CD with Fastlane Match
Introduction to the relationship between Certificates, Identifiers & Profiles and using Fastlane Match to centrally manage issued certificates and integrate them into the CI/CD workflow.
Photo by marcos mayer
Preface
In mid-2025, a series of articles was written on building a complete App CI/CD process from scratch using GitHub Actions:
Recently, I set up everything again in a new environment and learned new things each time. This time, I focused on iOS Codesigning: the relationship between Certificates, Profiles, and Devices, and how I use Fastlane Match to manage certificates and integrate with CI/CD.
What are Certificates, Identifiers & Profiles, and Devices?
In the Apple ecosystem, app development is based on certificate and profile management, unlike Android where having an .apk file is enough to install and use. Apple enforces strict certificate matching rules; if these are not met, the app cannot be installed or used.
Main Components and Their Functions:
Certificates: The identity used to sign the App (Signing Identity)
Development — Used on physical devices during the development phase (no certificates needed for simulators), belongs to a person or API Key (with quantity limits).
Distribution — Packaging for App Store, TestFlight, or Ad Hoc internal testing (limited to registered devices), with quantity limits, belongs to the Team.
Enterprise — For internal use within the enterprise.
Format : Requires both
Private KeyandCertificate .certo use, or exporting from the original creation computer’s Keychain as a.p12file will include both.
Identifiers: Which App/Extension (Bundle ID)
App’s Bundle ID registration and the required enabled Capabilities (such as Push Notifications, App Groups…) and App Services.
Extensions also have their own Identifier.
Devices: Registered Devices (iPhone/iPad, etc.)
Development running on physical devices and Distribution Ad Hoc internal testing can only be used on registered devices.
Limit: 100; including cancellations, the quota resets only at the start of each annual billing cycle.
Provisioning Profile (hereafter Profile):
Combination of Certificates + Identifiers + Devices Relationships.
Development — The provisioning profile used during the development phase. It is required for running tests on physical devices. The profile includes the relationship between Certificates, Identifiers, and Devices.
Ad Hoc — A provisioning profile for internal testing (e.g., Deploy to Firebase App Distribution), containing the relationship between Certificates, Identifiers, and Devices.
App Store — The provisioning profile used for packaging and uploading to the App Store / TestFlight, containing the relationship between Certificates and Identifiers.
Format:
.mobileprovision
Note: A Profile is just a description file that defines relationships; it does not contain the actual certificate.
Summary
Based on the above, to build on a clean machine without logging into the Xcode Apple Account for a physical device (Development Certificate) or to perform Archive packaging (Distribution Certificate), you must have two files:
.mobileprovisionProvisioning Profile: Describes the relationship between Certificates, Identifiers, and Devices..p12Certificate: The physical certificate (exported from the original computer where the certificate was created).
Additionally, for macOS ≥ 15, the Keychain has moved to:
1
open /System/Library/CoreServices/Applications/Keychain\ Access.app
Looked for a long time…
Common Errors
⚠️⚠️⚠️ Certificates and Profiles are confirmed correct but errors still occur:
Most likely, you still have leftover or multiple certificates from before, causing Xcode to get confused.
This issue is very common!
Close Xcode
Open macOS keychain:
open /System/Library/CoreServices/Applications/Keychain\ Access.applogin keychain -> All items -> search
apple development-> delete all CertificatesFinder -> Go -> Go to ->
~/Library/MobileDevice/Provisioning\ Profiles-> Delete all Profiles filesRe-pull Certificates
Restarting Xcode should fix the issue.
No signing certificate “iOS Distribution” found / No signing certificate “iOS Development” found:
No "iOS Distribution" signing certificate matching team ID "" with a private key was found.
No "iOS Development" signing certificate matching team ID "" with a private key was found.
Reason:
Missing iOS Distribution/iOS Development Certificate
Have an iOS Distribution/iOS Development Certificate but no corresponding Private Key
Solution:
Delete all old Certificates and Profiles from the Keychain
Find the certificate in the Keychain of the computer where the Certificate was originally created, export it as a
.p12file, and install it on the problematic computer.Go to Certificates, Identifiers & Profiles to revoke the old Certificate and generate a new one
(Don’t worry, this won’t affect the live app; it only impacts development and packaging stages)
Provisioning profile “” doesn’t include signing certificate “Apple Development: XXX”. / Provisioning profile “” doesn’t include signing certificate “Apple Distribution: XXX”.:
Reason:
- The currently selected Provisioning Profile does not match the current Certificate.
Solution:
Delete all old Certificates and Profiles from the Keychain
Go to Certificates, Identifiers & Profiles Profiles to ensure the profile has the corresponding certificate checked or regenerate the Profile for use.
No profile for team ‘’ matching ‘’ found: Xcode couldn’t find any provisioning profiles matching ‘’.:
Reason:
- Specified Provisioning Profile Not Found
Solution:
Delete all old Certificates and Profiles from the Keychain
Go to Certificates, Identifiers & Profiles to download the corresponding Profile for use
Provisioning profile “” has app ID “”, which does not match the bundle ID “”. / Provisioning profile doesn’t match the bundle identifier:
Reason:
- Provisioning profile does not include the current Bundle Identifier
Solution:
Delete all old Certificates and Profiles in the Keychain
Go to Certificates, Identifiers & Profiles and verify that the Bundle Identifier is registered under Identifiers.
Go to Certificates, Identifiers & Profiles to download the corresponding Profile for use
Provisioning profile “” doesn’t include the currently selected device “” (identifier ).:
Reason:
- Provisioning profile does not include the selected physical device’s Device Identifier
Solution:
Go to Certificates, Identifiers & Profiles Devices to confirm the physical device’s Identifier is registered.
Go to Certificates, Identifiers & Profiles and make sure the corresponding Profile has the physical device checked and enabled.
Re-download Profile for Use
Could not create another Development/Distribution certificate, reached the maximum number of available Development/Distribution certificates. :
Reason:
Indicates that the maximum number of Development/Distribution Certificates has been reached.
Solution:
- Go to Certificates, Identifiers & Profiles to delete unused certificates.
Xcode certificates are correct and packaging works fine, but signing errors occur when running packaging commands via CLI (Fastlane):
Reason:
Here I also ran into another issue: I foolishly placed the project in the iCloud sync folder, and for some reason, Fastlane kept showing certificate problems (suspected keychain access issues).
Solution:
Simply move out of the iCloud sync directory.
Common Issues in Daily Use
Development Certificate
Before adopting Match for unified certificate management, each developer creates their own
Development CertificateandDevelopment Profile; assuming there are 1,000+ developers in the organization, the Certificates, Identifiers & Profiles, Devices backend becomes extremely chaotic and unmanageable.If you have an outsourced team responsible only for development, you still need to add them to the Apple Developer Program backend so they can create their own development certificates and profiles.
Distribution Certificate
Distribution Certificates are created by the Team, so each developer program Team can only create a limited number of distribution certificates.
A common practice is for one engineer to create the Distribution Certificate and export the .p12 file to other developers who need to publish the app or to use it on the CI/CD machines.
When the team is large and there are many apps, sending certificates back and forth becomes very troublesome, and they need to be renewed every year.
When packaging Ad Hoc, if a new device is registered, everyone and the CI/CD must re-download the Profile for the new device to take effect.
Fastlane Match
Based on the above issues, we want a platform to manage everything related to certificates on our behalf. All developers and CI/CD services will pull and update data uniformly from this platform. The storage of this platform must be secure. This is — Fastlane Match.
Easily sync your certificates and profiles across your team
A new approach to iOS and macOS code signing: Share one code signing identity across your development team to simplify your code signing setup and prevent code signing issues.
match is the implementation of the codesigning.guide concept. match creates all required certificates & provisioning profiles and stores them in a separate git repository, Google Cloud, or Amazon S3. Every team member with access to the selected storage can use those credentials for code signing. match also automatically repairs broken and expired credentials. It’s the easiest way to share signing credentials across teams
Fastlane Match:
Interact with App Store Connect (via App Store Connect API or Apple Developer Login Session) to generate or update certificates
Encrypt and upload the certificate files (
.mobileprovisionProfiles,.p12Certificate,.cerCertificate) to the Git Repo (or other storage).
The.cerCertificate is also stored separately, as this allows verification of the certificate’s validity.If you want to divide permissions, you can use two Repos: one for managing Development certificates and another for Distribution certificates.
The
certsfolder contains all certificates with their private keysThe
profilesfolder contains all provisioning profiles
https://docs.fastlane.tools/actions/match/
Encryption Algorithm: AES-256-GCM
Developers, CI/CD Services:
Use the Fastlane match command to manage certificates consistently.
Fastlane Match will first fetch the certificate files from the Git repo and decrypt them for use. If it detects expired or unusable certificates and has Create/Write permissions, it will automatically regenerate and push them back to the repo; if it only has Read permission, it will report an error.
Create/Write:
Only the person responsible for managing certificates can generate, update, and push certificates.
Important Distribution Certificates should be stored in a separate repo accessible only by CI/CD services or administrators
Read:
Other developers and CI/CD services have read-only access to pull certificates.
The CI/CD service pulls the latest certificates before each task execution.
Everyone shares the same Development & Distribution Certificate.
After personnel changes, access to the Match Repo will be lost. You can revoke the old certificates and generate new ones. Others just need to pull again (if integrated with a make project script, it’s even smoother).
Fastlane Match Setup and Usage
Taking Git Storage as an example, all certificates.
1. Create an Empty Git Private Match Repo for Storing Certificates
Although all Certificates and Profiles are stored encrypted, you still need to set proper access permissions for the repo.
- Confirm that Git SSH access permissions are set up locally. You can use
git clone [email protected]:xxx/certificates.gitto verify.
It is recommended to use SSH Git Clone Repo consistently, as CI/CD will use the same method.
If running fastlane match gets stuck at
If cloning the repo takes too long, you can use theclone_branch_directlyoption in match., it is most likely an SSH permission issue.
- Run
bundle exec fastlane match initin the project directory to complete the setup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[21:54:32]: fastlane match supports multiple storage modes, please select the one you want to use:
1. git
2. google_cloud
3. s3
4. gitlab_secure_files
# Enter 1 to use git
? 1
[22:04:40]: Please create a new, private git repository to store the certificates and profiles there
[22:04:40]: URL of the Git Repo: git@github.com:xxx/certificates.git
# Enter the SSH URL of the Git Private Match Repo you created
[22:04:47]: Successfully created './fastlane/Matchfile'. You can open the file using a code editor.
[22:04:47]: You can now run `fastlane match development`, `fastlane match adhoc`, `fastlane match enterprise` and `fastlane match appstore`
[22:04:47]: On the first run for each environment it will create the provisioning profiles and
[22:04:47]: certificates for you. From then on, it will automatically import the existing profiles.
[22:04:47]: For more information visit https://docs.fastlane.tools/actions/match/
- After completion, a
fastlane/Matchfile: will be generated
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Your Git Private Match Repo SSH URL
git_url("[email protected]:xxxx/certificates.git")
storage_mode("git")
type("development") # The default type, can be: appstore, adhoc, enterprise or development
# app_identifier(["tools.fastlane.app", "tools.fastlane.app2"])
# username("[email protected]") # Your Apple Developer Portal username
# For all available options run `fastlane match --help`
# Remove the # at the beginning of the line to enable other options
# The docs are available on https://docs.fastlane.tools/actions/match
5. Generate App Store Connect API .p8 Key, use the API Key uniformly to create certificates:
⚠️️️️ App Store Connect API .p8 Key has extensive permissions. It can manage certificates, app submissions and reviews, as well as backend users, reviews, and financial reports.
Whether to include it in the team’s .git for everyone to access can be decided based on the team’s situation.
A higher security approach is to allow only the managers to handle it and store it encrypted for use in CI/CD (introduced later in the article).
For demo convenience, it is placed directly under the fastlane directory for access.
Also, the Fastlane script in this article is simplified for demonstration purposes and does not consider code duplication or structure.
Certificate Management
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
platform :ios do
lane :match_development do \\|options\\|
# Replace with your App Identifier ID
app_identifier = "li.zhgchg.myApp"
type = options.fetch(:type, "development")
isRead = options.fetch(:isRead, true)
if isRead
readonly = true
force = false
else
readonly = false
force = true
# App Store Connect API Key is required to manage certificates in Apple backend
# Assume the App Store Connect API .p8 Key is in the ./fastlane/ directory
app_store_connect_api_key(
key_id: "XXXXXX",
issuer_id: "XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX",
key_filepath: "./fastlane/AuthKey_XXXXXX.p8",
)
end
# Fetch Development certificates for app_identifier
match(
type: type,
app_identifier: app_identifier,
readonly: readonly, # Whether to update/upload cert/profile if needed
force: force # Whether to recreate provisioning profile unconditionally
)
end
end
Create Development Certificate & Profile and Upload to Match Repo:
1
bundle exec fastlane match_development type:development isRead:false
- No errors mean the Development Certificate & Profile were successfully created, installed, and pushed to the Match Repo.
The first time setup requires you to set a Passphrase:
1
2
3
4
[23:29:12]: Enter the passphrase that should be used to encrypt/decrypt your certificates
[23:29:12]: This passphrase is specific per repository and will be stored in your local keychain
[23:29:12]: Make sure to remember the password, as you'll need it when you run match on a different machine
[23:29:12]: Passphrase for Match storage:
This value is used as a reference for encrypting all the files in your Match Repo (passphrase + random salt).
It is recommended to generate a random string, set it, and record it.
Future updates or other users pulling the Match Repo certificates will need to enter this string to decrypt the original files.
Other team members uniformly pull the Development Certificate & Profile from the Match Repo:
1
bundle exec fastlane match_development type:development
The first time you use it, you will be asked for your login password (login keychain) because the certificate needs to be installed into the keychain. Just enter it twice to confirm:
1
2
3
4
5
6
7
8
9
10
[16:52:59]: Installing certificate...
[16:53:00]: There are no local code signing identities found.
You can run security find-identity -v -p codesigning to get this output.
This Stack Overflow thread has more information: https://stackoverflow.com/q/35390072/774.
(Check in Keychain Access for an expired WWDR certificate: https://stackoverflow.com/a/35409835/774 has more info.)
[16:53:00]: Enter the password for /Users/zhgchgli/Library/Keychains/login.keychain-db
[16:53:00]: This passphrase will be stored in your local keychain with the name fastlane_keychain_login and used in future runs
[16:53:00]: This prompt can be avoided by specifying the 'keychain_password' option or 'MATCH_KEYCHAIN_PASSWORD' environment variable
[16:53:00]: Password for login keychain: ********
[16:53:24]: Type password for login keychain again: ********
If Match Development has fetched the certificates, but Xcode still shows errors or invalid status:
You can refer to the common errors mentioned earlier. Most are caused by old, corrupted certificates. Clearing all certificates and then fetching them again should resolve the issue.
—
Create AdHoc Distribution Certificate & Profile and Upload to Match Repo:
1
bundle exec fastlane match_development type:adhoc isRead:false
Create AppStore Distribution Certificate & Profile and Upload to Match Repo:
1
bundle exec fastlane match_development type:appstore isRead:false
CI/CD services uniformly pull Distribution Certificate & Profile ( isRead:true ) from the Match Repo, then execute the build and release tasks.
Register a New Device
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
platform :ios do
desc "Register a new device and refresh profiles"
lane :registerDevice do \\|options\\|
# Replace with your App Identifier ID
app_identifier = "li.zhgchg.myApp"
# App Store Connect API Key is required to manage certificates in Apple backend
# Assume the App Store Connect API .p8 Key is in the ./fastlane/ directory
app_store_connect_api_key(
key_id: "XXXXXX",
issuer_id: "XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX",
key_filepath: "./fastlane/AuthKey_XXXXXX.p8",
)
# Input: UDID and device name
udid = options[:udid] \\|\\| UI.input("Enter device UDID:")
device_name = options[:name] \\|\\| UI.input("Enter device name:")
UI.message("📱 Registering device #{device_name} (#{udid})")
register_device(
name: device_name,
udid: udid,
platform: 'ios'
)
# Update Development certificates for app_identifier
match(
type: "development",
app_identifier: app_identifier,
readonly: false, # Update and upload cert/profile if needed
force_for_new_devices: true # Recreate provisioning profile for new devices
)
# Update AdHoc certificates for app_identifier
match(
type: "adhoc",
app_identifier: app_identifier,
readonly: false, # Update and upload cert/profile if needed
force_for_new_devices: true # Recreate provisioning profile for new devices
)
end
end
After registration, other developers or CI/CD services pulling the Profile (Development or AdHoc) from the Match Repo will include the new devices.
Fastlane Match x CI/CD Workflow Integration
After a general introduction to how Fastlane Match generates Push and Pull certificates, next is to explain how to integrate it into the CI/CD process.
Question 1 — How to Clone Private Match Repo
The most common issue is how to clone the private Match repo in CI/CD. On local development, we use SSH git clone with our own account’s SSH key, so there is no problem. However, CI/CD does not have this key. Although you can use a personal key, it is not secure.
GitHub — Repo Deploy Key:
First, generate the private/public key locally:
ssh-keygen -t rsa -b 4096 -f ./id_rsa( do NOT enter apassphrase)Go to Match Private Repo -> Settings -> Security -> Deploy keys -> Add deploy key:
- Open
id_rsa.pubwith a text editor, copy the content, and paste it into Key -> “Add key”
- Go back to the main Repo -> Settings -> Security -> Secrets and variables
- Add SSH Private Key Content to Secret:
- Name:
MATCH_REPO_DEPLOY_PRIVATE_KEY
- Back to the main repo’s GitHub Actions setting SSH Key:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
name: CI - Deploy
on:
push:
branches: [ main ]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout current repo (Repo A)
uses: actions/checkout@v4
- name: Setup SSH for Deploy Key
run: \\|
mkdir -p ~/.ssh
echo "${{ secrets.MATCH_REPO_DEPLOY_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Test Clone
run: \\|
git clone [email protected]:xxxx/match-certificates.git
# Success!
# .. do deploy job...
- Setup Successful!
Question 2 — Secure Storage and Use of App Store Connect API .p8 Key
Because GitHub Actions cannot store files directly, you must first save as a string and then write it to a file.
Same as step 1, add an
APP_STORE_CONNECT_API_KEY_CONTENTSecret in the main Repo.Open
AuthKey_XXXXXX.p8with a text editor, then copy and paste the content.Add a step in the main repo’s GitHub Actions to read content and write to a file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
name: CI - Deploy
on:
push:
branches: [ main ]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout current repo (Repo A)
uses: actions/checkout@v4
- name: Setup SSH for Deploy Key
run: \\|
mkdir -p ~/.ssh
echo "${{ secrets.MATCH_REPO_DEPLOY_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Write Secret Key to File
env:
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: \\|
# ensure fastlane directory exists
mkdir -p ./fastlane
# create file path
APP_STORE_CONNECT_API_KEY_PATH=./fastlane/AuthKey_XXXXXX.p8
# write content to file (keep newline)
echo "$APP_STORE_CONNECT_API_KEY_CONTENT" > "$APP_STORE_CONNECT_API_KEY_PATH"
# (optional) restrict permissions
chmod 600 "$APP_STORE_CONNECT_API_KEY_PATH"
- name: Deploy to Firebase
env:
MATCH_PASSWORD: "${{ secrets.MATCH_PASSWORD }}"
run: bundle exec fastlane deploy_to_firebase
Issue 3 — Setting a Passphrase for the Private Match Repo to Prevent Prompt Interruptions During Match
For the same step as Question 1, add
MATCH_PASSWORDto Secrets in the main RepoEnter the
Passphrasefor the Fastlane Match Repo you configuredAdd
env: secret.MATCH_PASSWORDto the main repo’s GitHub Actions:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
name: CI - Deploy
on:
push:
branches: [ main ]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout current repo (Repo A)
uses: actions/checkout@v4
- name: Setup SSH for Deploy Key
run: \\|
mkdir -p ~/.ssh
echo "${{ secrets.MATCH_REPO_DEPLOY_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Write Secret Key to File
env:
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: \\|
# ensure fastlane directory exists
mkdir -p ./fastlane
# create file path
APP_STORE_CONNECT_API_KEY_PATH=./fastlane/AuthKey_XXXXXX.p8
# write content to file (keep newline)
echo "$APP_STORE_CONNECT_API_KEY_CONTENT" > "$APP_STORE_CONNECT_API_KEY_PATH"
# (optional) restrict permissions
chmod 600 "$APP_STORE_CONNECT_API_KEY_PATH"
- name: Deploy to Firebase
env:
MATCH_PASSWORD: "${{ secrets.MATCH_PASSWORD }}"
run: bundle exec fastlane deploy_to_firebase
Question 4 — Keychain Handling on Self-hosted Runner
Unlike cloud machines that are always clean and new each time, with Self-hosted Runner we can specify derived_data_path, output_directory, buildlog_path, and reinstall_app in Fastlane to ensure a clean environment for each run; however, Certificates and Profiles are installed in the system Keychain app. How should we handle this?
Actually, Fastlane has considered this for us. You can create a clean Keychain before running Match:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
name: CI - Deploy
on:
push:
branches: [ main ]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout current repo (Repo A)
uses: actions/checkout@v4
- name: Setup SSH for Deploy Key
run: \\|
mkdir -p ~/.ssh
echo "${{ secrets.MATCH_REPO_DEPLOY_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Write Secret Key to File
env:
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: \\|
# ensure fastlane directory exists
mkdir -p ./fastlane
# create file path
APP_STORE_CONNECT_API_KEY_PATH=./fastlane/AuthKey_XXXXXX.p8
# write content to file (keep newline)
echo "$APP_STORE_CONNECT_API_KEY_CONTENT" > "$APP_STORE_CONNECT_API_KEY_PATH"
# (optional) restrict permissions
chmod 600 "$APP_STORE_CONNECT_API_KEY_PATH"
- name: Create fastlane keychain
env:
KEYCHAIN_NAME: "${{ runner.name }}"
MATCH_PASSWORD: "${{ secrets.MATCH_PASSWORD }}"
run: \\|
bundle exec fastlane run create_keychain \
name:"$KEYCHAIN_NAME" \
password:"$MATCH_PASSWORD" \
unlock:true \
timeout:0 \
lock_when_sleeps:false
- name: Deploy to Firebase
env:
MATCH_PASSWORD: "${{ secrets.MATCH_PASSWORD }}"
KEYCHAIN_NAME: "${{ runner.name }}"
run: bundle exec fastlane deploy_to_firebase
# 🔥 This will run regardless of success or failure above
- name: Delete fastlane keychain
if: always()
env:
KEYCHAIN_NAME: ${{ runner.name }}
run: \\|
bundle exec fastlane run delete_keychain \
name:"$KEYCHAIN_NAME"
Each Runner only executes one job at a time, so we use the Runner Name as the Keychain Name. Each Runner will have its own Keychain.
Deleted regardless of success or failure after execution
I did not set a separate
keychain_password; I usedMATCH_PASSWORDuniformly.
Add keychain parameters to the match method in Fastlane/Fastfile:
1
2
3
4
5
6
7
8
9
10
#...
match(
type: "adhoc",
app_identifier: app_identifier,
readonly: false, # Update and upload cert/profile if needed
force_for_new_devices: true, # Recreate provisioning profile for new devices
keychain_name: ENV['KEYCHAIN_NAME'], # default value: nil
keychain_password: ENV['MATCH_PASSWORD'] # default value: nil
)
#...
This way, when Match fetches certificates, it will save them to the specified Keychain instead of the shared login keychain.
Conclusion
The scope of Fastlane is very broad, so here I will only document the process of using Fastlane Match; other lanes like testing, packaging, and publishing will be covered in a separate article if there is a chance. I will also add more Match-related issues and cases as they come up! Feel free to leave questions in the comments!
Further Reading
Please kindly proceed to read. 🤞🏻
If you have any questions or feedback, feel free to contact me.
This post was originally published on Medium (View original post), and automatically converted and synced by ZMediumToMarkdown.











