Skip to content

Commit d470931

Browse files
committed
build ios app with github actions
1 parent 8d14c7f commit d470931

2 files changed

Lines changed: 207 additions & 0 deletions

File tree

.github/workflows/ios.yml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: Build source code on ios
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
workflow_dispatch:
9+
10+
jobs:
11+
build_ios:
12+
runs-on: macOS-latest
13+
steps:
14+
- uses: actions/checkout@v5
15+
- name: Use Node.js 20
16+
uses: actions/setup-node@v4
17+
with:
18+
node-version: 24
19+
cache: npm
20+
21+
- name: Install dependencies
22+
id: install_code
23+
run: npm ci
24+
25+
- name: Build
26+
id: build_code
27+
run: npm run build
28+
29+
- name: Build
30+
id: build_code
31+
run: npm run mobile
32+
33+
- uses: actions/cache@v3
34+
with:
35+
path: ios/App/Pods
36+
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
37+
restore-keys: |
38+
${{ runner.os }}-pods-
39+
40+
- name: Sync
41+
id: sync_code
42+
run: npx cap sync
43+
44+
- uses: ruby/setup-ruby@v1
45+
with:
46+
ruby-version: '3.0'
47+
bundler-cache: true
48+
49+
- uses: maierj/fastlane-action@v3.1.0
50+
env:
51+
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
52+
BUNDLE_IDENTIFIER: ${{ secrets.BUNDLE_IDENTIFIER }}
53+
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
54+
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
55+
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
56+
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
57+
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
58+
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
59+
APPLE_PROFILE_NAME: ${{ secrets.APPLE_PROFILE_NAME }}
60+
with:
61+
lane: ios beta
62+
63+
- name: Upload release bundle
64+
uses: actions/upload-artifact@v4
65+
with:
66+
name: ios-release
67+
path: ./App.ipa
68+
retention-days: 10

fastlane/Fastfile

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
platform :ios do
2+
desc 'Export ipa and submit to TestFlight'
3+
lane :beta do
4+
keychain_info = { keychain_name: "ios-build-#{Time.now.to_i}.keychain", keychain_password: SecureRandom.uuid }
5+
6+
begin
7+
setup_signing(keychain_info)
8+
bump_build_number
9+
build_app_with_signing(keychain_info)
10+
submit_to_testflight
11+
ensure
12+
cleanup_keychain(keychain_info)
13+
end
14+
end
15+
16+
private_lane :setup_signing do |options|
17+
create_keychain(
18+
name: options[:keychain_name],
19+
password: options[:keychain_password],
20+
unlock: true,
21+
timeout: 0,
22+
lock_when_sleeps: false,
23+
add_to_search_list: true
24+
)
25+
import_cert(options)
26+
install_profile
27+
update_project_settings
28+
end
29+
30+
lane :bump_build_number do
31+
file = File.read('../package.json')
32+
data_hash = JSON.parse(file)
33+
api_key = app_store_connect_api_key(
34+
key_id: ENV['APPLE_KEY_ID'],
35+
issuer_id: ENV['APPLE_ISSUER_ID'],
36+
key_content: ENV['APPLE_KEY_CONTENT'],
37+
is_key_content_base64: true,
38+
duration: 1200,
39+
in_house: false
40+
)
41+
build_num = app_store_build_number(
42+
api_key: api_key,
43+
app_identifier: ENV['BUNDLE_IDENTIFIER'],
44+
live: false
45+
)
46+
build_num = build_num + 1
47+
UI.message("Bumped build number to #{build_num}")
48+
increment_build_number(
49+
build_number: build_num,
50+
xcodeproj: "./ios/App/App.xcodeproj",
51+
skip_info_plist: true
52+
)
53+
end
54+
55+
private_lane :import_cert do |options|
56+
cert_path = "#{Dir.tmpdir}/build_certificate.p12"
57+
File.write(cert_path, Base64.decode64(ENV['BUILD_CERTIFICATE_BASE64']))
58+
import_certificate(
59+
certificate_path: cert_path,
60+
certificate_password: ENV['P12_PASSWORD'] || "",
61+
keychain_name: options[:keychain_name],
62+
keychain_password: options[:keychain_password],
63+
log_output: true
64+
)
65+
File.delete(cert_path)
66+
end
67+
68+
private_lane :cleanup_keychain do |options|
69+
delete_keychain(
70+
name: options[:keychain_name]
71+
)
72+
end
73+
74+
private_lane :install_profile do
75+
profile_path = "#{Dir.tmpdir}/build_pp.mobileprovision"
76+
File.write(profile_path, Base64.decode64(ENV['BUILD_PROVISION_PROFILE_BASE64']))
77+
UI.user_error!("Failed to create provisioning profile at #{profile_path}") unless File.exist?(profile_path)
78+
ENV['PROVISIONING_PROFILE_PATH'] = profile_path
79+
install_provisioning_profile(path: profile_path)
80+
File.delete(profile_path)
81+
end
82+
83+
private_lane :update_project_settings do
84+
update_code_signing_settings(
85+
use_automatic_signing: false,
86+
path: "./ios/App/App.xcodeproj",
87+
code_sign_identity: "iPhone Distribution",
88+
profile_name: ENV['APPLE_PROFILE_NAME'],
89+
bundle_identifier: ENV['BUNDLE_IDENTIFIER'],
90+
team_id: ENV['APP_STORE_CONNECT_TEAM_ID']
91+
)
92+
update_project_team(
93+
path: "./ios/App/App.xcodeproj",
94+
teamid: ENV['APP_STORE_CONNECT_TEAM_ID']
95+
)
96+
end
97+
98+
private_lane :build_app_with_signing do |options|
99+
unlock_keychain(
100+
path: options[:keychain_name],
101+
password: options[:keychain_password],
102+
set_default: false
103+
)
104+
build_app(
105+
workspace: "./ios/App/App.xcworkspace",
106+
scheme: "App",
107+
configuration: "Release",
108+
export_method: "app-store",
109+
output_name: "App.ipa",
110+
export_options: {
111+
provisioningProfiles: {
112+
ENV['BUNDLE_IDENTIFIER'] => ENV['APPLE_PROFILE_NAME']
113+
}
114+
},
115+
xcargs: "-verbose",
116+
buildlog_path: "./build_logs",
117+
export_xcargs: "-allowProvisioningUpdates",
118+
)
119+
end
120+
121+
private_lane :submit_to_testflight do
122+
api_key = app_store_connect_api_key(
123+
key_id: ENV['APPLE_KEY_ID'],
124+
issuer_id: ENV['APPLE_ISSUER_ID'],
125+
key_content: ENV['APPLE_KEY_CONTENT'],
126+
is_key_content_base64: true,
127+
duration: 1200,
128+
in_house: false
129+
)
130+
pilot(
131+
api_key: api_key,
132+
skip_waiting_for_build_processing: true,
133+
skip_submission: true,
134+
distribute_external: false,
135+
notify_external_testers: false,
136+
ipa: "./App.ipa"
137+
)
138+
end
139+
end

0 commit comments

Comments
 (0)