RORK LABEN
MAX — Rork MaxはReact NativeではなくネイティブSwiftアプリを生成。iPhone・iPad・Watch・TV・Vision Pro・iMessageに対応しますNATIVE — AR/LiDAR・Metalの3Dゲーム・Dynamic Island・Live Activities・HealthKit・Core MLなどネイティブ機能を解放しますCORE — 通常のRorkはReact Native(Expo)でiOS/Androidアプリを生成。自然言語からストア公開まで到達できますFUNDING — Rorkはa16zから$2.8Mを調達しましたGROWTH — 月間743,000訪問・成長率85%と勢いを増していますPRICING — 無料で始められ、有料プランは$25/月〜ですMAX — Rork MaxはReact NativeではなくネイティブSwiftアプリを生成。iPhone・iPad・Watch・TV・Vision Pro・iMessageに対応しますNATIVE — AR/LiDAR・Metalの3Dゲーム・Dynamic Island・Live Activities・HealthKit・Core MLなどネイティブ機能を解放しますCORE — 通常のRorkはReact Native(Expo)でiOS/Androidアプリを生成。自然言語からストア公開まで到達できますFUNDING — Rorkはa16zから$2.8Mを調達しましたGROWTH — 月間743,000訪問・成長率85%と勢いを増していますPRICING — 無料で始められ、有料プランは$25/月〜です
記事一覧/開発ツール
開発ツール/2026-06-22上級

壊れたキャッシュで毎回起動時に落ちるアプリ——ユーザーが自力で抜け出せる「セーフモード起動」を設計する

永続化したキャッシュが壊れて起動のたびに同じ場所で落ちると、ユーザーには再インストールしか残りません。アプリ自身が早期クラッシュの連続を数え、対話可能になって初めて起動を確定し、危険な状態だけを段階的にリセットするセーフモードを、Expo(React Native)の実装で設計します。

Rork439Expo93React Native175クラッシュ対策4MMKV6設計4

プレミアム記事

個人開発で複数のアプリを運用していると、ごくたまに「特定の端末だけ、起動した瞬間に落ちて二度と開けない」という報告が届きます。私自身、永続化していた設定の一部が壊れたレコードになり、起動時の復元処理がそこで例外を投げて、以後は何度開いても同じ場所で落ち続ける状態に遭遇したことがあります。

厄介なのは、この状態に陥ったユーザーには手段がほとんど残らないことです。アプリは開けない、設定画面にもたどり着けない、つまりアンインストールして入れ直す以外にできることがありません。起動ループはそのまま離脱率に直結します。そして再インストールは、レビュー欄でいちばん辛辣な一言につながります。

ここで扱いたいのは、壊れた状態を後から手で直すことではありません。アプリ自身が「自分は起動のたびに早期に落ちている」と気づき、危険な状態だけを段階的に捨てて立ち上がり直す——そんなセーフモード起動の設計を扱います。

なぜ ErrorBoundary や Crashlytics では抜け出せないのか

まず、既存の備えがこの問題のどこに効かないかを整理しておきます。

ErrorBoundary は強力ですが、守れるのは React のレンダーツリーの内側だけです。起動ループの多くは、プロバイダが永続ストアを復元している最中や、ネイティブ側のモジュール初期化で起きます。ツリーがマウントされる前に落ちれば、境界は捕まえる対象を持ちません。React の例外捕捉の基本は未処理の Promise まで取りこぼさない ErrorBoundary の設計で扱っていますが、それでも「マウント前のクラッシュ」は守備範囲の外です。

Crashlytics はクラッシュを記録してくれますが、記録は事後です。ユーザーの端末でループが止まるわけではありません。iOS の 0x8badf00d ウォッチドッグ終了のように OS がメインスレッドの停滞で殺してくるケースとも違い、ここで問題なのは「コードは正しく動いているのに、与えられた永続データが壊れている」点です。コードを直しても、すでに壊れた状態を持っている端末は救われません。

つまり必要なのは、観測でも捕捉でもなく、端末側で自走する回復ロジックです。起動直後の白画面・クラッシュの切り分けを一歩進め、切り分けをアプリ自身にやらせる、と考えると分かりやすいかもしれません。

