↓ Slackにも通知を送る ↓
下準備
アップロードに必要な前提環境、項目は以下の通り
(今回はPodでライブラリを管理している前提です、SPM (Swift Package Manager)の考慮はありません)
Apple Developerアカウント & Fastlane
今回はFastlane Matchを使って証明書管理を行うため、Apple Develoerに登録する必要があります。
証明書管理、作成の方法は↓の記事を参考に進めてください、今回はadhocを使用します。
Fastlane関連のファイルも↓の記事の通りに進めてセットアップをしてください。
[Xcode/Swift] Fastlane Matchで証明書管理リポジトリを作るFirebase
当たり前な気がしますが、Firebaseと繋ぐのでFirebaseのセットアップをして、プロジェクトにGoogleService-Info.plist
を入れておいてください。
Base64でエンコーディングするもの
今回Githubリポジトリに環境変数として色々なものを入れます、その中でエンコーディングして保存しないといけないものがあるので先に準備をしておきましょう。
GoogleService-Info.plist
対象のディレクトリを開いて、以下を実行。
cat GoogleService-Info.plist | base64 | pbcopy
base64でエンコーディング、とても長い文字列の出力になるのでpbcopyでその場でコピーしておく。
コピーした値は一旦メモとかに残しておきましょう。
Certificates.p12
fastlane matchで自動生成した証明書をKeychainで探す、末尾にApple DeveloperのTeamIDがついていると思われるのでそれを辿れば正しいものが見つかります。
対象の証明書を選択して、Export (証明書名)
を選択 → Desktop
とかに一旦保存する。
こちらも対象のディレクトリを開いて、以下を実行。
cat Certificates.p12 | base64 | pbcopy
証明書名は特に指定しない限りデフォルトではCertificates.p12
で保存されるはず(多分)。
こちらも一旦どこかにメモしておきましょう。
これで下準備は(ある程度)完了です。
自動実行環境を構築
workflows
対象のXcodeプロジェクトのルートディレクトリ直下に以下のファイルを作成
.github/workflows/distribution.yml
今回はdevelopブランチにPushされたときにトリガーされるようにします、この辺りのトリガータイミングは色々設定できるので調べてみてください (説明放棄)
name: Distribute IPA to Firebase App Distribution
on:
push:
branches:
- develop # developブランチへのpush時にジョブをトリガー
jobs:
build:
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2 # リポジトリのソースコードをチェックアウト
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2' # FastlaneとCocoaPodsに必要なRuby 3.2を使用
- name: Cache CocoaPods
uses: actions/cache@v2
with:
path: Pods # インストールされたCocoaPods依存関係をキャッシュ
key: ${{ runner.os }}-pods-${{ hashFiles('Podfile.lock') }} # Podfile.lockに基づいたキャッシュキー
restore-keys: |
${{ runner.os }}-pods- # メインキーが見つからない場合のフォールバックキー
- name: Install CocoaPods
run: |
gem install bundler
bundle install
pod install
- name: Decrypt GoogleService-Info.plist
run: |
mkdir -p <#GoogleService-Info.plistを格納するパス#>
echo "$GOOGLE_SERVICE_INFO_PLIST_BASE64" | base64 --decode > <#GoogleService-Info.plistへのパス#>
env:
GOOGLE_SERVICE_INFO_PLIST_BASE64: ${{ secrets.GOOGLE_SERVICE_INFO_PLIST_BASE64 }} # FirebaseのGoogleService-Info.plistをSecretsから復号
- name: Decrypt and Import .p12 Certificate
run: |
echo "$P12_BASE64" | base64 --decode > certificate.p12
security create-keychain -p "" build.keychain
security list-keychains -s build.keychain
security unlock-keychain -p "" build.keychain
security import ./certificate.p12 -k build.keychain -P "$P12_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" build.keychain
env:
P12_BASE64: ${{ secrets.P12_BASE64 }} # Base64でエンコードされた証明書
P12_PASSWORD: ${{ secrets.MATCH_PASSWORD }} # Secretsからの証明書パスワード
- name: Set up Fastlane
run: bundle exec fastlane match adhoc --readonly # Fastlane MatchでAdHocプロファイルを取得 (読み取り専用モード)
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} # SecretsからのMatchパスワード
- name: Enable Parallel Code Signing
run: |
defaults write com.apple.dt.Xcode IDEBuildOperationMaxNumberOfConcurrentCompileTasks 4 # 並列コード署名を有効化してビルド速度を向上
- name: Build and distribute to Firebase App Distribution
run: bundle exec fastlane distribute # Fastlaneでアプリをビルドし、Firebase App Distributionにアップロード
env:
FIREBASE_APP_ID: ${{ secrets.FIREBASE_APP_ID }}
FIREBASE_APP_DISTRIBUTION_API_TOKEN: ${{ secrets.FIREBASE_APP_DISTRIBUTION_API_TOKEN }} # Firebase App Distribution APIトークン
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} # SecretsからのMatchパスワード
FASTLANE_USER: ${{ secrets.FASTLANE_USER }} # Fastlaneユーザー (Apple IDなど)
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }} # Fastlaneパスワード
notify:
runs-on: ubuntu-latest # Slack通知はUbuntuランナーを使用
needs: build # buildジョブの成功/失敗に依存
if: always()
steps:
- name: Slack Notification on Success
if: ${{ needs.build.result == 'success' }}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} # Secretsに保存されたWebhook URL
SLACK_TITLE: "Deploy / Success"
SLACK_COLOR: good
SLACK_MESSAGE: "ビルドが正常にFirebase App Distributionに配布されました :rocket:"
- name: Slack Notification on Failure
if: ${{ needs.build.result == 'failure' }}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} # Secretsに保存されたWebhook URL
SLACK_TITLE: "Deploy / Failure"
SLACK_COLOR: danger
SLACK_MESSAGE: "ビルドのFirebase App Distributionへの配布に失敗しました :sob:"
Fastlane関連ファイル
default_platform(:ios)
# iOSプラットフォームの設定
platform :ios do
# 'Upload to Firebase'という処理の説明
desc "Upload to Firebase"
# distributeという名前のlane(処理のまとまり)を定義
lane :distribute do
# 'match'を使って証明書やプロビジョニングプロファイルを取得する
# type: "adhoc" はAdHoc配布用の証明書・プロファイルを使う設定
# readonly: true は読み取り専用で既存の証明書・プロファイルを使う設定
match(
type: "adhoc",
readonly: true
)
# ビルド番号を自動的に1つ増やす
increment_build_number
# Info.plistからバージョン番号を取得
# CFBundleShortVersionStringキーの値(バージョン番号)を取得
version_number = get_info_plist_value(path: "<#Info.plistのパス#>", key: "CFBundleShortVersionString")
# 現在のビルド番号を取得
build_number = get_build_number
# gymを使ってアプリをビルド
# schemeはXcodeプロジェクト内のスキームを指定
# verbose: true は詳細なログを表示する設定
gym(
scheme: "<#スキーム名#>",
verbose: true
)
# Firebase App Distributionにビルドをアップロード
# appはFirebaseアプリIDを指定(環境変数FIREBASE_APP_IDから取得)
# release_notesでリリースノートを指定
# firebase_cli_tokenはFirebase CLI用のトークン(環境変数から取得)
firebase_app_distribution(
app: ENV["FIREBASE_APP_ID"], # 環境変数FIREBASE_APP_IDからアプリIDを取得
release_notes: "Beta Release: #{version_number} (Build: #{build_number})", # リリースノートにバージョンとビルド番号を含める
firebase_cli_token: ENV["FIREBASE_APP_DISTRIBUTION_API_TOKEN"] # 環境変数からFirebase CLIのAPIトークンを取得
)
end
end
# Matchfile
# 使用するストレージモードの設定
storage_mode("git")
# 証明書のタイプを指定
type("adhoc") # 証明書のタイプ: appstore, adhoc, enterprise, development から選択
# 証明書管理用のGitリポジトリURLを設定
git_url("<#URL#>")
# 使用するブランチを指定
git_branch("master")
# Apple Developer アカウントに対応するチームID (Developerコンソールで確認可能)
team_id("<#TEAMID#>")
# このMatch設定に対するアプリのバンドルIDを指定
app_identifier(["<#アプリのBundle Identifier#>"])
# Gitリポジトリにコミットする際のユーザー情報
git_full_name("<#Githubユーザ名#>")
git_user_email("<#メールアドレス#>")
# 新しいデバイス用に証明書を強制的に生成するオプション(必要に応じて)
force_for_new_devices(true)
環境変数設定
少し多いですが一個ずつ入力漏れがないように埋めていきましょう。
(Slack関連はSlackAPIも絡んでくるのでめんどくさい or そもそもSlack使ってないなら環境変数の設定は不要 & ↑で設定したSlack関連スクリプトは削除で大丈夫です。)
- FASTLANE_PASSWORD
- Apple Developerにログインする際のPWと思いきや
App Specific Password
なるものらしい、詳細は↓の黄色セクションを確認してください
- Apple Developerにログインする際のPWと思いきや
- FASTLANE_USER
- Apple Developerにログインする際のID
- FIREBASE_APP_DISTRIBUTION_API_TOKEN
- FirebaseをCLIで操作するために発行するTOKEN
- FIREBASE_APP_ID
- 名前の通り、Firebaseの設定項目で確認できます。
- GOOGLE_SERVICE_INFO_PLIST_BASE64
- 序盤でエンコードした値をここに保存
- KEYCHAIN_PASSWORD
- 多分Macにログインする時のPW
- MATCH_PASSWORD
- Matchセットアップしたときに設定したPW
- P12_BASE64
- 序盤でエンコードした証明書の値
- SLACK_WEBHOOK_URL
- Slack APIコンソールから確認可能、めんどうなら省略
こんな感じになればOK
(Firebase TOKENの生成方法は以下の記事を参考に)
[Swift/Firebase] FastlaneでXcodeからFirebase App Distributionアプリを配信する実行する
ymlで設定したように、developブランチに新規PushをするとActionsの処理が開始されます。
問題なく完了すれば青色、何かエラーがあって落ちると赤になります。
今回はPushでのトリガーですが、Pull Requestでdistribute beta
みたいなコメントがされたとき、マージされたときのように色々な条件で実行できるので自分のプロジェクトに合わせて上手に活用してください。
まとめ
自動化は便利、ただ環境構築がめんどくさい。(周りに聞ける環境がなければ尚更)