SWSH の Expo ベース自動モバイルリリースパイプラインの内部
SWSH は1つの React Native コードで4つのプラットフォームを動かし、自社ハードウェア上で毎月300回のビルドを実行し、署名資格情報はチームが一切扱わない。
日本語
コピー

「Expo のエコシステムのおかげで、ローカルビルドからリリース検証まで、リリースフローにおける人為的なミスと手作業をなくせました。」
— Nathan Ahn、SWSH 最高技術責任者
1つのコードベースで全プラットフォーム
SWSH はソーシャル写真共有アプリで、共有アルバムやイベントに使われている。1つのチームが iOS、iOS App Clip、Android、Web を同時にリリースするとなれば、4つのビルドツールと、それぞれに対応するリリースチェックリストを維持しなければならないと思うだろう。しかし実際には、そのすべてが同じ React Native コードで動いており、リリース時に手作業で進める部分はほとんどない。

この事例が示すのは、SWSH がどうやってここまで来たかだ。毎月 300 回のビルドを自前のハードウェアで回し、署名資格情報はチームが一切触らず、App Store Connect はブラウザではなく API 経由で操作し、リリース前に必ず走らせる自作のエンドツーエンドテストスイートも用意している。
Web は別のリリーストラックなので、ここから先はネイティブの 3 ターゲットだけを扱う。変更はローカルビルドから始まり、iOS シミュレータと Android シミュレータ上のエンドツーエンドテストスイートを通り、最後に 2 つのアプリストアへ届く。ほぼ人手を挟まない。ネイティブ版はおよそ週 1 回リリースされ、パイプラインが安全に着地させる。
リリースを日常業務にする
モバイルアプリをリリースしたことがあれば、この流れは見慣れているはずだ。ビルドを出し、署名資格情報を扱い、App Store Connect と Google Play に提出し、その過程でリグレッションが起きていないか確認する。手作業でやるなら、どのステップもリリースが静かに壊れるポイントになり、頻度が上がるほどそのミスの代償は大きくなる。
そこで SWSH はチェーン全体に手を付けた。リリースパイプライン全体を自動化し、人為的ミスが入り込む余地をなくす。 Expo のビルド・提出ツールはこの自動化を最初から提供しており、その上に別のものを積めるだけの土台もある。
なぜ Expo が自動リリースパイプラインの最良の基盤なのか
Expo は SWSH に、ソースからストアまでの単一の自動化パスを与える。ビルド、資格情報、提出、そして OTA 更新だ。
Continuous Native Generation(expo prebuild)により、チームは Xcode や Gradle のプロジェクトを手で保守することなく、ネイティブプロジェクトを必要なときに再生成できる。必要ならネイティブコードを直接書くことも今もできる。しかも EAS はローカルでもクラウドでも同じビルドツールを動かすので、SWSH は EAS のオーケストレーション、資格情報管理、提出機能をそのまま使いながら、ビルドが実際どこで走るかの制御を手放さずに済む。
SWSH のリリースパイプラインの中へ
ローカルビルドを規模で回す:EAS Build
世界中のほぼすべてのモバイルチームにとって、Expo のクラウドビルドは堅実な選択だ。SWSH が例外なのは量のせいだ。ネイティブコードが絡む pull request ごとに iOS と Android のフルビルドを走らせ、さらに環境ごとのリリースビルドも加わる。1 か月で合計 300 回になる。この規模になると計算が変わり、チームは ローカル EAS ビルド に切り替えて、コンパイルを自前の macOS と Android の runner に移した。
EAS の見落とされがちな点が一つある。eas build がローカルでもクラウドと同じように動くおかげで、SWSH はオーケストレーション、資格情報の処理、提出をそのままに、最もリソースを食うコンパイル工程だけを自前のハードウェアに移せた。
チームが管理する必要のない資格情報:EAS
App Store Connect と Google Play の署名資格情報は EAS に保管されている。SWSH の CI が持つのは Expo access token 1 つだけだ。コード署名はモバイルリリースで最も CI 設定やリポジトリに散らばっていてはいけないものだが、SWSH ではそもそもそこに存在しない。
2 つのストアへの提出:EAS Submit とカスタムの App Store Connect パイプライン

EAS Submit は Google Play と App Store Connect への提出を担い、カスタムのつなぎコードなしで各ビルドを両ストアへ直接プッシュする。Google Play ではこれで十分だ。iOS はバイナリの周りでやることがもっと多い。新しい App Store バージョンの作成、メタデータとリリースノート、App Clip 体験の設定、そして審査への提出。
そこで SWSH は EAS Submit とは別に、App Store Connect 用のパイプラインを自前で組んだ。ビルドのアップロードが完了すると、このパイプラインが App Store Connect API を直接叩く。処理済みのビルドをポーリングし、App Store バージョンを作成し、メタデータと「What's New」の文言を設定する。続いて App Clip のデフォルト体験を、カードのサブタイトルやカード画像といった細部まで設定し、最後にバージョンを審査に提出する。
App Clip 体験を手作業で設定したことがある人なら、どれだけのウィンドウを開くことになるか分かるだろう。SWSH はそれをリリースフローの中のもう一つの自動ステップに変えた。
SWSH は App Store のメタデータを、EAS Metadata——Expo の宣言的メタデータソリューション——ではなく、カスタムパイプラインで管理している。ほとんどのチームは自前でパイプラインを書く必要はなく、EAS Metadata をそのまま使えばいい。
すべてのリリースを検証する:Meridian
何かをリリースする前に、SWSH は必ず Meridian を走らせる。Appium と WebDriverIO をベースに、Vitest で駆動する自社開発のエンドツーエンドテストフレームワークだ。Meridian は CI 上のシミュレータとエミュレータで iOS、App Clip、Android をカバーし、本当に重要なフローを通す。ログイン、サインアップ、アップロード、ディープリンク。つまり SWSH が「このリリースは検証済み」と言うとき、それはコンパイルが通ったという意味ではなく、アプリが実際にこれらのフローを走らされたという意味だ。

JavaScript の修正を配信する:EAS Update
ネイティブコードに触れない変更なら、EAS Update で SWSH は JavaScript の修正を即座に配信できる。
Meridian もこれらのアップデートを検証している。ここは見習うべき点だ。EAS Update はユーザーがすでに持っているネイティブビルドに新しい JavaScript を届ける仕組みなので、SWSH は更新後のバンドルに対してテストスイートを流し、新しいコードがそのビルドと互換性を持つこと、リグレッションを持ち込んでいないことを確認する。
本番環境でリグレッションを捕まえる:EAS Observe
リリースは終わりではない。SWSH は EAS Observe で本番環境のアプリの挙動を監視し、初回レンダリングや操作可能になるまでの時間といったランタイム指標を追跡している。あるバージョンが起動やレンダリングのリグレッションを持ち込めば、ここで露見する。チームはそのまま無線で修正を配信できる。
自動化されたリリースパイプラインがもたらしたもの
エンジニアは変更をプッシュしたら、あとは別の作業に移れる。ビルド、検証、提出、監視はバージョンごとにパイプラインが代行する。ビルドは月およそ 300 回、ネイティブ版は週に 1 回程度、JavaScript の修正はその日のうちに無線で配信される。
SWSH は、リリース頻度の高さと安全なリリースがトレードオフではないことを示した。パイプラインを一度きちんと作り込んでしまえば、リリース作業に取られていた労力をアプリ本体に戻せる。