「Rorkのプレビューでは完璧に動いていたのに、実機にインストールしたらすぐクラッシュする」——この問題、思ったより多くの方が経験されています。
Rorkが生成するのはExpo (React Native) ベースのアプリです。Rork上のプレビュー環境と実機の間には、ネイティブモジュールの有無・環境変数の扱い・OS固有の挙動など、いくつかの重要な違いがあります。原因を知っていれば、多くのケースで30分以内に解決できます。
クラッシュの種類を見分ける
対処法は原因によって変わるため、まず「いつクラッシュするか」を観察することが大切です。
起動直後にクラッシュする場合 → 環境変数の未設定・ネイティブモジュールの初期化エラーの可能性が高い
特定の操作をしたときにクラッシュする場合 → そのアクションに使われているコードまたはAPIの問題
iOSだけ(またはAndroidだけ)でクラッシュする場合 → プラットフォーム固有のパーミッションまたはネイティブAPIの問題
この観察だけで、確認すべき範囲が大幅に絞れます。
原因1: 環境変数の未設定
Rorkのプレビュー環境では、設定画面で入力した環境変数(APIキー、URLなど)が自動的に注入されます。しかし、実機ビルドでは別途設定が必要です。
クラッシュログを確認すると、以下のようなエラーが出ていることがあります。
TypeError: undefined is not an object (evaluating 'process.env.EXPO_PUBLIC_API_KEY.length')
修正方法:
Expo Goを使っている場合は、プロジェクトルートに .env.local を作成します。
# .env.local(ローカル実機テスト用)
EXPO_PUBLIC_API_KEY=your_actual_api_key_here
EXPO_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY=your_anon_key_hereEASビルド(App Store提出用)の場合は、eas.json に設定するか、EASダッシュボードの「Environment Variables」に登録します。
{
"build": {
"production": {
"env": {
"EXPO_PUBLIC_API_KEY": "your_production_key"
}
}
}
}また、コード側では undefined チェックを追加しておくと、デバッグが格段に楽になります。
const apiKey = process.env.EXPO_PUBLIC_API_KEY;
if (\!apiKey) {
console.error('API key is not configured. Check your .env file.');
// アプリをクラッシュさせるより、エラーUIを表示する方がデバッグしやすい
}原因2: ネイティブモジュールの互換性問題
Rorkが生成するコードには expo-camera、expo-location、expo-notifications などのネイティブモジュールが含まれることがあります。Expo GoやEAS Buildのバージョンと、これらのモジュールのバージョンが合っていないとクラッシュします。
確認手順:
# 現在のExpo SDKバージョンを確認
cat package.json | grep '"expo"'
# Expo Go の対応SDKバージョンを確認(公式ドキュメントで確認)
# https://docs.expo.dev/versions/latest/
# package.json のバージョンを固定する(Rorkが生成するコードは最新版を指定することが多い)
npx expo install --fix特に expo-notifications と expo-camera はバージョン差異によるクラッシュが多いモジュールです。
# よくある問題のあるパッケージを一括で互換バージョンに修正
npx expo install expo-notifications expo-camera expo-location expo-image-picker原因3: iOS/Android固有のパーミッション設定漏れ
カメラ・位置情報・通知などを使うアプリは、ネイティブの権限リクエスト設定が必要です。Rorkのコード生成では app.json の設定が不十分な場合があります。
// app.json に追加が必要な設定例
{
"expo": {
"ios": {
"infoPlist": {
"NSCameraUsageDescription": "写真を撮影するためにカメラへのアクセスが必要です",
"NSLocationWhenInUseUsageDescription": "現在地を取得するために位置情報へのアクセスが必要です",
"NSMicrophoneUsageDescription": "音声入力のためにマイクへのアクセスが必要です"
}
},
"android": {
"permissions": [
"CAMERA",
"ACCESS_FINE_LOCATION",
"RECORD_AUDIO"
]
},
"plugins": [
["expo-camera", { "cameraPermission": "写真撮影のためにカメラを使用します" }],
["expo-location", { "locationWhenInUsePermission": "現在地取得のため" }]
]
}
}この設定が漏れていると、iOSでは権限ダイアログが表示されずに即クラッシュ、Androidでは SecurityException が発生します。
原因4: Supabase・Firebase等の初期化タイミング
バックエンドサービスの初期化コードが非同期処理に対応していない場合、実機では起動時のタイミング差でクラッシュすることがあります。
// ❌ 非同期初期化が完了する前にデータ取得しようとするパターン
useEffect(() => {
fetchUserData(); // supabaseクライアントがまだ初期化されていない可能性
}, []);
// ✅ 初期化完了を待つパターン
const [isReady, setIsReady] = useState(false);
useEffect(() => {
const initialize = async () => {
// 必要な初期化処理を全て完了させる
await supabase.auth.getSession();
setIsReady(true);
};
initialize();
}, []);
// isReady が true になるまでローディング画面を表示
if (\!isReady) {
return <LoadingScreen />;
}クラッシュログの読み方
実機でクラッシュした場合、ログを確認するのが一番の近道です。
iOS の場合:
Xcodeを開いて Window → Devices and Simulators → 対象デバイス → View Device Logs でクラッシュレポートを確認できます。
Android の場合:
adb logcat *:E | grep "ReactNative\|expo"Expo Go の場合:
アプリをシェイクしてデバッグメニューを開き、Remote JS Debugging をオンにすると、Chromeのコンソールでエラーが確認できます。
まずやること
実機クラッシュに遭遇したら、以下の順番で確認してみてください。
- 環境変数が実機環境にも設定されているか確認する
npx expo install --fixでモジュールバージョンを修正するapp.jsonに使用している機能のパーミッション設定があるか確認する- クラッシュログを確認して、エラーメッセージを特定する
Rorkが生成するコードはプレビュー環境で動くことを前提に作られているため、本番ビルドでは上記の追加設定が必要になることが多いです。慣れれば設定パターンは決まってくるので、最初の数アプリで一通り経験しておくと、その後の開発がずっとスムーズになります。