コンテンツにスキップ
Webフロントエンドエンジニアのための React Native 実践入門
Esc
navigateopen⌘Jpreview
このページの内容

第21章 アップグレードを継続するためのスキル

短くなり続けるSDKリリースに追従するための手順と、エージェントとSkillsで手間を減らす進め方を扱います。

リリースしたアプリは「作って終わり」ではなく、ここからが運用の始まりです。Expo SDKは長らく年3回のペースでリリースされてきましたが、後述するとおり近年はもっと短い間隔へ動いています。対応するReact Nativeのバージョンもそれに合わせて更新されます。周辺ライブラリはさらに細かく、月1〜2回のペースで更新が入ることも珍しくありません。古いSDKに留まり続けるとEAS Buildのサポート期限が切れたり、ストアのtargetSdkVersion要件に引っかかって新規提出ができなくなったりするので、定期的なアップグレードは「やって良いこと」ではなく「やらざるを得ないこと」と考えてください。

本章ではアップグレードの考え方と、これをいかに楽に回すか ― 特にAIエージェントとSkillsの組み合わせで省力化する方法を扱います。

アップグレードの全体像

Expoのアップグレードは大きく3つの動きを束ねたものです。

  • Expo SDKそのもののバージョン上げ(SDK 54 → 55 → 56)
  • React Nativeのバージョン上げ(SDKに紐づく)
  • 周辺ライブラリのバージョン上げ(Reanimated、Gesture Handlerなど)

Expo SDKのバージョンを1つ上げると、対応するReact Nativeバージョンと、Expoがメンテしている主要ライブラリのバージョンが芋づる式に決まります。npx expo installコマンドはこの「SDKに合った組み合わせ」をJSONで持っているので、これに頼るのが基本です。

リリースは速くなり、1回あたりは軽くなっている

ここ最近で状況が変わってきているので、先に触れておきます。

React Nativeがリリース頻度を年6回へ引き上げ、あわせて2回に1回は「利用者に影響する破壊的変更を含まない」リリースを目指すという方針が打ち出されました。Expo側もこれを受けて、従来のように年数回の大きなSDKへ変更をまとめるのではなく、破壊的変更のない更新はより短い間隔で、任意で上げられる形で出していく方向を模索しています。

実例を挙げると、2026年6月30日にリリースされたSDK 57は、React Nativeを0.85から0.86へ上げる一方、Reactのバージョンは19.2のままSDK 56から据え置きでした。「番号は上がったが、自分のコードに手を入れる必要はほとんどない」という類のリリースです。

読者にとって大事なのは、回数が増えることと、1回あたりが重くなることは別だという点です。むしろ1回の差分が小さくなるぶん、こまめに上げるほうが楽になります。逆に「まとめて上げよう」と溜め込むと、破壊的変更を含む回といない回が団子になって、いちばん面倒な形で襲ってきます。本章の最後に月1回のメンテナンス時間を勧めているのは、この理由からです。

SDKをひとつ上げる手順

公式の標準的な流れです。

# expo本体と関連ライブラリを、互換性のあるバージョンへまとめて揃える
npx expo install expo@latest --fix

# 動作確認
npx expo start --clear
npm test

--fixオプションは「現在のExpo SDKに合うバージョンに、関係ライブラリを揃え直す」ものです。バージョンの食い違いを自動で直してくれるので、SDKを上げた直後にこれを実行する習慣をつけておきましょう。

--clearはMetroのキャッシュをクリアしてから起動するオプションで、SDKを上げた直後は古いキャッシュが原因で謎エラーが出やすいので必須です。

最後に、第14〜16章で書いたテストを走らせます。ストアのロジックやresolveColorSchemeのような純粋関数のテストは、SDKを上げてもほぼそのまま通るはずです。テストが通れば、その範囲では退行していないと自信が持てます。

マイグレーションガイドを読む

--fixで済む」のは、純粋にバージョン番号だけが変わったケースです。実際にはSDKごとにBreaking Changesがあります。

ExpoはSDKごとに「Upgrade Guide」と「Changelog」を公開しています。読むのは面倒ですが、エラーで詰まってからより、最初に目を通したほうが結局速いです。とくに次のセクションは外せません。

  • Removed APIs: 削除されたAPI(これを使っていれば確実に壊れる)
  • Behavior Changes: 互換性は保たれているが挙動が変わったAPI(壊れないが結果が変わる)
  • New Architecture関連: SDK 54〜55はNew Architectureの強制移行期にあたるので、ここで詰まる人が多い

短いマイグレーションなら20〜30分、大きなものでも数時間で読み切れます。

upgrading-expo Skill

ここからが本書の特色です。Expoは**upgrading-expo**というAIエージェント向けのスキルを公式に提供しています。Coding Agent(Claude CodeやCursorなど)がExpoのアップグレード作業を進めるためのチェックリストとガイドです。

利用するには、expo/skillsリポジトリで公開されているスキルを取り込みます。Claude Codeなら、

/skill upgrading-expo

のようにスキル参照を有効にして、

このプロジェクトを最新のExpo SDKに上げてください

と頼むだけで、

  1. 現在のSDKバージョンを検出
  2. 対象SDKまでのChangelogとマイグレーションガイドを取得
  3. package.jsonを更新し、npx expo install --fixを実行
  4. Breaking Changesに該当するコードを検索して修正案を出す
  5. テストを走らせて、失敗があれば原因を分析

をエージェントが順序立てて実行してくれます。差分はPRとしてレビューできる形で出てくるので、人間は判断と承認に集中できます。

実際にやると分かりますが、SDKアップグレードは「やる気を出す」ところが一番重い作業です。upgrading-expoを介するとその腰の重さが大幅に軽くなります。

AIエージェントがSDKの更新、依存関係の更新、テスト実行を進め、プルリクエストとして差分をまとめる流れ

ライブラリの単独アップグレード

SDKは据え置きで、特定のライブラリだけ上げたい場面もあります。たとえば

  • ReanimatedのバグFixが入った新バージョンをすぐ取り込みたい
  • 自作モジュールが依存しているSDKの新バージョンが出た

という状況です。

npx expo install react-native-reanimated@latest

npm installではなくnpx expo installを使うのは、Expo SDKが許容する範囲のバージョンに自動でクランプしてくれるからです。@latestを指定しても、Expo SDKが対応していないメジャーバージョンには上げません。

@latestより厳密に上げたい場合は、npx expo install --checkで「ずれているライブラリ」を検出できます。

npx expo install --check

Some dependencies are using outdated versions: react-native@0.83.4 → 0.83.6

のように出力されるので、必要に応じて--fixで揃えます。

OTA更新との合わせ技

第18章で触れたEAS Updateは、ネイティブ部分を変えないアップグレードに使えます。

  • アイコンやスプラッシュの差し替え → ネイティブ変更 → ストア再提出
  • Expoモジュールの追加 → ネイティブ変更 → ストア再提出
  • 文言修正、UI調整、JSロジックの修正 → JSのみ → EAS Updateで配信

「ストア提出が必要なアップデート」と「OTAで足りるアップデート」を仕分けるのは、運用に乗ってからのコツです。とくに小さなバグ修正をすぐ届けられるのは、ユーザー体験に直結します。

ただし、過信は禁物です。EAS Updateで配ったコードがネイティブ側の前提を破ると、起動時にクラッシュしてユーザーがアプリを開けなくなります。本番チャンネルへのeas updateの前には、previewチャンネルのテスターで一度確認するのを推奨します。

Fingerprintで「OTAで足りるか」を機械的に判定する

「ネイティブが変わったかどうか」を目で見て判断するのは事故のもとです。Expoには**@expo/fingerprint**という仕組みがあり、package.jsonapp.jsonios//android/配下のネイティブコードなどから、その時点での「ネイティブ依存のハッシュ値」を計算できます。

npx @expo/fingerprint .

