◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●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 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/開発ツール
⬡ 開発ツール/2026-04-08中級

Rork Max アプリでExpo Goプレビューと実機ビルドの動作が違う:よくある原因と解決法

Rork MaxアプリをExpo Goでプレビューすると動くのに、実機ビルドや本番環境で動かないというトラブルの原因を解説。フォント・ネイティブモジュール・環境変数・APIエンドポイントの不一致を解決します。

Rork Max236Expo Go3ビルドエラー9トラブルシューティング85React Native239実機テスト15EAS Build22

Rork Max アプリでExpo Goプレビューと実機ビルドの動作が違う:よくある原因と解決法

Rork Maxでアプリを開発していると、Expo Goでのプレビューでは完璧に動いているのに、本番ビルドや実機でテストすると急に動かなくなる……という体験をすることがあります。

「プレビューで確認したのにリリース後にクラッシュした」「Expo GoではUIが正しく見えるのにビルドすると崩れる」——このような問題は、Expo GoとネイティブビルドのRuntimeの違いに起因していることがほとんどです。

Expo Goとネイティブビルドの根本的な違い

まず前提として、Expo GoとEAS Build(またはexpo buildによるネイティブビルド)の違いを理解する点が肝心です。

Expo Goは事前にコンパイルされたExpoのシェルアプリで、JavaScript(またはTypeScript)のみを実行します。ネイティブモジュールはExpo SDKが提供するものだけが使えます。

EAS Build / ネイティブビルドは実際のApp Store配布向けバイナリを生成します。app.json/app.config.jsの全設定が反映され、カスタムのネイティブコードを含む本番アプリです。

この違いが、多くの「プレビューは動くのにビルドが動かない」問題の根本原因です。

問題パターン①:カスタムフォントが実機で表示されない

症状: Expo Goではカスタムフォントが適用されているのに、ビルドしたアプリではデフォルトフォントになります。

// ❌ フォントの読み込みタイミングが不適切
import * as Font from 'expo-font';
 
export default function App() {
  // フォント読み込みを待たずにレンダリングされる
  Font.loadAsync({
    'NotoSansJP': require('./assets/fonts/NotoSansJP-Regular.ttf'),
  });
  
  return <Text style={{ fontFamily: 'NotoSansJP' }}>テキスト</Text>;
}
 
// ✅ useFontsフックで読み込み完了を待つ
import { useFonts } from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import { useEffect } from 'react';
 
SplashScreen.preventAutoHideAsync();
 
export default function App() {
  const [fontsLoaded, fontError] = useFonts({
    'NotoSansJP': require('./assets/fonts/NotoSansJP-Regular.ttf'),
    'NotoSansJP-Bold': require('./assets/fonts/NotoSansJP-Bold.ttf'),
  });
  
  useEffect(() => {
    if (fontsLoaded || fontError) {
      SplashScreen.hideAsync();
    }
  }, [fontsLoaded, fontError]);
  
  if (!fontsLoaded && !fontError) {
    return null; // フォント読み込み中はnullを返す
  }
  
  return <Text style={{ fontFamily: 'NotoSansJP' }}>テキスト</Text>;
}

また、app.jsonでフォントファイルをassets配列に含める必要があります。

{
  "expo": {
    "assets": [
      "./assets/fonts/NotoSansJP-Regular.ttf",
      "./assets/fonts/NotoSansJP-Bold.ttf"
    ]
  }
}

問題パターン②:ネイティブモジュールがビルド後に動かない

症状: Expo Goでは使えていた機能が、本番ビルドでのみクラッシュします。

Expo Goには組み込まれていない(またはバージョンが異なる)ネイティブモジュールを使うと、このような問題が起きます。

# まず問題のモジュールを特定する
# Expo Goと互換性がないモジュールを使っているか確認
npx expo-doctor
 
# よく問題になるモジュールの例
# - react-native-camera (Expo Go非対応 → expo-camera を使う)
# - react-native-maps (バージョン依存 → react-native-maps@1.7以降を推奨)
# - @stripe/stripe-react-native (Expo Goで制限あり → dev-clientを使う)

解決策A: Expo互換の代替モジュールに切り替える

// ❌ Expo Goで完全動作しないことがある
import { Camera } from 'react-native-camera';
 
// ✅ Expo管理のモジュールを使う
import { CameraView, useCameraPermissions } from 'expo-camera';

解決策B: Development Build(Custom Dev Client)を使う

Expo Goを使わず、カスタムのDevelopmentビルドを使うことで、本番ビルドと同じ環境でテストできます。

# EASでdevelopmentビルドを作成
eas build --profile development --platform ios
 
# または開発サーバーをdevClientモードで起動
npx expo start --dev-client

問題パターン③:環境変数がビルド後に反映されない

症状: APIエンドポイントやAPIキーが本番ビルドで参照できません。process.env.EXPO_PUBLIC_API_URLがundefinedになります。

# .env.local (Expo Goでは読み込まれるが、ビルドには反映されない場合がある)
EXPO_PUBLIC_API_URL=https://api.example.com
// ❌ 本番ビルドで環境変数が取れないケース
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
// → undefinedになることがある
 
// ✅ app.config.jsを使って確実に埋め込む
// app.config.js
export default {
  expo: {
    name: "My App",
    // 環境変数をビルド時に埋め込む
    extra: {
      apiUrl: process.env.EXPO_PUBLIC_API_URL ?? "https://api.example.com",
      apiKey: process.env.EXPO_PUBLIC_API_KEY,
    }
  }
};
// アプリ内での参照
import Constants from 'expo-constants';
 
const apiUrl = Constants.expoConfig?.extra?.apiUrl;

EAS Buildでの環境変数管理(本番環境):

// eas.json
{
  "build": {
    "production": {
      "env": {
        "EXPO_PUBLIC_API_URL": "https://api.production.example.com"
      }
    },
    "preview": {
      "env": {
        "EXPO_PUBLIC_API_URL": "https://api.staging.example.com"
      }
    }
  }
}

EAS Secretsで機密情報を安全に管理することもできます。

eas secret:create --scope project --name STRIPE_SECRET_KEY --value "sk_live_xxxx"

問題パターン④:画像やアセットがビルド後に表示されない

症状: Expo Goでは画像が表示されるのに、ビルドしたアプリで表示されない、または壊れた画像アイコンになります。

// ❌ 動的なrequireはビルドに含まれないことがある
const imagePath = `./assets/images/${imageName}.png`;
const image = require(imagePath); // ← これはビルドで機能しない
 
// ✅ 静的なrequireを使う(ビルド時にバンドルされる)
const images = {
  cat: require('./assets/images/cat.png'),
  dog: require('./assets/images/dog.png'),
  bird: require('./assets/images/bird.png'),
};
 
// 動的に選ぶ場合はオブジェクトのマッピングを使う
const image = images[imageName];

app.jsonのassets配列にも必要なアセットを追加してください。

{
  "expo": {
    "assets": ["./assets/images/", "./assets/icons/"],
    "icon": "./assets/icon.png",
    "splash": {
      "image": "./assets/splash.png"
    }
  }
}

デバッグの効率化:Expo Goに依存しないテスト環境の構築

長期的な解決策として、Development Buildを常用することを強くおすすめします。

# EAS CLIのインストール
npm install -g eas-cli
 
# プロジェクトの初期化
eas build:configure
 
# iOS/Android向けdevelopmentビルドの作成
eas build --profile development --platform all
 
# ビルドをインストールして起動
npx expo start --dev-client

Development Buildを使うことで、本番ビルドとほぼ同じ環境でHot Reloadを使いながら開発できます。Expo Goで動かなくなるケースを事前に発見できるため、リリース前のトラブルを大幅に減らせます。

全体を振り返って

Expo Goと実機ビルドの動作不一致は、主に以下の4パターンに分類できます。

  • カスタムフォント → useFontsフックとapp.jsonのassets配列を正しく設定する
  • ネイティブモジュール → Expo互換モジュールへの移行またはDevelopment Buildの使用
  • 環境変数 → app.config.jsのextra経由またはEAS環境変数を使う
  • 動的アセット → 静的なrequireとオブジェクトマッピングに書き換える

プレビューと本番の差異を根本から解消するには、Development Buildを本開発環境として採用するのが最も効果的です。これにより、リリース後に初めてバグに気づくという状況を防げます。

本記事の内容

シェア

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

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

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

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

関連記事

⬡ 開発ツール2026-09-21
exit code 0 で止まるビルド — ログを黙らせていた設定と、空ファイルを通した存在チェック
eas build --local が exit code 0 but produced no further output で止まる件と、0 バイトのスタブが埋め込まれず dyld で落ちる件。どちらも原因は出力を減らす設定でした。自分のスクリプトを棚卸しする手順まで書き残します。
⬡ 開発ツール2026-06-29
Rork × Vision Camera v4:QR・OCR・ML推論まで本番投入できるカメラ機能を仕上げる実装ノート
Rork のアプリで React Native Vision Camera v4 を本番品質に仕上げる実装手順を、フレームプロセッサ・ML 推論・QR/OCR から、発熱対策・実機テストマトリクス・ストア審査・段階リリースまで通してお伝えします。
⬡ 開発ツール2026-05-18
Rork で Linking.canOpenURL が iOS だけ false を返す ─ LSApplicationQueriesSchemes 設定漏れの直し方
TikTok や X、LINE 公式アカウントへ飛ばす実装が iOS の本番ビルドだけで動かない症状を、LSApplicationQueriesSchemes の追加と EAS Build の再生成手順で確実に解消します。