OTA 更新の本番運用実践マニュアル
本番環境で OTA 更新を安全に実行する方法を解説します。段階的なリリース、リアルタイム監視、ロールバック戦略を組み合わせれば、どのリリースにも確信を持って臨めます。
日本語
コピー

Expo の OTA 更新サービス(EAS Update)は、数分でユーザーの手元に更新を届けられる。もちろん便利だが、更新が実環境でどう振る舞うかを観察したいときには、あえて速度を落としたほうが役に立つこともある。
最も強いシグナルは、実ユーザー、実デバイス、実トラフィックから得られる。EAS Update は高速な配信を狙いつつ、更新をどう本番環境に投入するか、そしてシグナルがどこで現れるかを自分で制御できるように設計されている。
1 回の更新をテストするために費やす時間と範囲が増えるほど、多くの場合それは安全になる。だが本番環境が無限の時間を与えてくれることはほとんどなく、速度を落とすことには確かなコストが伴う。EAS Update はこのトレードオフを消しはしない。露出範囲、タイミング、復旧手段を自分で握ることで、更新ごとに天秤のどこに落とすかを決められるようにする。
この記事では、段階的リリース、監視、中止、ロールバックまで、EAS Update を本番環境で運用するための実践的な方法を紹介する。軸は、これらの仕組みが実際の本番環境でどう振る舞うかにある。
Expo のドキュメントには、チームが EAS Update を使う際のデプロイパターンの例がいくつか挙げられている。本番環境へ直接出す 2 コマンドのフローから、staging channel とバージョン付きブランチを使い、リリース前により構造化されたテストを行うフローまで幅がある。
どのパターンを選ぶかで、更新のビルド方法と検証方法は変わる。ただ、ここで挙げる運用原則*(段階的に広げ、実際のシグナルを観察し、見えたものに応じて動く)*は、更新が本番環境に入った後ならどのワークフローでも当てはまる。
意図的に小さく出す
本番環境で小さく出すとは、たいてい露出範囲を絞るという意味になる。
更新を全ユーザーに即座に見せるのではなく、まず一部のユーザーにだけ届ける。これで露出範囲を限定でき、さらに広げる前に、更新が実環境でどう振る舞うかを観察する余地が生まれる。
rollout は、アプリが更新を確認する際にその更新を受け取れるユーザーの割合を制限する。残りのユーザーは前の更新を使い続ける。
この記事では、per-update rollouts に基づく例で説明する。これは公開済みの 1 つの更新に対して有効になる。
たとえば、低いロールアウト率で更新を公開できる。
eas update --rollout-percentage=10
コストも影響範囲も抑えられ、そのうえで更新が本番環境で実ユーザーとやり取りする様子を観察する時間が確保できる。
EAS Update はブランチベースのロールアウトにも対応している。ユーザーを別のブランチ(更新の流れ)へ段階的に切り替える方式だ。この 2 つのロールアウトモデルが実際にどう違うのか知りたい場合は、デプロイガイドに利用可能なロールアウトの種類が簡単にまとめられている。
実際の挙動を評価する準備ができたら、次はどのシグナルを見るべきか、それをどう読むかを押さえる番だ。
更新サイズと帯域について
ユーザーが更新をダウンロードするたびに帯域を消費する。たとえば週に 1 回更新を出し、ユーザーが頻繁にアプリを開くなら、1 か月で何度も更新をダウンロードすることになる。
EAS Update が提供する帯域はかなり余裕があるので、ほとんどのアプリは通常利用で上限に達することはない。更新サイズを小さくするのは、主に信頼性を上げ、頻繁に更新を出せる余裕を確保するためだ。
SDK 55から、Hermes バイトコード差分(現在ベータ版)を有効にできる。これを有効にすると、更新は完全な JavaScript bundle ではなくバイナリパッチとして配信される。クライアントは新しいバイトコードファイル全体をダウンロードするのではなく、インストール済みの内容に差分を適用するので、ダウンロードサイズと帯域消費の両方が減る。

バイトコード差分は使える帯域の余裕を大きく広げ、以前より少ないデータ量でユーザーがより多くの更新をダウンロードできるようにする。
本番環境でロールアウトを観察する
更新を一部のユーザーに配信すると、EAS ダッシュボードがその更新の本番環境での挙動をほぼリアルタイムで表示する。
更新の採用状況と数
まず見るべきものの 1 つは、実際に何人のユーザーが更新を受け取ったかだ。
たとえば 10% のロールアウトは、10% のユーザーがすぐに更新を適用するという意味ではない。デフォルトでは、アプリはコールドスタート時に更新を確認し、あればダウンロードする。更新は次回のアプリ再起動時に有効になるので、ユーザーが一斉に新バージョンへ移行することはない。
チームによっては fallbackToCacheTimeout を数秒早め、起動時にアプリを少し待たせて更新のダウンロードを完了させ、すぐ適用させることもある。採用は速くなるが、ダウンロード中はスプラッシュスクリーンが表示され続ける可能性があるため、起動時の挙動に影響する。
より一般的なのは、updates JS API を通じて更新のライフサイクルを観察し、それに応じて動くやり方だ。useUpdates のような hook は更新システムの状態(アプリが今更新を確認しているか、利用可能な更新があるか、ダウンロード済みかなど)を公開するので、アプリのレンダリング完了後に更新の採用を調整できる。
設定がどうであれ、ロールアウト中にたいてい見たいのは、採用率が即座に急上昇することではなく、時間とともに徐々に上がっていくことだ。
採用率が予想外に低いなら、それ自体がシグナルになる。ユーザーがアプリを起動する頻度が低く、更新をトリガーできていないかもしれないし、更新が想定したビルドに適用されていない可能性もある。たとえば、その更新が対象とするランタイムバージョンが、それらのビルドが対応するバージョンと違う、といったケースだ。
クラッシュと致命的エラー
ロールアウトの初期段階では、クラッシュデータが最も明快なシグナルになることが多い。起動時のクラッシュや致命的なランタイムエラーはすぐに表面化する。影響を受けたユーザーが、更新が動いたまさにその瞬間に遭遇するからだ。
まず気づくのは Expo dashboard の deployments と updates のビューだ。ここには更新ごとのクラッシュ回数と起動データが並んで表示される。

