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-24中級

Rork アプリの WebView が真っ白になる・ページが表示されないときに確認する 6 つの原因

Rork で WebView を組み込んだら画面が真っ白になる、ページが読み込まれない、JavaScript が動かない ─ そんな症状を切り分けて確実に直すためのチェックリストです。

Rork515WebView2トラブルシューティング77React Native209iOS108Android43

Rork で作ったアプリに「社内ツールの画面を WebView でそのまま埋め込みたい」「外部サービスのログインを一時的に WebView で挟みたい」といった要件を入れた途端、シミュレーターでは動いていたのに実機で真っ白、ということがよくあります。私自身も、プレビュー動画用に急いで組み込んだ WebView が Android の実機で一切描画されず、リリース直前に半日潰した苦い記憶があります。

WebView の「真っ白」はエラーが前面に出ないぶん原因の切り分けが難しいのですが、実際に起きる詰まり方には明確なパターンがあります。ここでは Rork で react-native-webview を使う前提で、現場でよく遭遇する 6 つの典型パターンを上から順に潰していく流れで整理します。

まずは「どこで止まっているか」を切り分ける

真っ白に見えるとき、実は 3 つの異なる状態が混ざっています。

  • ネイティブ側の WebView コンポーネント自体が画面に乗っていない
  • WebView は乗っているが URL がロードに失敗している
  • URL は読み込めているが HTML 側が空、または JavaScript で描画待ちのまま止まっている

この切り分けを最初にやるかどうかで、その後の作業時間が 1 時間変わります。いちばん手堅いのは、onLoadStart / onLoad / onError をすべて仕込んで、どのイベントが発火しているかをログに出してしまうことです。

// components/DebugWebView.tsx
import { WebView, type WebViewNavigation } from "react-native-webview";
import { View, Text, StyleSheet } from "react-native";
import { useState } from "react";
 
type Props = { uri: string };
 
export default function DebugWebView({ uri }: Props) {
  const [status, setStatus] = useState<"idle" | "loading" | "loaded" | "error">("idle");
  const [lastUrl, setLastUrl] = useState<string>("");
  const [errorText, setErrorText] = useState<string>("");
 
  return (
    <View style={styles.container}>
      {/* ステータスバー:ユーザーには見せず、開発中のみ描画する */}
      <Text style={styles.status}>
        status: {status} / url: {lastUrl}
        {errorText ? ` / error: ${errorText}` : ""}
      </Text>
      <WebView
        source={{ uri }}
        style={styles.webview}
        onLoadStart={(e) => {
          setStatus("loading");
          setLastUrl(e.nativeEvent.url);
        }}
        onLoad={() => setStatus("loaded")}
        onError={(e) => {
          setStatus("error");
          setErrorText(e.nativeEvent.description ?? "unknown");
        }}
        onNavigationStateChange={(nav: WebViewNavigation) => {
          // 遷移が起きた瞬間の URL を確認できる
          setLastUrl(nav.url);
        }}
      />
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: { flex: 1 },
  status: { padding: 8, backgroundColor: "#111", color: "#0f0", fontSize: 12 },
  webview: { flex: 1 },
});

このデバッグビューを 1 分だけ挟むと、「loading のまま止まっている」のか「error になっている」のか、「loaded なのに真っ白」なのかが一目で分かります。以降の原因特定はこの結果をもとに進めます。

原因 1:iOS の App Transport Security(ATS)で HTTPS が必須

iOS 実機で真っ白になり、シミュレーターでも onError が発火するのに Android では動く ─ これはほぼ確実に ATS による HTTP ブロックです。http:// で始まる URL は iOS 側で黙ってブロックされ、何のダイアログも出ません。

Rork 経由でエクスポートした Expo プロジェクトの場合、app.jsonios.infoPlist に例外を書くか、先方の URL を HTTPS に切り替えてもらうのがまっとうな解決策です。社内サーバーなど一時的に HTTP を許容したい場合は、次のように最小限のドメイン単位で許可するとリジェクトリスクを抑えられます。

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSAppTransportSecurity": {
          "NSAllowsArbitraryLoads": false,
          "NSExceptionDomains": {
            "staging.example.internal": {
              "NSTemporaryExceptionAllowsInsecureHTTPLoads": true,
              "NSTemporaryExceptionMinimumTLSVersion": "TLSv1.0",
              "NSIncludesSubdomains": true
            }
          }
        }
      }
    }
  }
}

NSAllowsArbitraryLoadstrue にする解説記事も見かけますが、App Store 審査で理由を問われることがあるので、対象ドメインだけを NSExceptionDomains で開ける形を強くおすすめします。HTTPS 化・証明書まわりで詰まったときは、API 通信側と同じ原因であることも多いので、ネットワークリクエストのデバッグ手順 もあわせて確認すると早いです。

原因 2:Android の cleartextTraffic と Mixed Content

Android 9(API 28)以降は HTTP 通信がデフォルトで無効になっています。iOS と同じように、HTTPS が使えるならそれが最良ですが、社内 URL や開発用の IP アドレス(http://192.168.x.x)を開きたい場面は現実に残ります。

Expo 管理下のプロジェクトでは、app.jsonandroid.usesCleartextTraffictrue にすることでまず扉を開けます。そのうえで、react-native-webview 側では mixedContentMode を明示しておかないと、HTTPS ページ内の HTTP リソース(画像や iframe)が読み込まれず、結果として中身がスカスカになります。

<WebView
  source={{ uri: "http://192.168.10.5:3000" }}
  mixedContentMode="compatibility" // "always" / "compatibility" / "never"
  javaScriptEnabled
  domStorageEnabled
  // 本番で使う場合は該当 URL のみに限定する
/>

mixedContentMode="always" を本番ビルドにそのまま残すとセキュリティ上よくないので、開発ビルドと本番ビルドで分けておくのが無難です。EAS のプロファイル別に環境変数で切り替える運用が、Rork で作ったアプリでもいちばん扱いやすいと感じます。

原因 3:リダイレクトとクッキーでログイン画面が無限ループ

外部サービスの OAuth や SAML を WebView で踏ませたとき、「ログインボタンを押した直後に最初の画面に戻る」「ずっとローディングのまま」になることがあります。これはクッキーが WebView 内で保持されていない、またはリダイレクト先が about:blank に化けているケースがほとんどです。

最低限押さえておきたいのは以下の 3 点です。

  • sharedCookiesEnabledtrue にして、iOS のネイティブクッキーストアと WebView を共有する
  • thirdPartyCookiesEnabled を Android で true にしておく(iOS 14 以降の ITP 相当の挙動に注意)
  • onShouldStartLoadWithRequest でカスタムスキーム(yourapp://callback)をフックしてネイティブ側へ戻す
<WebView
  source={{ uri: loginStartUrl }}
  sharedCookiesEnabled
  thirdPartyCookiesEnabled
  incognito={false}
  onShouldStartLoadWithRequest={(req) => {
    if (req.url.startsWith("yourapp://callback")) {
      // カスタムスキームを検出したらネイティブ側の認証完了処理へ渡す
      handleAuthCallback(req.url);
      return false; // WebView には遷移させない
    }
    return true;
  }}
/>

onShouldStartLoadWithRequest を仕込まずにカスタムスキームを渡すと、WebView が「開けない URL」と判断して白画面になることがあります。OAuth 絡みで真っ白になるときは、まずここを疑うのが近道です。

原因 4:JavaScript は動いているのに描画待ちで止まっている

onLoad まで発火したのに真っ白」というパターンは、SPA 側が window.requestIdleCallback やフォントロードを待ってから描画している、もしくは WebView の viewport メタタグがなくて縦横比がおかしくなっているだけ、というのが定番です。

確認は injectedJavaScriptBeforeContentLoadeddocument.readyStatedocument.body.innerHTML.length を通知させるのが速いです。

<WebView
  source={{ uri }}
  onMessage={(e) => console.log("[webview]", e.nativeEvent.data)}
  injectedJavaScriptBeforeContentLoaded={`
    window.addEventListener('DOMContentLoaded', () => {
      window.ReactNativeWebView.postMessage(JSON.stringify({
        ready: document.readyState,
        bodyLength: document.body ? document.body.innerHTML.length : 0,
        title: document.title,
      }));
    });
    true; // React Native 側で評価結果を undefined にするおまじない
  `}
/>

bodyLength がそれなりの数字なのに画面が真っ白なら、CSS の height: 100vh が iOS の Safari 同等で計算されている、あるいはダークテーマで背景が黒のまま文字も黒になっている、という見落としが疑われます。

なお表示は出るのに画像だけ出ない、という症状なら原因はまた別で、画像・メディアの読み込みエラー対処 に網羅的にまとめてあります。

原因 5:プロセス外 WebView のクラッシュ(Android 限定)

Android では 2023 年以降、WebView がアプリ本体と別プロセスで動くようになり、メモリ不足や System WebView の更新中に勝手に「真っ白+無反応」状態になることがあります。onRenderProcessGone が実装されていないと、その瞬間アプリ側は何も知りません。

対策はハンドラを書いてリロードする、これだけです。

<WebView
  source={{ uri }}
  onRenderProcessGone={(e) => {
    console.warn("[webview] render process gone", e.nativeEvent);
    // 自動リロード、またはエラー画面に切り替え
    webRef.current?.reload();
  }}
/>

体感としては低価格帯の Android 端末で再現しやすく、レビュー欄に「急に画面が動かなくなる」と書かれる症状の多くがこれです。気づかずに放置すると星が削られるので、出荷前に一度仕込んでおく価値があります。長時間使うアプリで頻発する場合は、より広いクラッシュ対策を扱った アプリが実機でクラッシュするときの切り分け も参考にしてください。

原因 6:Rork プレビュー特有の「Companion では見えるのに本番で出ない」

Rork で開発中、Companion 経由のプレビューでは完璧に動いていたのに、TestFlight ビルドだと WebView だけ真っ白 ─ これは Companion が一部のネイティブ設定を甘めに上書きしているためです。

チェックすべきは以下の順序です。

  • app.jsonplugins 配列に react-native-webview が追加されているか
  • eas.json の開発プロファイルと本番プロファイルで usesCleartextTraffic / infoPlist の値がずれていないか
  • 本番ビルドは Release 用の ATS ルールが適用される。Debug 用に緩めていた例外が Release に入っていない可能性がある

eas build --profile preview --platform ios でプレビューに近いビルドを作り、そのビルドで再現するかを確認すると、Companion 固有か本番固有かを切り分けられます。

次に何をするか

WebView の「真っ白」はエラーが見えにくいだけで、切り分けるイベントを 1 本仕込めば原因は必ず特定できます。いま手元のアプリで真っ白になっている方は、まず上の DebugWebView コンポーネントをそのまま貼り付け、statuserrorText がどう遷移するかを 1 回観察してみてください。そこから原因 1 〜 6 のどの節に飛べばよいかが決まります。

WebView を使い込むなら、React Native と Expo のネットワーク周りの知識が土台になります。

シェア

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

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

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

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

関連記事

開発ツール2026-05-02
Rork で StatusBar の色・スタイルが反映されない時の対処法
Rork で生成したアプリの StatusBar が iOS と Android で意図通りに表示されない問題を、実装パターン別に切り分けて解決する手順をまとめました。
開発ツール2026-04-18
RorkアプリがiOSで動くのにAndroidだけおかしい:プラットフォーム差異を修正する実践ガイド
RorkアプリがiOSで動くのにAndroidで崩れる問題を解決します。シャドウ・フォント・権限・キーボード制御など主要なプラットフォーム差異を実例コードで解説します。
開発ツール2026-05-19
Rork で AsyncStorage に大容量データを保存すると Android で CursorWindow エラーが出る原因と対処
Rork(React Native)で AsyncStorage に大きな JSON や画像メタデータを保存すると Android で発生する Row too big to fit into CursorWindow エラーの原因と、MMKV・SQLite・分割保存・圧縮など複数の現実的な対処をまとめています。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →