◉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 から)。上げる前に依存の対応状況を確認しましょう●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●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 から)。上げる前に依存の対応状況を確認しましょう●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/Rork入門
◈ Rork入門/2026-10-17中級

Expo SDK 58 に上げる前に、自分のコードで消える API を一覧にしておく

Expo SDK 58 の変更履歴から、削除・挙動変更・非推奨の API を拾って自分のプロジェクトを走査する検査スクリプトを書きました。試験プロジェクトでの実行結果と、走らせて初めて気づいた落とし穴つきで書き残します。

Expo SDK 58アップグレード3React Native240移行個人開発219Rork588

✦ プレミアム記事

SDK 58 の変更履歴を開いて、最初に感じたのは「長い」ということでした。

削除されるもの、挙動が変わるもの、非推奨になるもの。それぞれが別の節に分かれていて、読み終えたころには、最初の節に何が書いてあったかが曖昧になっております。読んで理解したつもりでも、いざ自分のプロジェクトに当てはめると、どこが該当するのかは別の作業として残ります。

そこで、読む順番を逆にしてみました。変更履歴から「検索できる形のもの」だけを先に拾い出して、自分のプロジェクトを走査する小さなスクリプトにします。読んで判断するのは、その一覧が出てからです。

Expo SDK 58 は 2026 年 10 月 15 日に公開されました(expo.dev/changelog の掲載による)。React Native は 0.86 から 0.88 へ上がります。Rork から書き出したプロジェクトも中身は普通の Expo プロジェクトですが、Rork 側が SDK 58 にいつ対応するかは、私の確認した範囲では案内がありません。ここで書くのは、書き出したあとのリポジトリを自分で上げる場合の話です。

先に、何を拾うかを三つに分けます

変更履歴の項目を、そのまま並べても点検にはなりません。点検の優先度で三つに分けました。

  • REMOVED(消える): 残っているとビルドか型検査が止まります。最優先です
  • BEHAVIOR(挙動が変わる): 動きはするが結果が変わります。意図と合っているかを人間が見る必要があります
  • DEPRECATED(非推奨): 今は動きます。上げる当日ではなく、次の機会に直せば足ります

変更履歴の記載から、検索の対象にしたのは次の項目です。