EAS UpdateとEAS Buildはこのfingerprintを内部的に持っていて、ビルド時とアップデート配信時のfingerprintが一致するときだけ更新が適用されるように設定できます(eas.jsonruntimeVersion: { policy: "fingerprint" })。fingerprintが変わっている=ネイティブが変わっているので、OTAで配るとクラッシュするであろうケースをそもそも届かなくしてくれる、という仕組みです。

「ライブラリを追加してOTAで配ったらユーザー全員のアプリが落ちた」という典型的な事故を、これで自動的に防げます。Expoで真面目に運用するなら、runtimeVersion"fingerprint"にしておくのが基本線です。

fingerprintは事故防止だけでなく、CIの短縮にも効きます。ネイティブが変わっていないビルドを丸ごとスキップする運用の例はReact NativeのQAビルド時間を約80%改善した話 — Expoのfingerprint × repackでフルビルドをスキップにまとめてあります。

OTAは「行動ログ分析」とのトレードオフがある

機能的な変更をOTAで配ると、アプリのバージョン番号が変わらないままユーザーの手元にあるJSバンドルだけ差し替わります。手軽な反面、ログ分析の観点では地味に厄介です。

たとえば「v1.2.0でCVRが下がった」と気づいたとき、v1.2.0の中で配信したOTAバンドルが3種類あれば、どのバンドルでの計測かを切り分ける必要があります。アプリのバージョンに加えて、OTAのバンドルバージョン(Updates.updateIdなどで取得)もログに乗せておかないと、後から原因の切り分けが難しくなります。

「軽微な文言修正やバグfixはOTA、機能追加やUIの大きな変更はストア提出」のように、ログ分析を無理に複雑化させない運用ルールを最初に決めておくと、後で困りません。

クラッシュレポートとログ収集

ストアに出した後は、ユーザーの端末で起きるクラッシュやエラーが手元に届かなくなります。代わりにエラー監視ツールを入れて、本番のクラッシュ・エラーをサーバ側に集める仕組みを用意します。React NativeではSentryがデファクトです。

npx expo install @sentry/react-native
npx @sentry/wizard@latest -i reactNative

ウィザードがルートレイアウトへのSentry.init挿入、app.config.tsへの@sentry/react-native/expoプラグイン登録、metro.config.jsへのソースマップ送信用ラッパ追加までやってくれます。手で入れる場合の最小コードは次のとおりです。

// app/_layout.tsx
import * as Sentry from "@sentry/react-native";

Sentry.init({
  dsn: process.env.EXPO_PUBLIC_SENTRY_DSN,
  tracesSampleRate: 0.2,
});

export default Sentry.wrap(RootLayout);

Sentry.wrapでルートをラップしておくと、未捕捉の例外とReactのエラー境界がまとめて拾われます。tracesSampleRateはパフォーマンス計測のサンプリング率なので、本番では低めに設定するのが無難です。

ソースマップはEAS Build中にSentryへアップロードします。本番アプリはHermesバイトコードに変換されているので、ソースマップが無いと「obfuscatedFn at index.bundle:1」のようなスタックトレースしか見えず、原因特定がほぼできなくなります。SENTRY_AUTH_TOKENsensitiveEAS環境変数として登録しておけば、CIから自動でアップロードされます(第18章の環境変数管理を参照)。

無料枠でも個人開発の範囲なら十分回るので、ストア提出前にウィザードを通しておくのがおすすめです。

パフォーマンスを継続的に見る ― EAS Observe

Sentryが拾うのは「落ちた」「エラーが出た」という異常です。一方で「起動が遅くなった」「特定の画面だけ重い」といった劣化は、クラッシュしない以上そこには出てきません。この領域を埋めるのが、Expoが提供するEAS Observeです(執筆時点ではオープンベータ)。

npx expo install expo-observe

導入後はルートレイアウトをObserveRoot(SDK 56以降。SDK 55ではAppMetricsRoot)で包み、アプリが操作を受け付けられる状態になった時点でmarkInteractive()を呼びます。あとはコールドスタート/ウォームスタートの時間、最初の描画までの時間、操作可能になるまでの時間(TTI)、バンドルの読み込み時間といった指標が自動で集まります。Expo Routerを使っていれば、画面(ルート)ごとに分けて見られます。

この仕組みが効くのは、ビルドとOTA更新がタイムライン上のマーカーとして並ぶ点です。ひとつ前の節で「同じアプリバージョンの中にOTAバンドルが複数あると、どれでの計測か切り分けにくい」と書きました。EAS ObserveはExpoのリリースパイプラインと繋がっているので、起動時間や画面の重さについては「どのビルド、どの更新から変わったか」をそのまま追えます。CVRのような行動ログの切り分けは引き続き自前で仕込む必要がありますが、パフォーマンスに関してはこの手間が要りません。

なお、クラッシュやエラーの追跡は現時点では対象外で、将来的な追加が予定されている段階です。Sentryの置き換えではなく、役割の違う道具と考えてください。「落ちたか」はSentry、「遅くなったか、どのリリースからか」はEAS Observe、という住み分けです。

Expo Goでは動かないので、確認にはDevelopment Buildか本番ビルドが要ります。料金は月間アクティブユーザー1万人までは無料です。

継続のために習慣化する

メンテナンスを「特別な作業」にせず日常に組み込むためのコツを最後に共有します。

ひとつめは、月1回のメンテナンス時間を確保することです。新機能の開発と切り離して、ライブラリの更新確認、expo install --checkの実行、ChangelogとUpgrade Guideのななめ読みだけする時間を取ります。1時間で十分です。リリース間隔が短くなったぶん1回の差分は小さいので、この頻度で追いかけていれば「気付いたら数バージョン遅れていて手がつけられない」状態を避けられます。日々の動きを週刊React Nativeのようなニュースレターで拾っておくと、この1時間で読むべきものを絞り込めます。

ふたつめは、テストとCIを薄くでも置いておくことです。第17章で書いたとおり、ストアのロジックと純粋関数だけでも自動テストがあれば、SDKを上げた後の安心材料になります。GitHub Actionsでnpm testtsc --noEmitを走らせるだけでも、退行検出には十分です。

3つめは、aiエージェントとSkillsの活用を前提にした作業手順を整えることです。upgrading-expo、Expo標準のexpo/skillsagent-deviceなどを組み合わせると、アップグレード作業の半分以上は人の手作業から外れます。本書のサンプルアプリも、これらのスキルとの相性を意識した構成にしてあります。

おわりに

本書では、Webフロントエンド開発の知識を起点に、React NativeとExpoでアプリをひとつ作り、ストアに公開し、運用に入るまでを通して扱いました。第14〜18章で組み上げたTODOアプリは、機能としては地味かもしれませんが、Expo RouterZustandAsyncStorageStyleSheetStorybookEAS Build、ストア提出という、現代的なReact Nativeアプリ開発の道具立てを一通り含んでいます。これを土台に、皆さん自身のアプリへ自由に拡張していってください。

次に読むもの

本書で触れきれなかった領域のうち、2つは別途ガイドブックを用意しています。どちらもブラウザで動くデモを見ながら読める構成なので、手を動かしながら進められます。

そして、本書を読み終えたあとにいちばん効くのは、変化を追い続けることです。ここまで繰り返し書いてきたとおりReact NativeとExpoは動きの速い領域なので、書籍の内容はどこかで必ず古くなります。追いかける先を2つ挙げておきます。

本章で「月1回のメンテナンス時間を確保する」と書きましたが、その1時間を実のあるものにするには、日頃からゆるく流れを掴んでおくのがいちばんの近道です。

「自分のスマホで動くアプリを作ってみたい」という入口の気持ちが、この本を読み終えたあとに「なるほど作れる」に変わっていれば、書いた甲斐があります。

それでは、よいReact Nativeライフを!

最終更新 2026年7月24日