ある更新がなぜクラッシュするのかを突き止めるには、通常は外部のクラッシュ監視と組み合わせる必要がある。たとえば Sentry を連携すれば、スタックトレースとセッションコンテキストをデプロイのデータと一緒に確認できる。Sentry はほとんどの実行時クラッシュと例外を捕捉できるが、ごく初期の起動時クラッシュは App Store Connect や Play Console といったプラットフォームのクラッシュレポートでしか見えないことがある。
EAS Update にはエラーからの復旧機構も組み込まれている。新しい更新が起動直後にクラッシュした場合(アプリが何も描画する前に落ちた場合)、その更新を失敗とマークし、以前の動作していた更新に戻せる。アプリが使えない状態に陥るのを防ぐための防御策だ——起動するたびにクラッシュして、修正版をダウンロードするまでたどり着けない、という事態を避ける。
トレンドを見る
リリース初期のデータはノイズが多い。サンプル数が少ないと変動が増幅される。ましてや更新を受け取ったユーザーがごく一部であればなおさらだ。
単一のデータ点に反応せず、トレンドを見る。
-
更新を受け取るユーザーが増えるにつれて、クラッシュ率やエラー率は変化しているか?
-
クラッシュは更新の配信時点の前後に集中していないか?
こうしたシグナルを使って、対象範囲を広げたときに見えている挙動が変わるかどうかを判断する。より多くのユーザーが更新を受け取ってもクラッシュ率とエラー率が許容範囲にとどまるなら、通常は配信範囲を広げて妥当だ。広げるにつれて悪化するなら、いったん止めてそれ以上広げない。
安全に配信範囲を広げる
更新が限られた範囲でしばらく動いたら、次はより多くのユーザーに届けるかどうかを決める。
配信範囲を広げることは、更新そのものを変えるわけではない。新しいものをリリースしているのではなく、次に更新を確認したより多くのデバイスが同じ更新を受け取れるようにするだけだ。
たとえば、配信パーセンテージを上げるには:
eas update:edit
インタラクティブガイドに沿って、その更新を選び新しいパーセンテージを設定する。
範囲を広げる過程で監視しているシグナルが許容範囲のままであれば、更新が全ユーザーをカバーするまで配信を広げ続けてよい。
更新をロールバックする
配信中に問題が起きた場合、更新を止める、あるいは取り消す方法は2つある。どこまで進んだかによって変わる。
配信がまだ進行中なら、それを取り下げられる。更新がすでに全ユーザーに届いているなら、ロールバックする。
進行中の配信を取り下げる
配信がまだ進行中のときは、それを取り下げられる。取り下げると配信が停止し、制御用の更新が再配信されて、クライアントは以前の状態に戻る——すでに更新を受け取ったユーザーも含めて。
シグナルがこの更新を配信し続けるべきでないと示していて、全ユーザーに届く前に影響を取り消したいとき、取り下げが正しい選択だ。
進行中の配信を取り下げるには:
eas update:revert-update-rollout
配信完了後のロールバック
配信が完了したら*(たとえば 100% に達したら)*、取り下げられる配信はもうない。この時点でこの更新を動かし続けるべきでないと判断したら、ロールバックを使う。
ロールバックは新しい更新を配信し、クライアントに以前のバージョンを実行させる、あるいはビルトインの更新に戻させる。
ロールバックは、更新が完全に配信され、ユーザーを既知の正常な状態に戻す必要がある場合に使う。
以前の更新にロールバックするには:
eas update:rollback
インタラクティブガイドが、ロールバックの種類の選択と実行を助ける。
永続化状態の互換性に関する注意
配信を取り下げたり以前の更新にロールバックしたりできるのは、古いコードが新しい更新の作った永続化状態を引き続き正しく扱える場合に限る。
ある更新が後方互換性のない変更*(たとえばローカルストレージやデータベース schema の変更)*を導入していたら、ユーザーを古い更新に戻すとクラッシュや異常な挙動を引き起こす可能性がある。
安全にロールバックできない場合は、互換性を回復する新しい更新を配信する必要があるかもしれない。
更新の問題をデバッグする
Expo のドキュメントには詳細なデバッグガイドがあり、よくある失敗シナリオを一つずつ解説している。たとえばビルドが更新を受け取らない、runtime version が一致しない、更新が起動直後にクラッシュする、アセットの読み込みに失敗する、といったケースだ。expo-updates のログを確認する、runtime version を照合する、更新 manifest を調べる、といった実用的なデバッグ戦略も紹介している。
更新の問題のほとんどは、設定の不一致か、ビルド自体が期待する更新の条件を満たしていないかに行き着く。どこを見ればよいか分かっていれば、診断はたいてい難しくない。
おわりに
まだ本番環境で EAS Updates を使ったことがないなら、試す価値はある。更新をユーザーに直接届けるのは、最初は大きな一歩に見えるかもしれない。しかし段階的な配信、監視、ロールバックの手段があれば、更新は安心して進められるものになる。
EAS Updates は、素早く反復しながら主導権も手放さずにいられるようにする。変更を少しずつ導入し、実ユーザーのもとでどう振る舞うかを見て、必要なら対応する——それをすべて同じワークフローの中で行える。
EAS Update は優れた開発体験を提供し、チームが世界水準のユーザー体験と改善を素早く届けることに集中できるようにする。
適切な運用習慣が身につけば、更新は、アプリを毎日使う人たちのためにそれを継続的に改善していく、自然で信頼できる手段になる。