◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Expo SDK 58 が 10/15 に正式リリースされました(Beta は 09/15 から)。上げる前に依存の対応状況を確認しましょう●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Expo SDK 58 が 10/15 に正式リリースされました(Beta は 09/15 から)。上げる前に依存の対応状況を確認しましょう●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/アプリ開発
◇ アプリ開発/2026-10-23中級

SDK 58 で削除された React Native の API を、アップグレード前に洗い出すスクリプト

Expo SDK 58 で削除された InteractionManager・Touchable・Modal の animated・StatusBar の一部 props などを、ソースから一括で探す Node スクリプトです。サンプルで動かした出力と、拾えないものの線引きも記します。

Expo SDK 585React Native241アップグレード4点検スクリプトInteractionManager

アップグレードの前夜に、いちばん避けたいのは「上げてみて、赤い画面が出てから原因を探す」ことです。SDK 58 の公式お知らせ(expo.dev/changelog の SDK 58)を読み直したところ、React Native 側の API がまとまって削除されていました。

書かれている項目を、そのまま引用に近い形で並べます。

  • InteractionManager が削除されました(代わりは requestIdleCallback)
  • react-native のルートからの Touchable の export が削除されました
  • Modal の animated prop が削除されました
  • StatusBar の backgroundColor・translucent・networkActivityIndicatorVisible が削除されました
  • react-native/Libraries/* からの深い import は、型エラーになります

どれも、一つひとつは小さな変更です。ただ、個人開発で長く触っているアプリほど、どこに何が残っているのかを自分の記憶だけでは数えきれません。そこで、ソースを走査して該当行を出すだけの小さなスクリプトを書き、サンプルで動かしました。

先に結論です

削除された API の使用箇所は、grep を何回か打つより、規則を一か所に書いたスクリプトで一度に出すほうが漏れにくいと感じました。理由は二つあります。StatusBar や Modal のように、props が複数行にまたがって書かれるタグは、行単位の grep では拾えません。もう一つは、import { Touchable } のように、ほかのパッケージの同名の語と区別したいものがあることです。

何を拾い、何を拾わないか

線引きを先に決めておきます。

対象拾い方備考
InteractionManager語そのもの(コメント行は除外)import にも呼び出しにも反応します
深い importreact-native/Libraries/ を含む文字列TypeScript の型エラーとも重なります
Touchablereact-native からの import 波括弧の中だけTouchableOpacity などは拾いません
Modal の animated開始タグ全体(複数行可)props 内に => があると途中で切れます
StatusBar の削除済み props開始タグ全体(複数行可)同上
expo-sqlite の libSQLsyncLibSQL・libSQLOptions・useLibSQL設定ファイル側は別に確認します
File.write()expo-file-system を import したファイルの .write(await のない行を拾います

拾わないものも決めました。ネイティブ側の変更(R8 の有効化、iOS のシーンベース・ライフサイクル)と、Node.js のバージョン要件は、ソースを読んでも分からないからです。これらは最後の節で、別の確認方法を書きます。

点検スクリプト

依存は Node だけです。node sdk58-removed-api-scan.mjs ./my-app のようにプロジェクトのルートを渡します。該当があれば終了コード 1 を返すので、CI に載せることもできます。

// sdk58-removed-api-scan.mjs — Expo SDK 58 で削除・変更された API の使用箇所を洗い出します
// 使い方: node sdk58-removed-api-scan.mjs <プロジェクトのルート>
import { readdirSync, readFileSync, statSync } from 'node:fs';
import { join, extname, relative } from 'node:path';
 
const root = process.argv[2] ?? '.';
const EXT = ['.ts', '.tsx', '.js', '.jsx'];
 
const walk = (d) =>
  readdirSync(d).flatMap((n) => {
    if (n === 'node_modules' || n.startsWith('.') || n === 'ios' || n === 'android') return [];
    const p = join(d, n);
    return statSync(p).isDirectory() ? walk(p) : EXT.includes(extname(p)) ? [p] : [];
  });
 
const lineOf = (text, index) => text.slice(0, index).split('\n').length;
 
// 行単位の規則: [名前, 正規表現, 直し方]
const LINE_RULES = [
  ['InteractionManager', /\bInteractionManager\b/, 'requestIdleCallback に置き換えます'],
  ['react-native 深い import', /['"]react-native\/Libraries\//, 'react-native の公開 export へ。急ぐなら tsconfig の customConditions で先送りできます'],
  ['Touchable (ルート export)', /import\s*\{[^}]*\bTouchable\b[^}]*\}\s*from\s*['"]react-native['"]/, 'Pressable などへ置き換えます'],
  ['expo-sqlite libSQL', /\bsyncLibSQL\b|\blibSQLOptions\b|\buseLibSQL\b/, 'libSQL は削除されています。同期の仕組みを別に用意します'],
];
 
// JSX タグ単位の規則: [名前, タグ名, 属性の正規表現, 直し方]
const TAG_RULES = [
  ['Modal の animated', 'Modal', /\banimated\b/, 'animationType に置き換えます'],
  ['StatusBar の削除済み props', 'StatusBar', /\b(backgroundColor|translucent|networkActivityIndicatorVisible)\b/, '削除された props です。背景色は画面側の View に持たせます'],
];
 
let total = 0;
const report = (rel, line, name, fix) => {
  total++;
  console.log(`${rel}:${line}  ${name}  → ${fix}`);
};
 
for (const p of walk(root)) {
  const text = readFileSync(p, 'utf8');
  const rel = relative(root, p);
  const lines = text.split('\n');
  lines.forEach((l, i) => {
    if (/^\s*(\/\/|\*)/.test(l)) return; // コメント行は数えません
    for (const [name, re, fix] of LINE_RULES) if (re.test(l)) report(rel, i + 1, name, fix);
  });
  for (const [name, tag, attr, fix] of TAG_RULES) {
    const tagRe = new RegExp(`<${tag}\\b[^>]*>`, 'g');
    for (const m of text.matchAll(tagRe)) if (attr.test(m[0])) report(rel, lineOf(text, m.index), name, fix);
  }
  // expo-file-system の File.write() は SDK 58 から非同期です
  if (/from\s*['"]expo-file-system['"]/.test(text)) {
    lines.forEach((l, i) => {
      if (/\.write\(/.test(l) && !/await\s/.test(l) && !/\.then\(/.test(l)) {
        report(rel, i + 1, 'File.write() が await されていません', 'await を付けるか、従来の挙動なら writeSync() を使います');
      }
    });
  }
}
console.log(total ? `\n${total} 件` : '該当なし');
process.exitCode = total ? 1 : 0;

規則は LINE_RULES(行単位)と TAG_RULES(JSX タグ単位)に分けました。タグ単位にしたのは、<StatusBar から /> までが三行にまたがる書き方を拾うためです。あとから項目が増えたら、配列に一行足すだけで済みます。

サンプルで走らせた結果

削除対象を意図的に混ぜた二つのファイルと、何も混ぜていない空のプロジェクトで試しました。コメントの中の InteractionManager と、await を付けた File.write() は、拾わない想定のものです。

app/home.tsx:1  InteractionManager  → requestIdleCallback に置き換えます
app/home.tsx:2  Touchable (ルート export)  → Pressable などへ置き換えます
app/home.tsx:6  InteractionManager  → requestIdleCallback に置き換えます
app/home.tsx:13  Modal の animated  → animationType に置き換えます
app/home.tsx:9  StatusBar の削除済み props  → 削除された props です。背景色は画面側の View に持たせます
app/store.ts:2  react-native 深い import  → react-native の公開 export へ。急ぐなら tsconfig の customConditions で先送りできます
app/store.ts:7  File.write() が await されていません  → await を付けるか、従来の挙動なら writeSync() を使います
 
7 件

空のプロジェクトでは「該当なし」と表示され、終了コードは 0 でした。コメント行と await 付きの行が数えられていないことも、同じ実行で確かめています。

なお、この出力は私が用意した小さなサンプルの結果です。実際のアプリでの件数ではありません。実際のアプリで何件出るかは、手元で走らせてみないと分からないところです。

出力の読み方と、直す順番

出力を眺めて、直す順番を次のように決めました。

  1. 型エラーになるもの(深い import)を先に。tsconfig.json の customConditions に "react-native-legacy-deep-imports" を足せば先送りできますが、お知らせによると、この逃げ道は React Native 0.89 のあとに外される予定です。先送りは一回きりと考えるほうが安全です
  2. 動作が変わるもの(File.write() の非同期化)を次に。await を忘れると、書き込み完了を待たずに次の処理へ進みます。画面上は何も起きず、あとから読んだファイルが空という形で現れやすい種類の変更です
  3. 画面の見た目に出るもの(StatusBar・Modal)は最後に。動作確認を実機で兼ねられます

ソースを読んでも分からない変更は、別の道具で

最後に、このスクリプトが拾えない変更を三つ書き留めます。

  • Node.js: Expo のツール類は 22.13 以上、24.3 以上、26 以上が必要で、奇数の 23 と 25 は対象外と書かれています。node -v で確認します
  • R8: リリースビルドで android.enableMinifyInReleaseBuilds=true が既定になります。リフレクションを使うライブラリは ProGuard の keep ルールが必要になることがあります。止めたい場合は expo-build-properties で false にできます
  • iOS のシーン・ライフサイクル: プレビルドが SceneDelegate.swift と Info.plist の UIApplicationSceneManifest を生成します。AppDelegate.swift を手で触っているプロジェクトは、公式の移行手順に沿って確認します

関連して、ほかの SDK 58 の変更の点検記録もあります。環境変数の読み込み規則はSDK 58 から .env.staging は読み込まれません。手元の .env 系ファイルを、70行ほどのスクリプトで棚卸ししますに、Stripe を使うプロジェクトのビルドはStripe を入れた Expo SDK 58 で pod install が止まる — precompiled modules を切るか、直るまで待つかの判断に書きました。依存パッケージ側の推奨がどれだけ動くかは、expo のパッチを1つ上げると、expo install の推奨が何個動くのかを数えましたで数えています。

アップグレードは、壊れてから探すより、削除された名前を先に数えておく。 それだけで、当日の迷いはかなり減ります。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

◇ アプリ開発2026-10-22
SDK 58 から .env.staging は読み込まれません。手元の .env 系ファイルを、70行ほどのスクリプトで棚卸しします
Expo SDK 58 以降、expo のコマンドは .env.staging などの独自ファイルを読み込まず、NODE_ENV の指定も上書きされます。読み込まれるファイルと優先順位を点検するスクリプトを、サンプルで動かして確かめた記録です。
◈ Rork 入門2026-10-17
Expo SDK 58 に上げる前に、自分のコードで消える API を一覧にしておく
Expo SDK 58 の変更履歴から、削除・挙動変更・非推奨の API を拾って自分のプロジェクトを走査する検査スクリプトを書きました。試験プロジェクトでの実行結果と、走らせて初めて気づいた落とし穴つきで書き残します。
◇ アプリ開発2026-10-21
iOS では動く expo-widgets が Android のビルドだけで落ちる — 版の固定と除外、どちらで逃げるかの判断
expo-widgets を 58.0.17 以降に上げると Android だけ Kotlin のコンパイルで止まる報告があります。症状の見分け方、版の固定と autolinking 除外の使い分け、手元で判定できる確認スクリプトをまとめました。