朝専用SNS ”朝の実(Asanomi)” 開発記録 #6 〜TestFlight・CIの導入〜

朝の実(Asanomi)ロゴ アプリ開発

朝専用SNS「朝の実」では、TestFlight でテスト配布を始めるタイミングで、AsanomiTests を実行する最小限の CI も入れました。

この記事では、TestFlight と CI をそれぞれ簡単に整理したうえで、朝の実で実際に入れた内容をまとめます。


1. TestFlightとは

TestFlight は、公開前のアプリを実機へ配布し、テスターからのフィードバックを集めるための Apple の仕組みです。
App Store に公開する前に、配布、インストール、フィードバック収集までを Apple の導線の中で完結できます。

TestFlight には内部テストと外部テストがあり、配布方法が少し違います。
内部テストでは、テスターはApp Store Connect の登録が必要です。
一方、外部テストでは、テスターは「TestFlight アプリ」がダウンロードしてあればOKです。
ただし、外部テスターに配る場合は、ビルドを AppleのReview に通さなければなりません。

内部テスターは最大 100人、外部テスターは最大 10,000人 まで追加でき、ビルド後は 90日間 テストできます。
現在、朝の実では内部テストのみで自分が実機テストを行なっています。以下、TestFlight のメリットをまとめます。

  • 実機で公開前ビルドを配れる
  • App Store Connect 上でテスター管理ができる
  • フィードバックやスクリーンショットをApple の導線で回収できる(テスター負荷 小)

2. TestFlightの導入方法

ここでは、TestFlight の詳しい導入手順を1つずつ説明するのではなく、全体の流れだけに絞ります。
TestFlight の導入は、大きく 3ステップ です。

  1. App Store Connect > TestFlight でテスト情報を入力する
    テスターに見せる基本情報を入れます。
  2. Xcode からビルドをアップロードする
    ビルドが App Store Connect 側で処理されると、TestFlight で選べるようになります。
  3. テスターグループを作り、ビルドを割り当てる
    内部テスターや外部テスターを追加し、そのグループへビルドを配布します。

3. TestFlightのフィードバック機能

TestFlight の良いところは、配るだけで終わらず、フィードバックの回収までつながっていることです。
テスターは TestFlight アプリからコメントやスクリーンショットを送れます。

特に便利なのが スクリーンショットフィードバック です。
テスターはアプリを使っている最中に、いつも通りスクリーンショットを撮るだけで、その画面に対するフィードバックを送れます。専用の報告フォームを探したり、あとから状況を文章で説明し直したりしなくてよいのが便利です。

開発側では、App Store Connect の スクリーンショットフィードバック 画面から、どの画面で何が起きたのかを画像つきで見返せます。
「なんとなく使いにくい」ではなく、「この画面でここが気になる」という粒度で整理しやすいのが良いところです。

朝の実でも、投稿画面やホーム画面に対するフィードバックをこの画面で確認しています。
実機で使ったときの違和感や文言の分かりづらさは、こうした画面付きフィードバックが追いやすいです。

4. CIとは

CI は Continuous Integration(継続的な統合) の略で、ざっくり言えば「コード変更のたびに、ビルドやテストを自動で回す仕組み」です。
以下、CIで行う処理の例です。(これ以外にもやれることはたくさんあります)

  • ビルド
  • Lint
  • Format チェック
  • Unit Test
  • UI Test

CI では、繰り返し確認する機械的なチェックを自動化します。
たとえば「ビルドが通るか」「テストが落ちていないか」「コードの書き方が一定のルールに沿っているか」を、PR作成時やブランチへのpush時に毎回同じ条件で確認できます。

これにより、人が確認する範囲を減らして、一定の品質を安定して確保できます。

5. CIの導入方法

朝の実では、GitHub Actions で CI を入れています。
最初にやったのは次の3つです。

  1. CI で使う scheme を決める
  2. .github/workflows/ci.yml を作る
  3. push や PR で xcodebuild test が動くことを確認する

ここから、それぞれを少し詳しく見ていきます。

1. CIで使うschemeを Shared にする

ここでいう scheme は、Xcode のビルドやテストの実行設定です。
Xcode では、どのアプリをビルドするか、どのテストを実行するかを scheme にまとめて管理します。

CI 用の scheme は Xcode 上で Shared にします。
Shared にした scheme は GitHub で管理されるため、GitHub Actions から参照できるようになります。
(以下の設定画面は、Xcode画面中央上部のアプリ名(scheme名)の部分を押下すると出てきます)

2. .github/workflows/ci.ymlを作る

.github/workflows/ci.yml は、GitHub Actions に「いつ」「どの環境で」「どのコマンドを実行するか」を伝える設定ファイルです。
リポジトリ内の決まった場所にこのファイルを置くと、GitHub が workflow として読み取ってくれます。

