2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

iOSAdvent Calendar 2024

Day 9

Watchアプリを含むiOSアプリをApp Store ConnectへデプロイするGithub Actions

Last updated at Posted at 2024-12-18

概要

業務内でWatchアプリ込みのiOSアプリについてGithubActionsを使用し、
App Store ConnectにアップロードするようなActionを作成したので備忘録として

※今回はxcode build + Xcode自動署名方式を使用しています

構成

アプリ:iOS + WatchOS + Widget
xcodeproj形式のプロジェクトファイル
Swift-6
XCode-16

完成したコード

name: Deploy To App Store Connect

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: macos-15
    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Set up Xcode
        uses: maxim-lobanov/setup-xcode@v1
        with:
          xcode-version: "16.1.0"

      - name: Archive Scheme
        run: |
          xcodebuild -project ProjectName.xcodeproj \
                     -scheme SchemeName \
                     -configuration Release \
                     archive -archivePath SchemeName.xcarchive \
                     CODE_SIGNING_ALLOWED=NO

      - name: Create ExportOptions.plist
        run: |
          echo '${{ secrets.EXPORT_OPTIONS }}' > ExportOptions.plist

      - name: Save App Store Connect Private Key to File
        run: |
          mkdir private_keys
          echo "${{ secrets.APP_STORE_CONNECT_PRIVATE_KEY }}" > ./private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8

      - name: Export .ipa
        run: |
          xcodebuild -exportArchive \
                     -archivePath SchemeName.xcarchive \
                     -exportOptionsPlist ExportOptions.plist \
                     -exportPath export \
                     -allowProvisioningUpdates \
                     -authenticationKeyPath $PWD/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8 \
                     -authenticationKeyID ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} \
                     -authenticationKeyIssuerID ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}

      - name: Upload ipa to TestFlight
        run: |
          xcrun altool --upload-app -f export/SchemeName.ipa \
                       --type ios \
                       --apiKey ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} \
                       --apiIssuer ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} \
                       --apiPrivateKey $pwd/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8

      - name: Cleanup
        run: rm ExportOptions.plist `pwd`/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8

アプリ固有の環境値

下記については各々のProjectに合わせて変更してください

ProjectName.xcodeproj:プロジェクト名
SchemeName:スキーム名

各種設定

Github

Secrets And Variablesに必要な値を取得します

App Store Connect API Keyの作成

API Keyを発行してください

※App Store Connect -> ユーザーとアクセス -> 統合 -> チームキーの作成

発行したら、下記三点をコピーしておきましょう

・Issue ID
・KeyID
・API Key ID

Export Options

Xcodeからipaファイルをexportするとexport先のフォルダにExportOptions.plistが作成されるのでそちらを使用します

Xcode -> Archive -> Distribute App -> Custom -> Export

スクリーンショット 2024-12-17 15.10.26.png

スクリーンショット 2024-12-17 15.11.05.png

※ TestFlightのみアップするように設定もできる

stgブランチ -> Test Flight
mainブランチ -> AppStoreConnect

のようにブランチごとに分けると良いかも

スクリーンショット 2024-12-17 15.15.22.png

Github Secrets And Variables設定

上記で取得した値を
Github Secrets And Variables -> Repository secretsに設定

スクリーンショット 2024-12-18 12.53.17.png

APP_STORE_CONNECT_PRIVATE_KEY: App Store Connectにて取得したPrivate Key 
↑ VSCodeなどで証明書を開いてコピペ
APP_STORE_CONNECT_API_KEY_ID: App Store Connectにて取得したAPI Key
APP_STORE_CONNECT_ISSUER_ID:  App Store Connectにて取得したIssuer ID
EXPORT_OPTIONS: XcodeでExportしたExportOption.plistの値
↑ VSCodeなどでplistを開いてコピペ

ここまで設定すれば動くようになります
あとは指定したブランチへマージし、Giahub Actionが動くことを確認してください

解説

仮想環境のセットアップ

仮想環境のセットアップしxcodeをインストール

jobs:
  deploy:
    runs-on: macos-15
    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Set up Xcode
        uses: maxim-lobanov/setup-xcode@v1
        with:
          xcode-version: "16.1.0"

アーカイブの作成

configuration
Archive時のBuild Configration

CODE_SIGNING_ALLOWED=NO
アーカイブ時は署名が不要なのでoptionをNOで設定

      - name: Archive Scheme
        run: |
          xcodebuild -project ProjectName.xcodeproj \
                     -scheme SchemeName \
                     -configuration Release \
                     archive -archivePath SchemeName.xcarchive \
                     CODE_SIGNING_ALLOWED=NO

各種設定ファイルの作成

ExportOptions.plistとApp Storeアップロード用の証明書を作成します

※ 後述しますが、p8形式の秘密鍵を書き出す際に、ファイル名はApp Store Connectで取得した名称をそのまま使用してください。

      - name: Create ExportOptions.plist
        run: |
          echo '${{ secrets.EXPORT_OPTIONS }}' > ExportOptions.plist

      - name: Save App Store Connect Private Key to File
        run: |
          mkdir private_keys
          echo "${{ secrets.APP_STORE_CONNECT_PRIVATE_KEY }}" > ./private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8

ipaファイルの書き出し

App Store ConnectのAPIKey情報をもとに署名を行い、ipaファイルを作成します

      - name: Export .ipa
        run: |
          xcodebuild -exportArchive \
                     -archivePath SchemeName.xcarchive \
                     -exportOptionsPlist ExportOptions.plist \
                     -exportPath export \
                     -allowProvisioningUpdates \
                     -authenticationKeyPath $PWD/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8 \
                     -authenticationKeyID ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} \
                     -authenticationKeyIssuerID ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}

ipaファイルのアップロード

--type ios
アップロードする際にはtypeをiOSを指定

App Store API Keyを使用して、App Store Connectへアップロードします

 - name: Upload ipa to TestFlight
        run: |
          xcrun altool --upload-app -f export/SchemeName.ipa \
                       --type ios \
                       --apiKey ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} \
                       --apiIssuer ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} \
                       --apiPrivateKey $pwd/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8

事後処理

不要ファイルを削除します

      - name: Cleanup
        run: rm ExportOptions.plist `pwd`/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8

詰まったところ

MacOS 仮想環境のバージョンについて

mac-osの仮想環境ではXCodeが1バージョンしか指定できなくなっていた。

(作成した当時はmac-osのlatestを選択するとsonoma(MacOS14 - XCode15)が指定され、Xcode16が見つからんぞ〜って怒られる。
※2024年11月中旬

ログ

Switching Xcode to version '16.1.0'...
Available versions:
┌─────────┬──────────┬─────────────┬─────────────┬────────┬──────────────────────────────────┐
│ (index) │ version  │ buildNumber │ releaseType │ stable │ path                             │
├─────────┼──────────┼─────────────┼─────────────┼────────┼──────────────────────────────────┤
│ 0       │ '15.4.0' │ '15F31d'    │ 'GM'        │ true   │ '/Applications/Xcode_15.4.app'   │
│ 1       │ '15.3.0' │ '15E204a'   │ 'GM'        │ true   │ '/Applications/Xcode_15.3.app'   │
│ 2       │ '15.2.0' │ '15C500b'   │ 'GM'        │ true   │ '/Applications/Xcode_15.2.app'   │
│ 3       │ '15.1.0' │ '15C65'     │ 'GM'        │ true   │ '/Applications/Xcode_15.1.app'   │
│ 4       │ '15.0.1' │ '15A507'    │ 'GM'        │ true   │ '/Applications/Xcode_15.0.1.app' │
└─────────┴──────────┴─────────────┴─────────────┴────────┴──────────────────────────────────┘
Error: Could not find Xcode version that satisfied version spec: '16.1.0'

そのため、macos-15(sequoia)とXcodeのバージョンを直接指定

jobs:
  deploy:
    # MacOS 15(sequoia)を指定
    runs-on: macos-15
    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Set up Xcode
        uses: maxim-lobanov/setup-xcode@v1
        with:
            # Xcodeのバージョンを直接指定
            xcode-version: "16.1.0"

Archive commandについて

WatchOSを含む場合は -sdk optionを設定したらビルドでこける

(...Watch系のPackageを取得後にこけていた。いまいち理解できなくて時間がたくさん溶けました笑

note: Disabling previews because SWIFT_VERSION is set and SWIFT_OPTIMIZATION_LEVEL=-Owholemodule, expected -Onone (in target 'SwiftUI Apple Watch Decimal Pad' from project 'SwiftUI Apple Watch Decimal Pad')
note: Disabling previews because SWIFT_VERSION is set and SWIFT_OPTIMIZATION_LEVEL=-Owholemodule, expected -Onone (in target 'Supabase' from project 'Supabase')
** ARCHIVE FAILED **

古い記事ですが、ここを参照

コメントの直後の行を削除すると動くようになりました。

      - name: Archive Scheme
        run: |
          xcodebuild -project ProjectName.xcodeproj \
                     -scheme SchemeName \
                     -configuration Release \
                     # ↓ sdkを指定するとbuildエラーになる
                     -sdk iphonesimulator
                     archive -archivePath SchemeName.xcarchive \
                     CODE_SIGNING_ALLOWED=NO

証明書の名前について

証明書の命名には規約があるようです。
(自分はapp_store_connect_key.p8のような命名にして8時間ぐらい時間を溶かしました...)

"Error Domain=ITunesConnectionAuthenticationErrorDomain Code=-26000 \"Failed to generate JWT token: Error Domain=NSCocoaErrorDomain Code=-43 \"Failed to load AuthKey file.\" UserInfo={NSLocalizedDescription=Failed to load AuthKey file., NSLocalizedFailureReason=The file \U2018AuthKey_***.p8\U2019 could not be found in any of these locations: '~/path/to/root/private_keys', '~/private_keys', '~/.private_keys', '~/.appstoreconnect/private_keys'.}\" UserInfo={NSLocalizedRecoverySuggestion=Failed to generate JWT token: Error Domain=NSCocoaErrorDomain Code=-43 \"Failed to load AuthKey file.\" UserInfo={NSLocalizedDescription=Failed to load AuthKey file., NSLocalizedFailureReason=The file \U2018AuthKey_***.p8\U2019 could not be found in any of these locations: '~/path/to/root/private_keys', '~/private_keys', '~/.private_keys', '~/.appstoreconnect/private_keys'.}, NSLocalizedDescription=Failed to generate JWT token: Error Domain=NSCocoaErrorDomain Code=-43 \"Failed to load AuthKey file.\" UserInfo={NSLocalizedDescription=Failed to load AuthKey file., NSLocalizedFailureReason=The file \U2018AuthKey_***.p8\U2019 could not be found in any of these locations: '~/path/to/root/private_keys', '~/private_keys', '~/.private_keys', '~/.appstoreconnect/private_keys'.}, NSLocalizedFailureReason=App Store operation failed.}"

AuthKey_{API_KEY_ID}.p8という形式で指定しましょう

      - name: Save App Store Connect Private Key to File
        run: |
          mkdir private_keys
          echo "${{ secrets.APP_STORE_CONNECT_PRIVATE_KEY }}" > ./private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8

と、まぁ色々引っかかりましたがなんとかデプロイするGithub Actionが完成しました。

iOSのみのアプリを書き出す際のxcodebuildコマンドは割とネットに転がっていましたが、AppleWatchアプリを含む場合のxcodebuildコマンドはなかなか見つからなかったので苦労しました〜

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?