区分対象直し先
REMOVEDInteractionManager/Touchable のルート export/NativeMethods 型/Modal の animated propPressable・instance 型・animationType など
REMOVEDreact-native/Libraries/* への deep import(Strict TypeScript API が既定)公開 API からの import
REMOVEDexpo-sqlite の syncLibSQL/libSQLOptionslibSQL 対応そのものが削除
BEHAVIORFile.write() が非同期に(expo-file-system)await するか writeSync()
BEHAVIORexpo-notifications がフォアグラウンドでも表示される意図した挙動かを確認
BEHAVIORNODE_ENV=test の expo start が .env.development を読むテスト用の env の置き場を見直す
DEPRECATEDFile.md5/ImageBackground/withLayoutContextFile.digest()/View+Image/integrateWithRouter

StatusBar の非推奨 prop も削除対象と書かれていますが、どの prop かまでは私は特定できておりません。スクリプトには一例として networkActivityIndicatorVisible を入れてあり、該当するかどうかは公式の一覧で確かめる前提にしています。

検査スクリプト全文

Node.js だけで動きます(SDK 58 は Node 22.13 以上、24.3 以上、または 26 以降が前提です。奇数の 23・25 は対象外と書かれています)。依存パッケージはありません。

// audit-sdk58.mjs — SDK 58 へ上げる前に、プロジェクト内の「消える・変わる」API を一覧にする
// 使い方: node audit-sdk58.mjs [プロジェクトのパス]
import { readdirSync, readFileSync, existsSync, statSync } from 'node:fs';
import { join, relative, extname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
 
const SELF = fileURLToPath(import.meta.url); // 自分自身は検査対象から外す
 
const root = process.argv[2] ?? '.';
const SKIP = new Set(['node_modules', '.git', 'ios', 'android', '.expo', 'dist']);
const EXT = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs']);
 
// level: REMOVED=消える/BEHAVIOR=挙動が変わる/DEPRECATED=非推奨(今は動く)
const RULES = [
  { id: 'rn-interactionmanager', level: 'REMOVED', re: /\bInteractionManager\b/, why: 'RN から削除。requestAnimationFrame か、描画後に走らせたい処理を useEffect 側へ' },
  { id: 'rn-touchable-root', level: 'REMOVED', re: /import\s*\{[^}]*\bTouchable\b[^}]*\}\s*from\s*['"]react-native['"]/, why: 'Touchable のルート export が削除。Pressable へ' },
  { id: 'rn-nativemethods', level: 'REMOVED', re: /\bNativeMethods\b/, why: 'NativeMethods 型が削除。ViewInstance など instance 型へ' },
  { id: 'rn-modal-animated', level: 'REMOVED', re: /<Modal\b[^>]*\banimated\b/, why: 'Modal の animated prop が削除。animationType を使う' },
  { id: 'rn-deep-import', level: 'REMOVED', re: /from\s*['"]react-native\/Libraries\//, why: 'Strict TypeScript API が既定。Libraries/* の deep import は型エラー' },
  { id: 'rn-statusbar-ios-props', level: 'REMOVED', re: /<StatusBar\b[^>]*\bnetworkActivityIndicatorVisible\b/, why: 'StatusBar の非推奨 prop の一部が削除対象。この prop が該当するかは公式の変更履歴で確認(ここは例)' },
  { id: 'fs-file-write', level: 'BEHAVIOR', re: /\.write\(/, why: 'expo-file-system の File.write() は非同期に。同期のままなら writeSync()(File 以外の .write も拾うので目視)' },
  { id: 'fs-md5', level: 'DEPRECATED', re: /\.md5\b/, why: 'File.md5 は非推奨。File.digest() へ' },
  { id: 'sqlite-libsql', level: 'REMOVED', re: /\b(syncLibSQL|libSQLOptions|useLibSQL)\b/, why: 'expo-sqlite の libSQL 対応が削除' },
  { id: 'rn-imagebackground', level: 'DEPRECATED', re: /\bImageBackground\b/, why: '非推奨。View + 絶対配置の Image へ' },
  { id: 'router-withlayoutcontext', level: 'DEPRECATED', re: /\bwithLayoutContext\b/, why: '非推奨。integrateWithRouter へ' },
  { id: 'notif-foreground', level: 'BEHAVIOR', re: /from\s*['"]expo-notifications['"]/, why: 'フォアグラウンド通知が既定で表示される。意図した挙動か確認' },
  { id: 'nodeenv-test', level: 'BEHAVIOR', re: /NODE_ENV=test/, why: 'NODE_ENV=test で expo start すると .env.development を読む' },
];
 
function* walk(dir) {
  for (const name of readdirSync(dir)) {
    if (SKIP.has(name)) continue;
    const p = join(dir, name);
    const st = statSync(p);
    if (resolve(p) === SELF) continue;
    if (st.isDirectory()) yield* walk(p);
    else if (EXT.has(extname(name)) || name === 'package.json') yield p;
  }
}
 
const hits = [];
for (const file of walk(root)) {
  const lines = readFileSync(file, 'utf8').split('\n');
  lines.forEach((line, i) => {
    for (const r of RULES) if (r.re.test(line)) hits.push({ r, file: relative(root, file), line: i + 1, text: line.trim() });
  });
}
 
// ネイティブ側の確認(CNG でない場合に効く)
const notes = [];
if (existsSync(join(root, 'ios'))) notes.push('ios/ があります。CNG なら削除して再生成、手書き管理なら AppDelegate のシーン対応(SceneDelegate.swift)を確認');
if (existsSync(join(root, 'android'))) notes.push('android/ があります。R8 が release で既定オンになるため keep ルールを確認');
 
const order = { REMOVED: 0, BEHAVIOR: 1, DEPRECATED: 2 };
hits.sort((a, b) => order[a.r.level] - order[b.r.level] || a.file.localeCompare(b.file));
for (const h of hits) console.log(`[${h.r.level}] ${h.file}:${h.line}  ${h.r.id}\n    ${h.text}\n    → ${h.r.why}`);
const c = (l) => hits.filter((h) => h.r.level === l).length;
console.log(`\n集計: REMOVED ${c('REMOVED')} / BEHAVIOR ${c('BEHAVIOR')} / DEPRECATED ${c('DEPRECATED')}`);
notes.forEach((n) => console.log('NOTE: ' + n));
process.exit(c('REMOVED') > 0 ? 1 : 0);

なぜこう書くかを三点だけ補足します。

  1. ルールを配列にして、why に直し先まで書いておきます。 出力を読んだ時点で次の行動が決まるようにするためです。ルールを足すのも一行で済みます
  2. 終了コードを REMOVED の有無で変えています。 後から CI に載せるとき、REMOVED がゼロでなければ止める、という使い方がそのままできます
  3. ios/ と android/ の存在を最後に注記します。 ネイティブ側は文字列検索では見えないので、「ここは別の確認が要ります」と出すだけに留めました
✦

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

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦SDK 58 に上げた直後にビルドが赤くなる前に、自分のコードのどこが対象かを行番号つきで一覧にできるようになります
✦「全部読む」と「上げてから直す」の中間にあたる、三十分で終わる事前点検の型を自分のプロジェクトに置けるようになります
✦検索で拾えるものと拾えないものの線引きがわかり、手元の点検に頼りすぎずに済むようになります
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

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

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

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

関連記事

◈ Rork 入門2026-10-13
個人アカウントで出した iOS アプリを、あとから法人へ移せるか——App Transfer の前に外す5つ
個人の Apple Developer アカウントで公開した iOS アプリを、あとで法人アカウントへ移す手順の前提を、Apple の公式ページで確かめて整理しました。移す前に外すもの、引き継がれるもの、引き継がれないものの一覧です。
◈ Rork 入門2026-09-14
Rork の新規作成から Expo が消えました。手元のプロジェクトを続けるか、SwiftUI へ作り直すか
Rork では Expo(React Native)の新規プロジェクトを作れなくなりました。既存の Expo アプリは動き続けます。続けるか SwiftUI へ作り直すかを、公式ドキュメントの記述と、作り直しで実際に抜け落ちる場所から判断する材料をまとめます。
◈ Rork 入門2026-09-08
Rork Max が要るかどうかは、料金表ではなく権限の棚卸しで判断できます
Rork Max に上げるべきか迷ったとき、料金表を先に見ないようにしています。app.json と Info.plist から実際に要求している OS 機能を抜き出し、標準版で届くもの・設定で届くもの・ネイティブが要るものへ仕分ける手順を書き残します。