今回はvがついたタグがPushされた時にトリガーされるように実装します。
Contents 非表示
下準備
証明書管理
デプロイに際して必要な証明書、Provisioning Profile関連の管理はFastlane Matchを使って1個のリポジトリで管理します、以下の記事を読んでセットアップを完了させてください。
今回はAppStore
タイプを使用します
環境変数系
今回使用するのはこちら
FASTLANE_USER
- Apple Developerにログインする時のID
FASTLANE_PASSWORD
- Apple Developerにログインする時のPW (App Specific Passwordなるものが必要、詳細は以下の関連記事に)
GOOGLE_SERVICE_INFO_PLIST_BASE64
- GoogleService-Info.plistをエンコーディングしたもの、詳細は以下の関連記事に
P12_BASE64
- 証明書をエンコーディングしたもの、詳細は以下の関連記事に
KEYCHAIN_PASSWORD
- Macにログインする時のPW、いらないかも? (この辺よくわかってない)
APP_STORE_CONNECT_API_KEY
- Apple Developerに外部から接続するためのKEY、JSON形式で保存します
MATCH_PASSWORD
- Matchのセットアップ時に設定したPW
SLACK_WEBHOOK_URL
- Slackに通知を送るためのURL、めんどくさい or Slack使ってない等であれば無視でOK
GOOGLE_SERVICE_INFO_PLIST_BASE64
、P12_BASE64
、FASTLANE_PASSWORD
のセットアップ詳細はこちらの記事を参考に進めてください。
APP_STORE_CONNECT_API_KEY
のセットアップ
Apple DeveloperからAPI Keyを発行する必要があります。
User and Access → Integration → Team Keysで新規にAPIKeyを発行、一旦どこかにメモしておく。
以下の形式で環境変数に保存する。
{
"key_id": "<#KeyID#>",
"issuer_id": "<#Issuer ID#>",
"key": "-----BEGIN PRIVATE KEY-----\n<#APIKey#>\n-----END PRIVATE KEY-----"
}
keyは1行で扱うため、\nで改行を入れる必要があります。
下準備はこれで完了です。
自動デプロイフロー実装
以下のディレクトリにupload_appstore.yml
を作成
.github/workflows/upload_appstore.yml
upload_appstore.yml
name: Upload to App Store # App Storeにアップロード
on:
push:
tags:
- 'v*' # vのついたタグがPushされた時にトリガー
jobs:
upload-to-appstore:
runs-on: macos-latest # 最新のmacOSで実行
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 # CocoaPodsの依存関係をインストール
- 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 appstore --readonly # Fastlane Matchを使用してAppStoreプロファイルを取得
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} # SecretsからのMatchパスワード
- name: Build and upload to App Store
run: bundle exec fastlane upload_appstore # Fastlaneでビルドし、App Storeにアップロード
env:
FASTLANE_USER: ${{ secrets.FASTLANE_USER }} # Fastlaneユーザー(Apple IDなど)
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }} # Fastlaneパスワード
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }} # SecretsからのApp Store Connect APIキー
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} # SecretsからのMatchパスワード
notify:
runs-on: ubuntu-latest
needs: upload-to-appstore
if: always()
steps:
- name: Slack Notification on Success
if: ${{ needs.upload-to-appstore.result == 'success' }}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_TITLE: "Deploy / Success"
SLACK_COLOR: good
SLACK_MESSAGE: "Successfully uploaded build to AppStoreConnect :rocket:"
- name: Slack Notification on Failure
if: ${{ needs.upload-to-appstore.result == 'failure' }}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_TITLE: "Deploy / Failure"
SLACK_COLOR: danger
SLACK_MESSAGE: "Failed to upload build to AppStoreConnect :sob:"
Fastfile
default_platform(:ios)
platform :ios do
desc "Build and upload to the App Store"
lane :upload_appstore do
match(
type: "appstore",
readonly: true
)
increment_build_number(
build_number: latest_testflight_build_number(app_identifier: "<#App Identifier#>") + 1
)
gym(
scheme: "<#Scheme名#>",
export_method: "app-store",
configuration: "Release"
)
upload_to_app_store(
skip_metadata: true,
skip_screenshots: true,
automatic_release: false,
precheck_include_in_app_purchases: false
)
end
end
upload_to_app_storeのパラメータ一覧は以下を参考に、必要に応じて自分好みに設定してください。
upload_to_app_store
の主要なパラメータとその説明
skip_metadata
- 説明: アプリのメタデータ(アプリ名、説明、カテゴリなど)をアップロードせずにスキップするかを指定します。
- デフォルト:
false
(メタデータをアップロード) - 使用例:
skip_metadata: true
(メタデータのアップロードをスキップ)
skip_screenshots
- 説明: アプリのスクリーンショットをアップロードせずにスキップするかを指定します。
- デフォルト:
false
(スクリーンショットをアップロード) - 使用例:
skip_screenshots: true
(スクリーンショットのアップロードをスキップ)
automatic_release
- 説明: アップロード後、App Storeで自動的にリリースするかどうかを指定します。
- デフォルト:
false
(自動リリースしない) - 使用例:
automatic_release: false
(手動でリリースを管理)
precheck_include_in_app_purchases
- 説明: アプリ内課金の確認を含むかどうかを指定します。
precheck
は、一般的なApp Store提出の問題を事前にチェックする機能です。 - デフォルト:
true
(アプリ内課金の確認を含む) - 使用例:
precheck_include_in_app_purchases: false
(アプリ内課金の確認をスキップ)
- 説明: アプリ内課金の確認を含むかどうかを指定します。
force
- 説明: アップロード時にすでに同じバージョンが存在しても強制的に上書きするかどうかを指定します。
- デフォルト:
false
(強制しない) - 使用例:
force: true
(強制的に上書き)
submit_for_review
- 説明: ビルドをApp Store審査に自動的に提出するかどうかを指定します。
- デフォルト:
false
(自動提出しない) - 使用例:
submit_for_review: true
(審査に提出)
release_on_approval
- 説明: 審査が承認された後、App Storeで自動的にリリースするかどうかを指定します。
- デフォルト:
false
(自動リリースしない) - 使用例:
release_on_approval: true
(承認後に自動リリース)
build_number
- 説明: 明示的にアップロードするビルド番号を指定します。
- デフォルト: 指定なし(最新のビルドを使用)
- 使用例:
build_number: "42"
(ビルド番号42をアップロード)
overwrite_screenshots
- 説明: 既存のスクリーンショットを上書きするかどうかを指定します。
- デフォルト:
false
(上書きしない) - 使用例:
overwrite_screenshots: true
(既存のスクリーンショットを上書き)
app_identifier
- 説明: アプリのバンドルIDを明示的に指定します。これにより、正しいアプリケーションがターゲットになります。
- デフォルト: 指定なし(Fastfileで定義されたものを使用)
- 使用例:
app_identifier: "com.example.app"
これでvを含むタグをPushした時にActionsが走ってアップロードされます。
まとめ
自動化できるものは自動化するのが吉、ヒューマンエラーを防ぐために。