Skip to content

Commit 63597a8

Browse files
Merge pull request #5 from HekmatullahAmin/enhance/firebase-ios-action-appstore-connect-support
Add appstore connect inputs to firebase distribution action and updated README.md
2 parents d3ea8c5 + 0a954ec commit 63597a8

File tree

2 files changed

+178
-87
lines changed

2 files changed

+178
-87
lines changed

README.md

Lines changed: 157 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# KMP Publish iOS App on Firebase Action
22

3-
This GitHub Action automates the process of building and publishing iOS applications to Firebase App Distribution. It handles the build process, signing, and deployment using Fastlane.
3+
This GitHub Action automates the process of building and publishing iOS applications to Firebase App
4+
Distribution. It handles the build process, signing, and deployment using Fastlane.
45

56
## Features
67

@@ -25,15 +26,20 @@ Before using this action, ensure you have:
2526
## Setup
2627

2728
### SSH Key Setup
29+
2830
1. Generate SSH Key Locally<br>
2931
In your terminal, run:
32+
3033
```yaml
3134
ssh-keygen -t ed25519 -C "your_email@example.com"
3235
```
36+
3337
It will ask for a file path. Press enter a custom path like:
38+
3439
```yaml
3540
~/.ssh/match_ci_key
3641
```
42+
3743
You can skip setting a passphrase when prompted (just hit enter twice).
3844

3945
This generates two files:
@@ -44,11 +50,14 @@ This generates two files:
4450

4551
2. Add the Private Key to the SSH Agent (optional but helpful)
4652
This step ensures the key is used during local development.
53+
4754
```yaml
4855
eval "$(ssh-agent -s)"
4956
ssh-add ~/.ssh/match_ci_key
5057
```
58+
5159
3. Add the Public Key to Your Certificates Repo (GitHub)
60+
5261
- Go to your certificates repo on GitHub (e.g., openMF/ios-provisioning-profile).
5362
- Go to Settings → Deploy Keys.
5463
- Click “Add deploy key”.
@@ -57,22 +66,26 @@ ssh-add ~/.ssh/match_ci_key
5766
```yaml
5867
cat ~/.ssh/match_ci_key.pub
5968
```
69+
6070
- Check **Allow write access**.
6171
- Click Add key.
6272

6373
4. Convert the Private Key to Base64
6474
This is how we pass it to GitHub Actions securely.
75+
6576
```yaml
6677
base64 -i ~/.ssh/match_ci_key | pbcopy
6778
```
79+
6880
This command copies the base64-encoded private key to your clipboard (macOS).
6981

7082
5. Save the Private Key as a GitHub Secret
83+
7184
- Go to the repo with your Fastfile (the project repo, not the certs repo).
7285
- Navigate to Settings → Secrets and variables → Actions → New repository secret.
7386
- Add the following:
74-
- Name: MATCH_SSH_PRIVATE_KEY
75-
- Value: Paste the base64-encoded private key
87+
- Name: MATCH_SSH_PRIVATE_KEY
88+
- Value: Paste the base64-encoded private key
7689

7790
### Fastlane Setup
7891

@@ -91,60 +104,92 @@ Create a `fastlane/Fastfile` with the following content:
91104
default_platform(:ios)
92105

93106
platform :ios do
94-
desc "Deploy to Firebase App Distribution"
95-
lane :deploy_on_firebase do |options|
96-
97-
firebase_app_id = options[:firebase_app_id] || ENV["FIREBASE_APP_ID"]
98-
match_type = options[:match_type] || ENV["MATCH_TYPE"]
99-
app_identifier = options[:app_identifier] || ENV["APP_IDENTIFIER"]
100-
git_url = options[:git_url] || ENV["GIT_URL"]
101-
git_branch = options[:git_branch] || ENV["GIT_BRANCH"]
102-
match_password = options[:match_password] || ENV["MATCH_PASSWORD"]
103-
git_private_key = options[:git_private_key] || ENV["GIT_PRIVATE_KEY"] || "./secrets/match_ci_key"
104-
groups = options[:groups] || ENV["GROUPS"]
105-
serviceCredsFile = options[:serviceCredsFile] || ENV["SERVICE_CREDS_FILE"]
107+
desc "Deploy iOS app to Firebase App Distribution"
108+
lane :deploy_on_firebase do |options|
109+
# === Variables at top ===
110+
firebase_app_id = options[:firebase_app_id] || "1:xxxxxx:ios:xxxxxxxx"
111+
match_type = options[:match_type] || "adhoc"
112+
app_identifier = options[:app_identifier] || "com.example.myapp"
113+
git_url = options[:git_url] || "git@github.com:openMF/ios-provisioning-profile.git"
114+
git_branch = options[:git_branch] || "master"
115+
match_password = options[:match_password] || "your-default-match-password"
116+
git_private_key = options[:git_private_key] || "./secrets/match_ci_key"
117+
groups = options[:tester_groups] || "qa-team,beta-testers"
118+
serviceCredsFile = options[:serviceCredsFile] || "secrets/firebaseAppDistributionServiceCredentialsFile.json"
119+
provisioning_profile_name = options[:provisioning_profile_name] || "match AdHoc com.example.myapp"
120+
appstore_key_id = options[:appstore_key_id] || "DEFAULT_KEY_ID"
121+
appstore_issuer_id = options[:appstore_issuer_id] || "DEFAULT_ISSUER_ID"
122+
key_filepath = options[:key_filepath] || "secrets/Auth_key.p8"
106123

107-
setup_ci(
108-
provider: "circleci"
109-
)
124+
# === Setup CI ===
125+
unless ENV['CI']
126+
UI.message("🖥️ Running locally, skipping CI-specific setup.")
127+
else
128+
setup_ci(provider: "circleci")
129+
end
110130

111-
latest_release = firebase_app_distribution_get_latest_release(
112-
app: firebase_app_id,
113-
service_credentials_file: options[:serviceCredsFile] || firebase_config[:serviceCredsFile]
114-
)
115-
116-
if latest_release
117-
increment_build_number(
118-
xcodeproj: iosApp/iosApp.xcodeproj,
119-
build_number: latest_release[:buildVersion].to_i + 1
120-
)
121-
else
122-
UI.important("⚠️ No existing Firebase release found. Skipping build number increment.")
123-
end
124-
125-
match(
126-
type: match_type,
127-
app_identifier: app_identifier,,
128-
readonly: true,
129-
git_url: git_url,
130-
git_branch: git_branch,
131-
git_private_key: git_private_key
132-
)
131+
# === Load API Key ===
132+
app_store_connect_api_key(
133+
key_id: appstore_key_id,
134+
issuer_id: appstore_issuer_id,
135+
key_filepath: key_filepath,
136+
duration: 1200
137+
)
133138

134-
build_ios_app(
135-
scheme: "iosApp",
136-
project: "iosApp/iosApp.xcodeproj",
137-
output_name: "DeployIosApp.ipa",
138-
output_directory: "iosApp/build",
139-
)
139+
# === Fetch Match certs ===
140+
match(
141+
type: match_type,
142+
app_identifier: app_identifier,
143+
readonly: false,
144+
git_url: git_url,
145+
git_branch: git_branch,
146+
git_private_key: git_private_key,
147+
force_for_new_devices: true,
148+
api_key: Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
149+
)
140150

141-
firebase_app_distribution(
142-
app: firebase_app_id,
143-
service_credentials_file: serviceCredsFile,
144-
release_notes: r"New build from GitHub Actions",
145-
groups: groups
146-
)
147-
end
151+
# === Increment build number from Firebase ===
152+
latest_release = firebase_app_distribution_get_latest_release(
153+
app: firebase_app_id,
154+
service_credentials_file: serviceCredsFile
155+
)
156+
157+
if latest_release
158+
increment_build_number(
159+
xcodeproj: "iosApp/iosApp.xcodeproj",
160+
build_number: latest_release[:buildVersion].to_i + 1
161+
)
162+
else
163+
UI.important("⚠️ No existing Firebase release found. Skipping build number increment.")
164+
end
165+
166+
# === Build signed IPA ===
167+
build_ios_app(
168+
scheme: "iosApp",
169+
project: "iosApp/iosApp.xcodeproj",
170+
output_name: "DeployIosApp.ipa",
171+
output_directory: "iosApp/build",
172+
export_options: {
173+
provisioningProfiles: {
174+
app_identifier => provisioning_profile_name
175+
}
176+
},
177+
xcargs: "CODE_SIGN_STYLE=Manual CODE_SIGN_IDENTITY=\"Apple Distribution\" DEVELOPMENT_TEAM=L432S2FZP5 PROVISIONING_PROFILE_SPECIFIER=\"#{provisioning_profile_name}\""
178+
)
179+
180+
# === Generate release notes ===
181+
releaseNotes = changelog_from_git_commits(
182+
commits_count: 1
183+
)
184+
185+
# === Upload to Firebase ===
186+
firebase_app_distribution(
187+
app: firebase_app_id,
188+
service_credentials_file: serviceCredsFile,
189+
release_notes: releaseNotes,
190+
groups: groups
191+
)
192+
end
148193
end
149194
```
150195

@@ -153,60 +198,86 @@ end
153198
Add the following workflow to your GitHub Actions:
154199

155200
```yaml
156-
name: Deploy to Firebase
201+
name: Deploy iOS to Firebase
157202

158203
on:
159204
push:
160205
branches: [ main ]
161-
# Or trigger on release
162-
release:
163-
types: [created]
206+
# or:
207+
workflow_dispatch:
164208

