EAS Update の安全な運用 — stg / prd 分離
00要約Overview
Tools
- EAS UpdateOTA 配信Free
- GitHub Actionsstg の自動配信Free
- Expo Gostg の実機確認Free
01物語Story
Situation
1.1.1 と 1.1.2 で、開発ループとリリースの仕組みは通った。main にマージすると OTA が配信される。まず最初のリリースまでは、この構成で足りる。
Complication
問題は、リリースした後の改修フェーズである。一般的な構成はこうなっている。
main にマージ
↓
EAS Update
↓
公開ユーザー
この構成だと、デバッグコードや一時的な修正が誤って main に入ったとき、そのまま公開ユーザーへ OTA が届いてしまう。さらに、ネイティブコードを変更した後でも OTA は配信できるため、古いアプリへ互換性のない JavaScript が降ってクラッシュする危険もある。
Question
開発中のコードや、ネイティブ非互換な更新を、公開ユーザーへ誤って届けないようにするには?
02解決Solution
Criteria
- 開発中のコードが公開ユーザーへ届かないこと
- ネイティブ変更で古いアプリがクラッシュしないこと
- Expo Go による開発体験を維持できること
- 公開タイミングを自分で制御できること
Answer
出発点は、OTA が届く条件を正確に押さえることである。OTA が配信されるには、次の 2 つの条件を同時に満たす必要がある。
channel が一致
AND
runtimeVersion が一致
- channel … 配信先 (開発用か、公開用か)
- runtimeVersion … ネイティブ互換性
両方が一致した端末だけが OTA を受信する。逆に言えば、どちらか片方をずらせば、その端末には届かない。この性質を使って、2 つの経路を分離した。
channel で「配信先」を分ける。 LycoApp では配信チャネルを stg と prd の 2 つに分けている。
| channel | 用途 | 配信方法 |
|---|---|---|
| stg | 開発・検証 | GitHub Actions が自動配信 |
| prd | 公開ユーザー | 手動配信 |
main へのマージでは stg にだけ自動配信され、prd への配信は明示的に実行しない限り起きない。これで、開発中のコードが公開ユーザーへ流れる経路が構造的に塞がれる。
runtimeVersion で「ネイティブ互換性」を守る。 runtimeVersion は appVersion ポリシーを採用している。
{
"runtimeVersion": {
"policy": "appVersion"
}
}
こうすると version 1.0.0 のアプリの runtimeVersion は 1.0.0 になる。ネイティブコードを変えたときは version を 1.0.1 に上げる。すると runtimeVersion も自動で 1.0.1 に変わるため、1.0.0 のアプリには 1.0.1 の OTA が届かない。ネイティブ変更による非互換クラッシュを、バージョンを上げるという普段の操作だけで防げる。
Expo Go だけは例外を挟む。 Expo Go は runtimeVersion = exposdk:<SDK Version> しか認識できない。そこで GitHub Actions では、stg 配信のときだけ policy を一時的に sdkVersion へ切り替えて OTA を配信する。
{
"runtimeVersion": {
"policy": "sdkVersion"
}
}
この書き換えは CI 上だけで行い、Git にはコミットしない。ストアビルドと prd への OTA では、通常どおり appVersion のままである。開発体験 (Expo Go) と本番の安全性 (appVersion) を、両立させるための小さな仕掛けである。
Reason
注意力ではなく、仕組みで防ぎたかったからである。 「本番に間違って配信しないよう気をつける」という運用は、いつか必ず事故る。人はミスをする。だから OTA が届く条件そのものに手を入れた。channel をずらせば公開ユーザーには届かず、runtimeVersion をずらせば古いアプリには届かない。届く条件を握っておけば、届いてはいけないものは、そもそも届かない。これが一番安心して眠れる設計だと考えている。
Options
- 単一 channel のまま運用する — main → EAS Update → 公開ユーザー、という素の構成。設定は最もシンプルだが、誤配信とネイティブ非互換クラッシュのリスクをそのまま抱える。最初のリリースまではこれでよいが、改修フェーズに入る前に分離した。
03結果Result
Good
日常の開発フローは、こう落ち着いた。
修正 ↓ main にマージ ↓ GitHub Actions ↓ stg へ自動 OTA ↓ Expo Go で確認
公開するときだけ、GitHub Actions から prd の EAS Update を手動で実行する。結果として、開発中のコードは公開ユーザーへ届かず、ネイティブ変更によるクラッシュも防げ、Expo Go の快適な開発体験も残り、公開のタイミングも自分で握れる。狙った 4 つが、すべて成立した。
Bad
代わりに、ひと手間と分かりにくさが増える。prd は手動配信なので、公開のたびに自分で実行する必要がある。また、CI 上で runtimeVersion を一時的に書き換える仕掛けは、仕組みを知らないと「なぜここだけ policy が違うのか」と混乱しやすい。この分かりにくさを埋めるために、こうしてドキュメントに残している。
Follow-up
この stg / prd 分離は、一度組めば他のアプリでもそのまま使える。だから Git のテンプレートリポジトリにして、新規アプリはコピーして始める 運用にした。最初のリリースは 1.1.1 と 1.1.2 の素の構成で済ませ、リリースが済んだらこの分離を入れてテンプレ化しておく。以降のアプリは、最初から安全な OTA 運用の上でスタートできる。