設計の核:起動を「未確認」で数え、対話可能になって初めて確定する

仕組みの中心はとても単純です。

起動が始まった瞬間に「未確認の起動」を1つ増やします。そしてアプリが実際に対話可能な状態(最初の画面が描画され、ユーザーが触れる状態)まで到達したら、その未確認カウントをゼロに戻します。これを「起動の確定」と呼ぶことにします。

もしアプリが対話可能になる前に落ちれば、確定は実行されません。未確認カウントは増えたまま残ります。次の起動でまた増え、また落ちれば、カウントは積み上がっていきます。これが連続して一定回数に達したとき、「この端末は起動ループに入っている」と判断します。

import { MMKV } from 'react-native-mmkv'
 
const store = new MMKV({ id: 'boot-guard' })
const KEY_PENDING = 'boot.pending'      // 未確認の連続起動回数
const KEY_LAST = 'boot.lastStartAt'     // 直近の起動開始時刻
const FAILED_BOOT_THRESHOLD = 3         // この回数の連続失敗でセーフモード
const RECENT_WINDOW_MS = 30_000         // この間隔を超える起動は「連続」とみなさない
 
export type BootDecision = { safeMode: boolean; failedBoots: number }
 
// プロバイダを一切マウントする前に、エントリの先頭で呼ぶ
export function beginBoot(): BootDecision {
  const now = Date.now()
  const lastStart = store.getNumber(KEY_LAST) ?? 0
  let pending = store.getNumber(KEY_PENDING) ?? 0
 
  // 速い連続でなければ起動ループではない。数え直す
  if (now - lastStart > RECENT_WINDOW_MS) pending = 0
 
  store.set(KEY_PENDING, pending + 1)
  store.set(KEY_LAST, now)
 
  // この起動を始める前に、すでに閾値ぶん落ちているか
  return { safeMode: pending >= FAILED_BOOT_THRESHOLD, failedBoots: pending }
}
 
// 対話可能になったら呼ぶ。これで連続失敗カウントが消える
export function confirmBoot() {
  store.set(KEY_PENDING, 0)
}

RECENT_WINDOW_MS を挟んでいるのは、誤検知を避けるためです。ユーザーがアプリを開いてすぐ閉じ、数日後にまた開いた——というのはクラッシュループではありません。連続して短時間に起動が積み上がったときだけをループとみなします。

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

この記事の続きを読む

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

この記事で得られること
ErrorBoundary でも Crashlytics でも救えない「起動ループ」を、アプリ自身に気づかせて自己回復させる設計
起動を未確認で数え、対話可能になって初めて確定する仕組みと、なぜ同期ストレージ(MMKV)でないと数えられないのか
被害範囲を最小にする段階的リセットの梯子と、ユーザー作成データを絶対に触らないための原則
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

開発ツール2026-05-07
Rork で作ったアプリの「原因不明クラッシュ」を撲滅する — Error Boundary と Unhandled Promise の実戦的な捕捉法
Rork が生成したコードに頻出する「await のエラー握り潰し」と「ErrorBoundary なし」の組み合わせが原因で、本番アプリが原因不明で落ちる問題。実装で解決する手順を解説します。
開発ツール2026-06-22
Rork(Expo)のトーストは、重なっても読み上げられても崩れない設計にする
Rork が生成した React Native アプリにトースト通知を足すとき、単純な実装は『同時に2つ出ると重なる』『スクリーンリーダーに無視される』『ノッチやホームインジケータに隠れる』の3点で破綻します。ルート1か所に置くキュー設計、本体の再レンダーから切り離すアニメーション、AccessibilityInfo による読み上げ、セーフエリア対応までを動くコードで示します。
開発ツール2026-06-20
Rork の一覧が増えるほどスクロールで重複と欠落が出る——カーソルページネーションと再取得の状態設計
Rork が生成する素朴な offset ページネーションは、リストが更新されるたびに重複や欠落を起こします。カーソル方式の契約設計、取得状態を一つに束ねる usePaginatedList フック、失敗時の指数バックオフ再試行まで、本番運用で詰まらない一覧の作り方を実装中心に解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →