[iOS]Github Actionsを使用してプッシュ時にビルドを行いtestflightへ配信する
こんにちは。リテールアプリ共創部のYahiroです。
CI/CDってなんか響きがいいですよね。
iOSで開発を行うとき、動作確認のためにApp Store Connectからtestflightへ配信するというのはよくあると思うのですが、GitHubにプッシュした時にビルド〜testflight配信まで自動でやってくれたらなあって思うことは多々あると思います。
今日はそれをGithub Actionsで実現しようというお話です。
この記事でわかること
- iOSアプリのビルドからtestflight配信までをGithub Actionsで行う
前提
- Apple Developer Programに参加していること
- Github上でソースを管理していること
- プロジェクトの自動署名を有効にしていること
GitHub Actions?
Github Actionsとは、Githubが提供するワークフローの実行環境です。
https://github.co.jp/features/actions
Jenkinsなどを使用されたことがある方はわかりやすいかなと思うのですが、さまざまなスクリプトをGithub上で動かすことができます。
これのすごいところは、なんと無課金でも実行できるということです。
利用料金
Publicリポジトリの場合は、原則無料で使用可能です。
Privateリポジトリの場合、下記の料金がかかります。
これは記事執筆時点(2024/12/4)時点の料金となるので、最新の料金は公式ページからチェックしてください。
プラン | 利用時間 |
---|---|
Free | 2000分/月 |
Pro | 3000分/月 |
Team | 3000分/月 |
Enterprise | 50,000分/月 |
ここでの利用時間とは、1つのワークフローを実行できる時間となります。
こう見るとFreeでもそれなりに使えることがわかりますね。
ところが、気をつけないといけないのが倍率という考え方があります。
GithubはLinux/Windows/macOSの三種の実行環境を提供していますが、この実行環境によって消費される利用時間の倍率が異なります。
環境 | 倍率/分 |
---|---|
Linux | 1 |
Windows | 2 |
macOS | 10 |
これはつまりどういうことかというと、利用した環境に応じて消費される利用時間は、
実際に実行した時間 * 上記の倍率
となります。どういうことや・・・??
詳しく解説します。
今回はiOSのビルドとなるので、macOSを例に解説します。
例えばiOSのビルドを100分行ったとします。macOSの倍率は10となるため、消費される利用時間は下記で求めることができます。
実際に実行した時間(100分) * 上記の倍率(10倍) = 1000分
そのため、Freeプランは2000分/月の使用が可能ですが、iOSのビルドに使用する場合は実際には200分/月しか使用できない。ということになります。(急に少なく感じてきましたね・・・)
じゃあ、超過したらどうなるのか?というところですが、Githubはデフォルトでは支払い限度額が$0.00となっています。
そのため、月の利用時間を使い切った場合はワークフローが実行されなくなります。
ですので、急に請求が来るということはありませんが、ワークフローの実行がプロジェクトにクリティカルに影響する場合は、事前に確認しておくことをおすすめします。
設定は下記で確認することができます。
Settings>Access>Billing and plans/Spending limits
自分が残りどれくらい使えるかは下記で確認することができます。
※私はCopilitに課金しているため$10.00になっています。
Settings>Access>Billing and plans/Spending limits
準備編
さて、ここからは準備を進めていきましょう
AppStoreConnect
まず、AppStoreConnectでの準備を進めていきます。AppStoreConnectにログインしたら、下記を「ユーザとアクセス」に進んでください。
次に、統合から「アクセス権をリクエスト」を選択してください。
「提出」を選択。
すると、下記のように表示が変わりますので「APIキーを生成」を選択してください。
APIキーの生成を行います。名前はなんでも良いですが今回は「Github Actions」としました。ここは何にしても動作に影響はないので、環境に応じて適した名前にしてください。
アクセスは色々選択出来ますが、「Admin」を選択してください。
両方とも入力が完了したら「生成」を選択してください。
すると、下記のような表示に変わりますので、「ダウンロード」を選択してください。
※ここでのダウンロードは生成後一回のみです。以降二度とダウンロードできないため、ダウンロードしたファイルはなくさないように厳重に保管してください。
iCloud
続いて、iCloud上での設定を行っていきます。
まず、iCloudにログインしたら、右上のアイコンから「Apple Accountを管理」を選択してください。
下記の画面に移動したら、アプリ用パスワードを選択してください。
「アプリ用パスワードを生成」を選択。
名前を入力してください。ここではわかりやすく「Github Actions」にしましたが、ここは何にしても動作に影響はないので、環境に応じて適した名前にしてください。
すると、下記のようにパスワードが表示されます。後ほど使用するので控えておいてください。
※ここでのパスワード閲覧は生成後一回のみです。以降二度と確認できないため、気をつけてください。
Github Secrets
ここまで、AppStore Connect、iCloudで取得した情報をGithubのSecretsに登録していきます。
SecretsとはGithub Actions内で使用する環境変数を定義する場所です。
パスワードやキーなど、コード内に記載することができない機密性の高い値を保存するのに使用します。
Secretsに設定する環境変数は下記の5つになります。
- APPLE_API_KEY_BASE64
- APPLE_API_ISSUE_ID
- APPLE_API_KEY_ID
- APPLE_ID
- APP_SPECIFIC_PASSWORD
- EXPORT_OPTIONS
順に作成していきましょう。
追加方法
Githubにて該当のプロジェクトを開いたら、Settingsから「Secrets and variables」の「Actions」を開いてください。
開けたら、「New repository secrets」を選択して値を追加していきます。
Nameには環境変数の名前、Secretにはその内容を記載して「Add secret」を選択していきます。
APPLE_API_KEY_BASE64
ここからは各値の取得方法について解説していきます。
追加方法で記載した方法で、NameにAPPLE_API_KEY_BASE64と設定してください。
内容は、AppStoreConnectでダウンロードした証明書を下記のコマンドでBase64にエンコードし、その内容を記載してください。
※macでのコマンドとなるのでお手元の環境に応じて読み替えてください。
cat AuthKey_*******.p8| base64
APPLE_API_ISSUE_ID
AppStoreConnectの下記の部分で取得できるので、これを値に記載してください。
APPLE_API_KEY_ID
AppStoreConnectの下記の部分で取得できるので、これを値に記載してください。
APPLE_ID
ご自身のAppleIDを値に記載してください。
APP_APP_SPECIFIC_PASSWORD
先の画面で取得したパスワードを値に記載してください。
EXPORT_OPTIONS
ExportOptions.plistの内容になります。これは、XCode上でArchiveを行なって生成する方法もありますが、今回は下記の内容を値に記載します。
なお、「YOUR_TEAM_ID」の部分はApple Developer Programの「メンバーシップの詳細」から確認して、置き換えてください。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
</dict>
</plist>
以上全てが完了すると、下記のような状態になっていると思います。
これで準備は完了です。
実装編
いよいよ実装を進めていきます。
まず、Actionsタブを開いて、検索バーに「simple」と入力して、「Simple workflow」を選択してください。
すると、下記のようなテンプレートが作成されるので一旦Commit changesを選択してみましょう。
ワークフローのビルドが走り、ビルドが成功すると思います。
これで、ワークフローのymlも作成できました。
作成したymlを下記のように書き換えてコミットしてください。
今回、「ci_cd_test」という名前でプロジェクトを作成しているので、該当する部分は適宜置き換えてください。
ワークフローのyml
name: Build
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:
jobs:
build:
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Archive
run: |
xcodebuild archive -project ci_cd_test.xcodeproj -scheme ci_cd_test -archivePath ci_cd_test.xcarchive -sdk iphoneos -configuration Release CODE_SIGNING_ALLOWED=NO
- name: Create ExportOptions.plist
run: |
echo '${{ secrets.EXPORT_OPTIONS }}' > ExportOptions.plist
cat ExportOptions.plist
- name: Create Private Key
run: |
mkdir private_keys
echo -n '${{ secrets.APPLE_API_KEY_BASE64 }}' | base64 --decode > ./private_keys/AuthKey_${{ secrets.APPLE_API_ISSUER_ID }}.p8
- name: Export IPA
run: |
xcodebuild -exportArchive -archivePath ci_cd_test.xcarchive -exportOptionsPlist ExportOptions.plist -exportPath ci_cd_test.ipa -allowProvisioningUpdates -authenticationKeyPath `pwd`/private_keys/AuthKey_${{ secrets.APPLE_API_ISSUER_ID }}.p8 -authenticationKeyID ${{ secrets.APPLE_API_KEY_ID }} -authenticationKeyIssuerID ${{ secrets.APPLE_API_ISSUER_ID }}
- name: Upload to App Store Connect
run: |
xcrun altool --upload-app -f ci_cd_test.ipa/ci_cd_test.ipa -t ios -u ${{ secrets.APPLE_ID }} -p ${{ secrets.APP_SPECIFIC_PASSWORD }} --type ios
項目解説
on
onはいつワークフローの実行を行うかを定義します。ここではmainブランチにプッシュまたはプルリクエストが行われた時となっています。
jobs
実行するジョブと環境を指定します。「runs-on」ではOSの指定となります。
「macos-latest」という指定方法もありますが、Github Actionsのlatest指定は必ずしも最新のOSで実行されるわけではないので(2024/12時点では15は使用可能ですが、latestで実行すると14で実行されます)、バージョンを指定することをおすすめします。
なお、使用可能なイメージは下記のリポジトリで確認してください。
https://github.com/actions/runner-images
実行
いよいよ実行です。先ほどコミットしたymlをmainブランチにプッシュしてみましょう。
プッシュすると自動的にワークフローのビルドが行われ、AppStore Connectへアップロードされます。
testflightで確認してみてください。
以降は、mainブランチにプッシュまたはプルリクエストが行われる度にワークフローが実行されるようになります。
お疲れ様でした。
最後に
倍率が10倍で消費されるとはいえ、Github上でビルド〜testflightに配信まで無料である程度行えるのは便利ですね。
また、動作確認の手順を簡略化できるので運用次第でプロジェクトの進行にも寄与できそうな予感がしています。