165209
jobs:
166-
deploy:
210+
deploy_ios:
167211
runs-on: macos-latest
168212
steps:
169-
- uses: actions/checkout@v3
170-
171-
- name: Deploy to Firebase
172-
uses: openMF/kmp-publish-ios-on-firebase-action@v1.0.0
213+
- name: Set Xcode version 16.2
214+
uses: maxim-lobanov/setup-xcode@v1
215+
with:
216+
xcode-version: latest-stable
217+
218+
- name: Checkout Repository
219+
uses: actions/checkout@v4
220+
221+
- name: Publish iOS App to Firebase
222+
uses: openMF/kmp-publish-ios-on-firebase-action@v1.0.2
173223
with:
174-
app_identifier: 'org.mifos.kmp.template'
175-
git_url: 'git@github.com:openMF/ios-provisioning-profile.git'
176-
git_branch: 'master'
177-
match_type: 'adhoc'
178-
provisioning_profile_name: 'match AdHoc org.mifos.kmp.template'
179-
match_password: ${{ secrets.MATCH_PASSWORD }}
180-
match_ssh_private_key: ${{ secrets.MATCH_SSH_PRIVATE_KEY }}
181-
ios_package_name: 'YourAppName'
182-
firebase_creds: ${{ secrets.FIREBASE_CREDS }}
183-
firebase_app_id: '1:xxxx:ios:xxxxxxxx'
184-
tester_groups: 'qa-team,beta-testers'
224+
app_identifier: 'com.example.myapp'
225+
git_url: 'git@github.com:openMF/ios-provisioning-profile.git'
226+
git_branch: 'master'
227+
match_type: 'adhoc'
228+
provisioning_profile_name: 'match AdHoc com.example.myapp'
229+
match_password: ${{ secrets.MATCH_PASSWORD }}
230+
match_ssh_private_key: ${{ secrets.MATCH_SSH_PRIVATE_KEY }}
231+
appstore_key_id: ${{ secrets.APPSTORE_KEY_ID }}
232+
appstore_issuer_id: ${{ secrets.APPSTORE_ISSUER_ID }}
233+
appstore_auth_key: ${{ secrets.APPSTORE_AUTH_KEY }}
234+
ios_package_name: 'iosApp'
235+
firebase_app_id: '1:xxxxxx:ios:xxxxxxxx'
236+
firebase_creds: ${{ secrets.FIREBASE_CREDS }}
237+
tester_groups: 'qa-team,beta-testers'
185238
```
186239
187240
## Inputs and Secrets
188241
189-
| Input | Description | Required |
190-
|--------------------|-----------------------------------------------------|----------|
191-
| `ios_package_name` | Name of your iOS app/scheme | Yes |
192-
| `firebase_creds` | Base64 encoded Firebase service account credentials | Yes |
193-
| `tester_groups` | Comma-separated list of Firebase tester groups | Yes |
194-
| `MATCH_PASSWORD` | Used to encrypt/decrypt match certs | Yes |
195-
| `MATCH_SSH_PRIVATE_KEY` | base64 encoded private SSH key used by Fastlane Match | Yes |
242+
| Input | Description | Required |
243+
|-----------------------------|-----------------------------------------------------|----------|
244+
| `app_identifier` | The unique bundle identifier for the iOS app | ✅ |
245+
| `git_url` | Git URL to certificates/profiles repo | ✅ |
246+
| `git_branch` | Branch in certificates repo | ✅ |
247+
| `match_type` | Profile type (adhoc, appstore, development) | ✅ |
248+
| `provisioning_profile_name` | Name of provisioning profile | ✅ |
249+
| `match_password` | Password to decrypt Match certs | ✅ |
250+
| `match_ssh_private_key` | Base64-encoded SSH private key for Match | ✅ |
251+
| `appstore_key_id` | App Store Connect API key ID | ✅ |
252+
| `appstore_issuer_id` | App Store Connect issuer ID | ✅ |
253+
| `appstore_auth_key` | Base64-encoded `.p8` API key | ✅ |
254+
| `ios_package_name` | Name of the iOS package/module (Xcode scheme) | ✅ |
255+
| `firebase_app_id` | Firebase App ID | ✅ |
256+
| `firebase_creds` | Base64 encoded Firebase service account credentials | ✅ |
257+
| `tester_groups` | Firebase tester groups (comma-separated) | ✅ |
196258

197259
## Setting up Secrets
198260

199261
1. Encode your Firebase credentials file to base64:
262+
200263
```bash
201264
base64 -i path/to/firebase-credentials.json -o firebase-creds.txt
202265
```
203266

204-
2. Add the following secret to your GitHub repository:
267+
2. Encode you r `.p8` API key to base64:
268+
```bash
269+
base64 -i path/to/AuthKey_XXXXXXXXXX.p8 | pbcopy
270+
```
271+
272+
3. Add the following secret to your GitHub repository:
273+
205274
- `FIREBASE_CREDS`: Content of firebase-creds.txt
275+
- `APPSTORE_AUTH_KEY`: Content of AuthKey_XXXXXXXXXX.p8
206276

207277
## Build Artifacts
208278

209279
The action uploads the built IPA file as an artifact with:
280+
210281
- Name: 'ios-app'
211282
- Retention period: 1 day
212283
- Maximum compression (level 9)
@@ -229,10 +300,10 @@ This helps reduce build times in subsequent runs.
229300
Common issues and solutions:
230301

231302
1. Build fails due to signing
232-
- Ensure your Xcode project has proper signing configuration
233-
- Verify the export method matches your provisioning profile
303+
- Ensure your Xcode project has proper signing configuration
304+
- Verify the export method matches your provisioning profile
234305

235306
2. Firebase deployment fails
236-
- Check if the service account has sufficient permissions
237-
- Verify the Firebase app ID is correct
238-
- Ensure tester groups exist in Firebase console
307+
- Check if the service account has sufficient permissions
308+
- Verify the Firebase app ID is correct
309+
- Ensure tester groups exist in Firebase console

0 commit comments

Comments
 (0)