Skip to content

Commit 295b8cb

Browse files
Use fastlane to distribute iOS app
1 parent 81c6ea7 commit 295b8cb

File tree

3 files changed

+138
-49
lines changed

3 files changed

+138
-49
lines changed

.github/workflows/ci.yaml

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -13,41 +13,36 @@ on:
1313
jobs:
1414
test-ios:
1515
runs-on: macos-14
16-
defaults:
17-
run:
18-
working-directory: "./example"
1916
steps:
2017
- uses: actions/checkout@v4
21-
- uses: actions/setup-node@v4
18+
- uses: ruby/setup-ruby@v1
2219
with:
23-
node-version-file: "./.tool-versions"
20+
bundler-cache: true
2421
# Xcode_16.2.app is available, but it does not have any simulator pre-installed.
2522
# So it is not really usable.
2623
# Let's use Xcode_16.1.app instead.
27-
- run: sudo xcode-select -s /Applications/Xcode_16.1.app/Contents/Developer
24+
- run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer
2825
- uses: subosito/flutter-action@v2
2926
with:
3027
# This has to be kept in sync with .tool-versions
3128
flutter-version: '3.27.1'
3229
channel: 'stable'
3330
# This action takes 1m30s to finish. Enable cache to make it shorter.
3431
cache: true
35-
- run: flutter pub get
36-
- run: flutter test
37-
- run: flutter analyze --no-fatal-infos
38-
- run: dart format --set-exit-if-changed lib
39-
- run: flutter build ipa --no-codesign
32+
- run: make example-flutter-pub-get
33+
- run: make example-flutter-test
34+
- run: make example-flutter-analyze
35+
- run: make example-dart-format
36+
- run: make example-pod-install
37+
- run: make example-build-unsigned-ios-app
4038

4139
test-android:
4240
runs-on: macos-14
43-
defaults:
44-
run:
45-
working-directory: "./example"
4641
steps:
4742
- uses: actions/checkout@v4
48-
- uses: actions/setup-node@v4
43+
- uses: ruby/setup-ruby@v1
4944
with:
50-
node-version-file: "./.tool-versions"
45+
bundler-cache: true
5146
# https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md#java
5247
- name: Set java version
5348
run: |
@@ -60,10 +55,10 @@ jobs:
6055
# This action takes 1m30s to finish. Enable cache to make it shorter.
6156
cache: true
6257
- run: echo "$ANDROID_HOME/tools/bin" >> $GITHUB_PATH
63-
- run: flutter pub get
64-
- run: flutter test
65-
- run: flutter analyze --no-fatal-infos
66-
- run: dart format --set-exit-if-changed lib
58+
- run: make example-flutter-pub-get
59+
- run: make example-flutter-test
60+
- run: make example-flutter-analyze
61+
- run: make example-dart-format
6762
- run: flutter build apk --debug
6863

6964
deploy-docs:
@@ -78,52 +73,42 @@ jobs:
7873
channel: 'stable'
7974
# This action takes 1m30s to finish. Enable cache to make it shorter.
8075
cache: true
81-
- run: flutter pub get
82-
- run: flutter test
83-
- run: flutter analyze --no-fatal-infos
84-
- run: dart format --set-exit-if-changed lib
76+
- run: make sdk-flutter-pub-get
77+
- run: make sdk-flutter-test
78+
- run: make sdk-flutter-analyze
79+
- run: make sdk-dart-format
8580
# Install the latest dartdoc to avoid a bug
8681
# See DEVELOPER.md
8782
- run: flutter pub global activate dartdoc
88-
if: ${{ github.ref == 'refs/heads/main' }}
8983
- run: flutter pub global run dartdoc
90-
if: ${{ github.ref == 'refs/heads/main' }}
9184
- name: Deploy docs to gh-pages
9285
uses: peaceiris/actions-gh-pages@v3
93-
if: ${{ github.ref == 'refs/heads/main' }}
86+
if: ${{ github.repository == 'authgear/authgear-sdk-flutter' && github.ref == 'refs/heads/main' }}
9487
with:
9588
github_token: ${{ secrets.GITHUB_TOKEN }}
9689
publish_dir: ./doc/api
9790

9891
deploy-ios:
9992
runs-on: macos-14
10093
needs: ["test-ios"]
101-
# We cannot build in PRs because secrets are not available in PRs.
102-
if: ${{ github.repository == 'authgear/authgear-sdk-flutter' && github.ref == 'refs/heads/main' }}
103-
defaults:
104-
run:
105-
working-directory: "./example"
94+
if: ${{ github.repository == 'authgear/authgear-sdk-flutter' }}
10695
steps:
10796
- uses: actions/checkout@v4
108-
- uses: actions/setup-node@v4
97+
- uses: ruby/setup-ruby@v1
10998
with:
110-
node-version-file: "./.tool-versions"
111-
# Xcode_16.2.app is available, but it does not have any simulator pre-installed.
112-
# So it is not really usable.
113-
# Let's use Xcode_16.1.app instead.
114-
- run: sudo xcode-select -s /Applications/Xcode_16.1.app/Contents/Developer
115-
- run: npm install -g appcenter-cli
99+
bundler-cache: true
100+
- run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer
116101
- uses: subosito/flutter-action@v2
117102
with:
118103
# This has to be kept in sync with .tool-versions
119104
flutter-version: '3.27.1'
120105
channel: 'stable'
121106
# This action takes 1m30s to finish. Enable cache to make it shorter.
122107
cache: true
123-
- run: flutter pub get
124-
- run: flutter test
125-
- run: flutter analyze --no-fatal-infos
126-
- run: dart format --set-exit-if-changed lib
108+
- run: make example-flutter-pub-get
109+
- run: make example-flutter-test
110+
- run: make example-flutter-analyze
111+
- run: make example-dart-format
127112
- name: Prepare certificate and provisioning profile
128113
env:
129114
IOS_CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
@@ -153,14 +138,29 @@ jobs:
153138
# apply provisioning profile
154139
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
155140
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
156-
- name: Build .ipa
141+
- name: Install App Store Connect API key
142+
env:
143+
IOS_API_KEY_BASE64: ${{ secrets.IOS_API_KEY_BASE64 }}
144+
IOS_API_KEY_ID: ${{ secrets.IOS_API_KEY_ID }}
157145
run: |
158-
BUILD_NUMBER=$(date +%s)
159-
flutter build ipa --export-options-plist ./exportOptions.plist --build-number $BUILD_NUMBER
160-
- name: Distribute to App Center
146+
API_KEY_PATH=$RUNNER_TEMP/AuthKey_${IOS_API_KEY_ID}.p8
147+
echo -n "$IOS_API_KEY_BASE64" | base64 --decode -o $API_KEY_PATH
148+
- name: Create fastlane api key json
161149
env:
162-
APPCENTER_ACCESS_TOKEN: ${{ secrets.IOS_APPCENTER_ACCESS_TOKEN }}
163-
run: appcenter distribute release --debug --silent --file "./build/ios/ipa/Authgear Flutter.ipa" --store "App Store Connect Users" --app "Oursky/Authgear-Demo-Flutter-iOS" --release-notes "no release notes"
150+
API_ISSUER: ${{ secrets.IOS_API_KEY_ISSUER }}
151+
API_KEY: ${{ secrets.IOS_API_KEY_ID }}
152+
run: |
153+
export API_KEY_PATH=$RUNNER_TEMP/AuthKey_${API_KEY}.p8
154+
make fastlane-api-key-json
155+
- run: make example-build-ios-app
156+
- name: Upload to TestFlight
157+
if: ${{ github.ref == 'refs/heads/main' }}
158+
run: make example-upload-ios-app
159+
- name: Clean up keychain and provisioning profile
160+
if: ${{ always() }}
161+
run: |
162+
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
163+
rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.mobileprovision
164164
165165
deploy-android:
166166
runs-on: macos-14

