RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/開発ツール
開発ツール/2026-04-30中級

Rork で iCloud バックアップから復元するとアプリ内データが消える問題の直し方

Rork で作った iOS アプリで『機種変更後にユーザーデータが全部消えた』とレビューが付くのは、ほとんどが iCloud バックアップ設計の問題です。AsyncStorage・Documents・Keychain の挙動を整理し、復元後も状態を引き継ぐ設定方法を解説します。

Rork515iCloud3iOS108AsyncStorage10Keychain3

機種変更をしたユーザーから「アプリを開いたら全部最初からになっていた」とレビューが付くとき、原因のほとんどは iCloud バックアップ周りの設定漏れです。Rork で素直に作ると AsyncStorage や Keychain に保存したデータが復元時に持ち越されないことが多く、せっかくのリピーターを毎回失っていくことになります。

私自身、過去に3つのアプリで同じ問題に当たりました。デバッグでは何も起きず、TestFlight でも気付かず、本番のレビュー欄で初めて発覚するタイプのバグです。出荷前に必ず潰しておきたい挙動なので、ここでは「Rork アプリのデータがどこに保存されていて、復元時にどう振る舞うのか」を整理し、データを失わずに引き継ぐための設定方法を順を追って説明していきます。

なぜ Rork アプリは iCloud 復元後にデータが消えるのか

iOS のデータ保存先は、iCloud バックアップに含まれるかどうかが場所ごとに異なります。Rork(React Native + Expo)でよく使う保存先を整理すると、以下のように分かれます。

  • AsyncStorage: 内部的には Library/Application Support/RCTAsyncLocalStorage/ 以下のファイルです。iCloud バックアップに含まれます が、ライブラリ次第で「除外フラグ」が付いていることがあるので注意が必要です
  • Documents フォルダ: ユーザーが作成したファイルを置く場所です。デフォルトで iCloud バックアップに含まれます
  • Library/Caches: キャッシュ用です。iCloud バックアップに含まれません(システムが任意で削除する可能性もあります)
  • tmp/: 一時ファイルです。iCloud バックアップに含まれません
  • Keychain: 暗号化された資格情報置き場です。kSecAttrAccessible の設定次第で iCloud Keychain 経由で復元先に持ち越されます

データが消える典型パターンは、おおむね次の3つに集約されます。

  1. ユーザー作成データを Library/Caches/ に保存していた — 大きな画像や録音データを Caches に置くと、復元時にゼロから生成し直しになります
  2. AsyncStorage の保存先がいつの間にかバックアップ除外フラグ付きになっていた — 一部のライブラリが内部で自動的にフラグを付けます
  3. Keychain の kSecAttrAccessibleThisDeviceOnly 系になっていた — ログイントークンが復元時に持ち越されません

それぞれの直し方を順に見ていきます。

まずは保存先を可視化する

自分のアプリがどこに何を保存しているかを把握しないことには、話が始まりません。Rork のアプリで保存先を実機確認するためのデバッグスニペットを置いておきます。

import * as FileSystem from 'expo-file-system';
import AsyncStorage from '@react-native-async-storage/async-storage';
 
// アプリ起動直後に1回だけ呼んで確認用ログを出す
export async function debugStorageLocations() {
  console.log('documentDirectory:', FileSystem.documentDirectory);
  console.log('cacheDirectory:', FileSystem.cacheDirectory);
  console.log('bundleDirectory:', FileSystem.bundleDirectory);
 
  const keys = await AsyncStorage.getAllKeys();
  console.log('AsyncStorage keys count:', keys.length);
  console.log('AsyncStorage keys:', keys);
}

iOS 実機で実行すると、以下のような出力が得られるはずです。

documentDirectory: file:///var/mobile/Containers/Data/Application/<UUID>/Documents/
cacheDirectory:    file:///var/mobile/Containers/Data/Application/<UUID>/Library/Caches/
AsyncStorage keys count: 12

ここで Library/Caches/ 配下にユーザーが「自分が作った」と認識しているデータ(撮影した画像、ダウンロードした音声、書いたメモ等)を保存していたら、それは設計ミスです。Documents もしくは Library/Application Support/ に移動させてください。

判断基準としては、ユーザーが自分のものとして認識するデータは Documents、アプリ内部のマスターデータや設定は Application Support、再生成可能なキャッシュだけ Caches、と分けるのが基本になります。

ファイルごとに「バックアップに含めるか」を明示する

iOS にはファイル単位で「これはバックアップに含めない」と指定する仕組みがあります。これを忘れると、巨大な動画ファイルを Documents に置いただけで iCloud 容量を圧迫してしまい、ユーザーから「容量を食われている」とクレームが来ることがあります。

逆に、本当はユーザーデータなのに Excluded from backup フラグが付いていれば、それは復元時に消えてしまいます。Expo / React Native では以下のように制御できます。

import * as FileSystem from 'expo-file-system';
 
// バックアップから除外(再ダウンロード可能なキャッシュ画像など)
await FileSystem.setExcludeFromBackupAsync(
  `${FileSystem.documentDirectory}cached_thumbnails/photo_001.jpg`
);
 
// バックアップに含める(ユーザーが手書きしたメモなど)
// → デフォルトで含まれるため、明示的にフラグを外す API は基本不要
// 過去に setExcludeFromBackupAsync を呼んでしまった場合は、
//   別のファイルパスにコピーして作り直す

期待する動作としては、setExcludeFromBackupAsync を呼んだファイルは iCloud バックアップから除外され、復元先のデバイスには戻りません。呼ばなければデフォルトでバックアップ対象です。

私が一番ハマったのは、自前でサムネイル画像を Documents 配下に保存していた箇所です。元画像は外部から再取得可能だったので本来 Caches で十分だったのですが、Excluded from backup フラグも付け忘れていたために iCloud 容量を不必要に食っていました。「ユーザー本人が作ったか、外部から取得して再現できるか」で必ず仕分けてください。

Keychain の kSecAttrAccessible を機種変更に強い設定にする

ログイントークンを Keychain に保存している場合、kSecAttrAccessible の設定によって機種変更時の挙動が大きく変わります。expo-secure-store を使っているケースで例を示します。

import * as SecureStore from 'expo-secure-store';
 
// ❌ ダメな例: ThisDeviceOnly 系は機種変更時に持ち越されない
await SecureStore.setItemAsync('auth_token', token, {
  keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
});
 
// ✅ 良い例: 機種変更で iCloud Keychain 経由で復元される
await SecureStore.setItemAsync('auth_token', token, {
  keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK,
});

期待する挙動としては、AFTER_FIRST_UNLOCK で保存しておけば、機種変更後の新しい端末で初回ロック解除した直後から、同じ Apple ID で iCloud Keychain が同期されているユーザーは引き続きログイン状態を維持できます。

ただし、トークンの種類によっては「端末固有で、持ち越したくない」ケースもあります。たとえば指紋認証や FaceID で守っている決済用トークンは、安全性の観点から WHEN_PASSCODE_SET_THIS_DEVICE_ONLY のほうが望ましい場合もあります。「ユーザーに新しい端末で改めてログインしてもらうか、黙って引き継ぐか」をプロダクト側の方針として先に決めてから設定するのがおすすめです。 Keychain の詳細な使い分けは Rork × Keychain で機密情報を安全に保存する完全ガイド でも触れていますので、合わせて参照してみてください。

出荷前テスト — iCloud 復元シナリオを実機で再現する

設定を直したら、必ず本番に出す前に「実際に復元してみて」確認します。シミュレータでは正確に再現できないので、実機・Apple ID・少しの待ち時間が必要です。

  1. テスト端末A で iCloud バックアップを作成
    • 設定 → Apple ID → iCloud → iCloud バックアップ → 今すぐバックアップを作成
    • バックアップが「最後のバックアップ: 今」になるまで待つ
  2. テスト端末B(または同じ端末を初期化)に復元
    • 設定 → 一般 → 転送または iPhone をリセット → すべてのコンテンツと設定を消去
    • 初期セットアップで「iCloud バックアップから復元」を選び、1 で作ったバックアップを指定
  3. アプリを開いて、保存していたデータが残っているか目視確認
    • ログイン状態が維持されているか
    • ユーザーが作成したコンテンツが表示されているか
    • ダウンロード済みファイルが復活しているか、あるいは「再ダウンロードを促す UI」が正しく出ているか

ここで何かが消えていれば、保存先・バックアップフラグ・Keychain のいずれかに問題があります。日付や時刻まわりも復元後に違和感が出やすい箇所なので、合わせて Rork で日付が日本時間にならない・9時間ずれる時の直し方 も読んでおくと安心です。

Android 側の挙動も合わせて確認する

Android にも似た仕組みがあります。react-native-async-storage はアプリのサンドボックスに書き込まれ、Android 6 以降は Auto Backup の対象に入ります。ただし AndroidManifest.xmlandroid:allowBackup="false" を設定していると同じく「復元後に空」になります。Rork で素のまま使っているなら基本は安全ですが、過去に「セキュリティ強化」を謳う記事から Manifest 設定をコピーした覚えがあれば、出荷前に該当箇所を確認しておくのがおすすめです。

本当に大きなユーザー生成ファイル(写真・動画など)については、そもそも iCloud や Google Drive 経由のバックアップで運ぶのは現実的ではありません。メタデータだけ AsyncStorage や SQLite に置き、バイナリは Supabase Storage や自前のバックエンドへ預けて、復元時には参照だけ戻して必要に応じて再ダウンロードさせる設計が、長期的には一番素直です。

全体を振り返って — 復元時の挙動はリリース前に必ず確認する

機種変更や端末初期化からの復元は、ユーザーが「このアプリを使い続けるか、ここで辞めるか」を決定する瞬間です。ここで全部消えると、どれだけ作り込んだアプリでも一発で星1レビューが付いてしまいます。

今日できる具体的な一歩として、まずは自分のアプリで debugStorageLocations を呼んで、何がどこに保存されているのかを書き出してみてください。「Caches に置いていてはいけないもの」が1つでも見つかれば、それを直すだけで復元シナリオの大半は改善します。Keychain の kSecAttrAccessible も、開発初期の値のまま忘れがちな設定なので、合わせて見直してみることをおすすめします。

シェア

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

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

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

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

関連記事

開発ツール2026-07-10
クラッシュとして記録されない強制終了 — Rork アプリの JetsamEvent を読む
Crashlytics には何も出ていないのにレビューで「勝手に閉じる」と書かれる。その多くはメモリ超過による OS からの強制終了です。JetsamEvent レポートの読み方と、画像中心アプリのメモリ上限を実測から設計する手順をまとめます。
開発ツール2026-06-29
写真の「選択した項目だけ許可」に正しく向き合う設計
iOS の写真ライブラリ限定アクセス(選択した項目だけ許可)に Rork(Expo)アプリで正しく対応します。フルアクセス・限定・拒否の3状態の判定、選んだ写真だけを扱う前提の画面設計、追加選択を促す導線までを実装コードとともに整理します。
開発ツール2026-06-26
ユーザー自身の画像を「ファイル」アプリから取り込む — Rorkアプリのドキュメントピッカーとセキュリティスコープ付きURL
写真アプリにない画像を「ファイル」アプリやiCloud Driveから取り込むと、選んだはずのURLが直後に無効になります。expo-document-pickerとセキュリティスコープ付きURL、サンドボックスへの確実なコピーまでを、動くコードで整理します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →