1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【iOS】GitHubActionsでCI/CD構築

Posted at

はじめに

個人開発のiOSアプリでCI/CDを構築したので書いていきます。以下の仕様です。

  • GitHubActionsを用いる
  • ブランチ戦略
    • main: 開発統合ブランチ
    • release: リリースブランチ
    • feature/XXX: 開発作業ブランチ
  • タイミングと内容
    • mainのpush/PR, releaseのPR
      • ビルド
        • テストは未実装のため行わないが代わりにビルドできるかを確認する
    • releaseへのpush
      • アーカイブ
      • AppStoreConnectへのアップロード
  • その他使用パッケージ
    • SPM
      • TCA (The Composable Architecture)
    • CocoaPod
      • AWSMobileClient

参考文献

こちらの記事が非常に役立ちました。著者のYahiroさんありがとうございます。

参考文献との大きな違いはCocoapodとSwift Macrosを導入している点でした。

環境変数

参考文献の準備編がとてもわかりやすいです。

ワークフロー

プロジェクト名はMyAppにしているので一斉置換してください

mainブランチ用

name: main

on:
  push:
    branches: ["main"]
  pull_request:
    branches: ["main", "release"]

  workflow_dispatch:

jobs:
  build:
    runs-on: macos-15

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Xcode 16.4
        uses: maxim-lobanov/setup-xcode@v1
        with:
          xcode-version: "16.4"

      - name: Cache SPM
        uses: actions/cache@v3
        with:
          path: |
            ~/Library/Caches/org.swift.swiftpm
          key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
          restore-keys: |
            ${{ runner.os }}-spm-

      - name: Cache Pods
        uses: actions/cache@v3
        with:
          path: |
            Pods
            ~/Library/Caches/CocoaPods
            ~/.cocoapods
          key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-pods-

      - name: Cache DerivedData
        uses: actions/cache@v3
        with:
          path: .derivedData
          key: ${{ runner.os }}-derived-${{ hashFiles('MyApp.xcodeproj/project.pbxproj', '**/*.swift', '**/*.h') }}
          restore-keys: |
            ${{ runner.os }}-derived-

      - name: Install CocoaPods
        run: |
          gem install cocoapods
          pod install

      - name: Build
        run: |
          xcodebuild build \
            -workspace MyApp.xcworkspace \
            -scheme MyApp \
            -sdk iphoneos \
            -configuration Release \
            -destination 'generic/platform=iOS' \
            -derivedDataPath .derivedData \
            -skipMacroValidation \
            CODE_SIGNING_ALLOWED=NO \
            ENABLE_SWIFT_MACROS=YES

変更点は以下の通りです。

  • XCodeのバージョン指定
  • キャッシュ追加
  • build時にマクロに関する引数追加

release用

name: release

on:
  push:
    branches: ["release"]

  workflow_dispatch:

jobs:
  release-archive:
    runs-on: macos-15

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Xcode 16.4
        uses: maxim-lobanov/setup-xcode@v1
        with:
          xcode-version: "16.4"

      - name: Cache SPM
        uses: actions/cache@v3
        with:
          path: |
            ~/Library/Caches/org.swift.swiftpm
          key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
          restore-keys: |
            ${{ runner.os }}-spm-

      - name: Cache Pods
        uses: actions/cache@v3
        with:
          path: |
            Pods
            ~/Library/Caches/CocoaPods
            ~/.cocoapods
          key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-pods-

      - name: Cache DerivedData
        uses: actions/cache@v3
        with:
          path: .derivedData
          key: ${{ runner.os }}-derived-${{ hashFiles('MyApp.xcodeproj/project.pbxproj', '**/*.swift', '**/*.h') }}
          restore-keys: |
            ${{ runner.os }}-derived-

      - name: Install CocoaPods
        run: |
          gem install cocoapods
          pod install

      - name: Build
        run: |
          xcodebuild archive \
            -workspace MyApp.xcworkspace \
            -scheme MyApp \
            -archivePath MyApp.xcarchive \
            -sdk iphoneos \
            -configuration Release \
            -destination 'generic/platform=iOS' \
            -skipMacroValidation \
            CODE_SIGNING_ALLOWED=NO \
            ENABLE_SWIFT_MACROS=YES

      - 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_ISSUE_ID }}.p8

      - name: Export IPA
        run: |
          xcodebuild -exportArchive -archivePath MyApp.xcarchive -exportOptionsPlist ExportOptions.plist -exportPath MyApp.ipa -allowProvisioningUpdates -authenticationKeyPath `pwd`/private_keys/AuthKey_${{ secrets.APPLE_API_ISSUE_ID }}.p8 -authenticationKeyID ${{ secrets.APPLE_API_KEY_ID }} -authenticationKeyIssuerID ${{ secrets.APPLE_API_ISSUE_ID }}

      - name: Upload to App Store Connect
        run: |
          xcrun altool --upload-app -f MyApp.ipa/MyApp.ipa -t ios -u ${{ secrets.APPLE_ID }} -p ${{ secrets.APP_SPECIFIC_PASSWORD }} --type ios

考察

もともとGitHubActions + Fastlane + Firebase AppDistributionを使った自動テスト配布を行っていましたが、AWSの認証周りと不整合が起きたので直近では専ら手動アップロードしてTestFlightを使っていました。そこでGitHubActionsのみでAppStoreConnectにアップロードする形へ切り替えたわけです。

切り替え前は12~20分とかなりばらつきがあり、しかも長い時間がかかっていました。

切り替え直後もあまり変わりませんでしたが以下の対応でかなり短縮されました

  • podのクリーンインストール
    • これは本当に効果あったか微妙だが、実行前はAWSCoreのビルドにかなり時間がかかっていた
  • Firebase-iOS-SDKの削除
    • AppDistributionを使用しなくなったため削除

これによりmainのビルドは4分半、releaseのアーカイブも10分半になりました。
またreleaseの手動アップロード時はせっかくPRしたのにプルし忘れたままアーカイブ取ることが多発していたので、これによりかなり改善されるでしょう。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?