Makefile

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
API_ISSUER ?= "invalid"
2+
API_KEY ?= "invalid"
3+
API_KEY_PATH ?= ./AuthKey_invalid.p8
4+
5+
.PHONY: fastlane-api-key-json
6+
fastlane-api-key-json:
7+
mkdir -p ./build
8+
jq --slurp --raw-input > ./build/fastlane-api-key.json \
9+
--arg key_id $(API_KEY) \
10+
--arg issuer_id $(API_ISSUER) \
11+
'{key_id: $$key_id, issuer_id: $$issuer_id, key: .}' \
12+
$(API_KEY_PATH)
13+
14+
.PHONY: example-flutter-pub-get
15+
example-flutter-pub-get:
16+
cd ./example; flutter pub get
17+
18+
.PHONY: example-flutter-test
19+
example-flutter-test:
20+
cd ./example; flutter test
21+
22+
.PHONY: example-flutter-analyze
23+
example-flutter-analyze:
24+
cd ./example; flutter analyze --no-fatal-infos
25+
26+
.PHONY: example-dart-format
27+
example-dart-format:
28+
cd ./example; dart format --set-exit-if-changed lib
29+
30+
.PHONY: example-pod-install
31+
example-pod-install:
32+
cd ./example/ios; bundle exec pod install
33+
34+
.PHONY: example-build-unsigned-ios-app
35+
example-build-unsigned-ios-app:
36+
bundle exec fastlane runner_build_ios_app skip_codesigning:1
37+
38+
.PHONY: example-build-ios-app
39+
example-build-ios-app:
40+
bundle exec fastlane runner_build_ios_app FLUTTER_BUILD_NAME:1.0 FLUTTER_BUILD_NUMBER:$(shell date +%s)
41+
42+
.PHONY: example-upload-ios-app
43+
example-upload-ios-app:
44+
bundle exec fastlane upload_ios_app ipa:./build/Release/iOS/Runner/Runner.ipa
45+
46+
.PHONY: sdk-flutter-pub-get
47+
sdk-flutter-pub-get:
48+
flutter pub get
49+
50+
.PHONY: sdk-flutter-test
51+
sdk-flutter-test:
52+
flutter test
53+
54+
.PHONY: sdk-flutter-analyze
55+
sdk-flutter-analyze:
56+
flutter analyze --no-fatal-infos
57+
58+
.PHONY: sdk-dart-format
59+
dart format --set-exit-if-changed lib

fastlane/Fastfile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
default_platform(:ios)
2+
3+
platform :ios do
4+
lane :runner_build_ios_app do |options|
5+
build_app(
6+
skip_codesigning: options[:skip_codesigning] == "1",
7+
# when skip_codesigning is false, there is no Team ID.
8+
# -exportArchive requires Team ID.
9+
# So we need to skip generating the ipa.
10+
skip_package_ipa: options[:skip_codesigning] == "1",
11+
destination: "generic/platform=iOS",
12+
workspace: "./example/ios/Runner.xcworkspace",
13+
scheme: "Runner",
14+
configuration: "Release",
15+
export_options: "./example/exportOptions.plist",
16+
clean: true,
17+
output_directory: "./build/Release/iOS/Runner",
18+
output_name: "Runner.ipa",
19+
xcargs: "FLUTTER_BUILD_NAME=#{options[:FLUTTER_BUILD_NAME]} FLUTTER_BUILD_NUMBER=#{options[:FLUTTER_BUILD_NUMBER]}",
20+
)
21+
end
22+
23+
lane :upload_ios_app do |options|
24+
upload_to_testflight(
25+
skip_waiting_for_build_processing: true,
26+
api_key_path: "./build/fastlane-api-key.json",
27+
ipa: options[:ipa],
28+
)
29+
end
30+
end

0 commit comments

Comments
 (0)