GitHub Actions の workflow は YAML で書きます。
今の朝の実では、develop, main への PR と、develop, main への push で走る設定にしています。

※ ci.yml の実際の内容は 「6. 朝の実で使用しているCIの内容」で公開してます。

3. pushやPRでxcodebuild testが動くことを確認する

設定を書いたら、実際に対象ブランチへ push するか、PR を作成して GitHub Actions が起動することを確認します。
朝の実では、GitHub Actions 上で xcodebuild test が実行され、その結果を GitHub の Actions 画面で確認できる状態にしました。

GitHub Actionsでxcodebuild testが実行され、CIが成功している画面

この CI はローカルの simulator を使うのではなく、GitHub Actions の macOS runner 上で動きます。
つまり、ネット上の macOS 環境でビルドし、その runner 上の iOS Simulator でテストしている形です。

6. 朝の実で使用しているCIの内容

朝の実で今使っている CI は、かなり最小限です。
対象は AsanomiTests の実行で、UI Test、lint、Format チェック、TestFlight 配布の自動化まではまだ入れていません。

name: CI

on:
  # main/develop 向けの PR で実行
  pull_request:
    branches: [main, develop]
  # main/develop ブランチへの push で実行
  push:
    branches: [main, develop]

jobs:
  build-test:
    # Xcode が使える macOS runner
    runs-on: macos-15

    # 何かが固まったときに CI が待ち続けないよう、最大実行時間を決めておく
    timeout-minutes: 30
    env:
      # ビルド対象の Xcode プロジェクト
      XCODE_PROJECT: Asanomi.xcodeproj
      # CI で使う scheme
      XCODE_SCHEME: Asanomi-CI
      # CI では simulator 向けに deployment target を明示する
      CI_IOS_DEPLOYMENT_TARGET: "18.5"

    steps:
      # GitHub Actions の runner に、このリポジトリのコードを取得する
      - uses: actions/checkout@v6

      # Unit Test を実行する
      # xcodebuild test は、テスト前に必要なビルドもまとめて実行してくれる
      - name: Unit Tests
        run: |
          # 指定した project / scheme を、指定 simulator 上でテストする
          # -only-testing で AsanomiTests だけに絞っている
          xcodebuild \
            -project "$XCODE_PROJECT" \
            -scheme "$XCODE_SCHEME" \
            -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.5' \
            IPHONEOS_DEPLOYMENT_TARGET="$CI_IOS_DEPLOYMENT_TARGET" \
            -only-testing:AsanomiTests \
            test

構文として見ると、ポイントは次の7つです。

  • on
    workflow を起動するタイミングを指定します。ここでは pull_requestpush を指定し、それぞれ対象ブランチを branches で絞っています。
  • jobs
    実行する処理のまとまりを定義します。ここでは build-test という1つの job を作っています。
  • runs-on
    job を実行する環境を指定します。iOS アプリのビルドやテストには Xcode が必要なので、ここでは macOS runner を使っています。
  • env
    job 内で使う環境変数を定義します。プロジェクト名や scheme 名、deployment target のように何度も使う値をここにまとめています。
  • steps
    job の中で実行する手順を上から順に並べます。uses は既に用意されている Action を使う指定で、ここでは actions/checkout@v6 を使ってリポジトリのコードを runner に取得しています。
  • run
    runner 上で実行するシェルコマンドを書きます。複数行のコマンドを書くときは | を使い、その下にコマンドを並べます。
  • xcodebuild test
    Xcode のテストをコマンドラインから実行します。-project-scheme-destination で対象を指定し、-only-testing で実行するテストを絞っています。

7. まとめ

TestFlight は、公開前のアプリを実機で配布し、フィードバックを集めるための仕組みです。
一方で CI は、ビルドやテストのような機械的に確認できる処理を、同じ条件で自動実行するための仕組みです。

朝の実では、TestFlight で実機確認を始めるタイミングで、GitHub Actions による最小限の CI も入れました。
今の CI では xcodebuild testAsanomiTests を実行し、処理側のテストを GitHub Actions 上で確認できるようにしています。

まだ UI Test や lint、TestFlight 配布の自動化までは入れていません。
まずは TestFlight で人が見る部分と、CI で毎回同じ条件で見る部分を分けるところから始めました。

sho shimizu

SwiftUI を用いた iOS アプリの個人開発を行っています。
これまでに2本のアプリを App Store にリリースしました。

現在は、朝専用SNS「朝の実(Asanomi)」を開発中です。
アプリを作る中で学んだことや、設計・実装で考えたことを、
あとから振り返れるように技術記事としてまとめています。

sho shimizuをフォローする
アプリ開発朝の実開発記録
シェアする
sho shimizuをフォローする