開発

react-native-webviewとは?postMessage連携と版が三つに割れた導入判断【2026年8月時点】

react-native-webviewは、React Nativeのアプリ内にWebページを埋め込むためのコミュニティ製ライブラリです。React Native本体が標準で持っていたWebViewコンポーネントは本体から切り離されており、現在この用途を担うのはこのパッケージひとつになっています。2026年8月19日時点で週間ダウンロードは約377万、ライセンスはMITです。この記事では、描画の実体がiOSとAndroidでどう分かれるか、postMessageで双方向の連携をどう組むか、認証情報の引き継ぎがどこで壊れるか、そしてストア審査を踏まえて受託案件で採用してよいかを実装目線で整理します。React Native自体の構造はReact Nativeとは?仕組みとNew Architectureの構造・採用判断を実装目線で解説にまとめてあります。

まとめ:既定で入るのは14系、16系はnextに置かれたまま

先に結論を示します。実装そのものは難しくありません。WebViewを置いてsourceにURLを渡せば表示は出ますし、Webとネイティブの往復もpostMessageonMessageの組み合わせだけで成立します。

つまずくのは版の選択です。2026年8月19日時点のnpm上のdist-tagsは、latestが14.0.1(2026年6月20日公開)、nextが16.0.0(2026年7月11日公開)に分かれたままになっています。npm install react-native-webviewと打つと入るのは14系で、New Architecture専用になった16系は明示的に@nextを指定しない限り入りません。メンテナ自身も15.0.0のリリースノートで、変更量が多いので当面14をlatestに置くと書いています。

Expoを使う場合はさらに古い版で固定されます。Expo SDK 57のバンドル定義が指しているのは13.16.1(2026年2月27日公開)で、npmのlatestである14.0.1よりも1メジャー手前です。個別に上げる前に、この定義を先に確認する進め方が安全でしょう。

入手経路 入る版 アーキテクチャ
npm 既定(latest) 14.0.1 旧・新の両対応
npm @next 指定 16.0.0 New Arch専用
Expo SDK 57 の定義 13.16.1 旧・新の両対応

react-native-webviewが埋める役割と描画実体の違い

WebViewの中身は、React Nativeが用意した独自のレンダラではありません。OS側が持つブラウザエンジンをそのまま画面に貼り付ける部品です。この前提を押さえておくと、後述する挙動差の理由がつかみやすくなります。

RN本体からWebViewが外れて別パッケージへ移された経緯

React Nativeは以前、WebViewをコア側のコンポーネントとして提供していました。その後、本体の肥大を避けるためコアからの切り離しが進み、WebViewはコミュニティ管理の独立パッケージへ移されています。公式ドキュメントの旧版アーカイブにWebViewの項が残っているのはこの経緯によるもので、現行のドキュメントを見ても本体側には見つかりません。

結果として、この領域はreact-native-webviewの1リポジトリに集約されました。週間377万ダウンロードという数字は、React Native案件のかなりの割合が何らかの形でWeb埋め込みを抱えていることの裏返しでもあります。

iOSのWKWebViewとAndroidのSystem WebViewという差

描画の実体は、iOSではWKWebView、AndroidではSystem WebViewです。パッケージが提供するのはこの2つを共通のpropsで包む層であり、下の挙動まで揃えるわけではありません。公式のReference.mdを見ると、propsの表に対応プラットフォームの列が付いていて、片方のOSでしか効かないものが多数あります。

たとえばCookieの共有設定はiOSとmacOS向けのsharedCookiesEnabled、サードパーティCookieの可否はAndroid向けのthirdPartyCookiesEnabledと、名前も対象も分かれています。allowFileAccessのようにAndroid専用のものもあります。実装の際は、propsを1つ足すたびに対象プラットフォームを確認する手間が発生すると考えておいてください。

端末側のWebView更新に挙動が左右されるAndroidの事情

Androidで注意したいのは、System WebViewがアプリではなく端末側の構成要素だという点です。同じアプリでも、端末に入っているWebViewの版が違えばCSSの描画やJavaScriptの対応範囲が変わります。iOS側もWKWebViewはOSに紐づきますが、更新の足並みはAndroidほど散りません。

14.0.0ではAndroidの下限がAPI 24(Android 7.0)へ引き上げられ、古い版向けの互換コードとネイティブのファイルアップロード経路が削除されました。それ以前の端末を要件に含む案件では、この版から先へ進めない判断が必要になります。

latest・next・Expo固定版で三つに割れた版の選び方

ここが実務でいちばん判断を要する部分です。同じパッケージでありながら、入手経路によって入る版が3つに割れています。

安定版が14.0.1で止まり16.0.0がnextに置かれた状態

14.0.1は2026年6月20日、16.0.0は2026年7月11日の公開です。約5週間が経ってもlatestタグは14.0.1のまま動いていません。この状態は放置ではなく意図的なもので、メンテナは15.0.0のリリースノートに、Windows以外では破壊的変更ではないはずだが変更量が多いため当面14をlatestに置く、導入は@nextで、と明記しています。

つまり、記事や社内資料で最新版は16系だと書いてあっても、素直にインストールした環境に入るのは14.0.1です。バグ報告や再現手順を扱うときは、まずnpm ls react-native-webviewで実際に入っている版を確かめてから話を進めた方が食い違いが減ります。

16系で旧アーキが外れReact Native 0.76以上が必須になる

16.0.0の破壊的変更は、旧アーキテクチャ(Paper)のサポート削除です。READMEには、New Architecture(Fabric)のみをサポートする、React Native 0.76以上(New Architecture有効)とiOS 15.1以上を要求する、macOSはreact-native-macos 0.76以上、と書かれています。14.0.1のREADMEが旧と新の両方をサポートすると書いていたのとは対照的です。

React Native本体のlatestは0.87.0なので、新規案件であれば0.76以上という条件はまず問題になりません。引っかかるのは、旧アーキテクチャのまま動いている保守案件の方です。その場合は14系に留めるか、本体のアーキテクチャ移行を先に済ませるかの二択になります。

Expo SDK 57が13.16.1を固定している事情と上げ方の順序

Expo管理下のプロジェクトでは、SDKごとのバンドル定義が各ライブラリの版を指定します。SDK 57の定義はreact-native 0.86.2に対してreact-native-webview 13.16.1で、npmのlatestより1メジャー古い組み合わせです。npx expo installを使えばこの定義に沿った版が入りますが、npm installで直接入れると14系が入り、定義と食い違います。

先に上げたくなる場面はありますが、Expoの版管理はSDK単位で整合を取る仕組みです。Expo Go・開発ビルド・EAS Buildの関係はExpo(React Native)とは?Expo Go・開発ビルド・EASの役割と採用判断で整理しています。個別のライブラリだけ先行して上げる場合は、開発ビルドを作り直したうえで実機確認まで通す前提で見積もっておくと安全です。

postMessageで双方向の連携を組み立てる手順と初期化順

WebView埋め込みが単なる表示で終わらないのは、埋め込んだページとネイティブ側が値をやり取りできるからです。react-native-webviewでは、この往復が文字列1本のチャネルに統一されています。

Web側からwindow.ReactNativeWebViewへ送る書き方

埋め込まれたページ側からは、window.ReactNativeWebView.postMessageを呼びます。引数は1つだけで、しかも文字列でなければなりません。オブジェクトを渡したい場合はJSONへ直列化して送り、受け側で戻す形になります。

// 埋め込んだWebページ側
window.ReactNativeWebView.postMessage(
  JSON.stringify({ type: 'checkout_done', orderId: 'A-1024' })
);

ネイティブ側はonMessageで受け取り、値はevent.nativeEvent.dataに文字列として入る仕様です。ここで型の検証を挟まずにそのまま処理へ流すと、埋め込み先のページが差し替わったときに壊れます。受信直後にスキーマを検証する層を1枚置く作りにしておくと、後の改修が軽くなります。

ネイティブ側からinjectJavaScriptで送り返す2つの経路

逆向きの経路は2つあります。1つはrefから呼ぶinjectJavaScript(str)メソッドで、任意のJavaScript文字列をその場で実行させます。もう1つはpostMessage(str)メソッドで、こちらはページ側のmessageイベントで受ける形です。

読み込み時点で一度だけ値を渡したい場合は、propsのinjectedJavaScriptが選択肢です。これはドキュメントの読み込み完了後、他のサブリソースの読み込み前に実行されます。より早い段階に差し込むinjectedJavaScriptBeforeContentLoadedもありますが、公式ドキュメントはAndroidでの動作を100%信頼できるわけではないと明記しており、代わりにinjectedJavaScriptObjectを勧めています。

// 初期値の受け渡しはオブジェクトで渡す方が安定する
<WebView
  source={{ uri: 'https://example.com/mypage' }}
  injectedJavaScriptObject={{ locale: 'ja-JP', theme: 'dark' }}
  onMessage={handleMessage}
/>

ページ側はwindow.ReactNativeWebView.injectedObjectJson()でこの値をJSON文字列として取り出します。ただしこの値はページの全フレームから見えるため、トークンのような秘匿値をここへ置くのは避けてください。

onMessageを外すと注入スクリプトごと動かなくなる依存

見落としやすい依存関係が1つあります。onMessageを設定していないと、window.ReactNativeWebView.postMessageがページへ注入されないだけでなく、injectedJavaScriptに書いたコードも実行されません。公式ドキュメントは、何もしない関数でよいので必ずonMessageを設定するようにと念を押しています。

注入したスクリプトが動かないという症状に当たったら、まずこの1点を疑うのが早道です。あわせて、注入する文字列はtrueのような有効な値へ評価される必要があり、例外を投げてもいけません。即時関数で包んで末尾にtrue;を置く書き方が定石になっているのはこのためです。

フレームの扱いにも既定があります。injectedJavaScriptForMainFrameOnlyは既定でtrue、つまりメインフレームだけに注入されます。iframe内へも届かせたい場合はfalseにできますが、対応はiOSとmacOSのみで、Androidはtrueしか受け付けません。

認証情報とCookieをWebViewへ引き継ぐ実装と壊れる条件

業務システムでWebViewを使う場面の多くは、ログイン済みの画面を出すことが目的です。ここが最も設計を要する部分になります。

iOSのsharedCookiesEnabledとAndroid側の設定の差

iOSでは、既定のままだとWKWebViewはアプリ側のCookieストアを共有しません。sharedCookiesEnabledをtrueにして初めて、NSHTTPCookieStorageのCookieが各リクエストへ乗ります。React Native側からCookieを書き込む手段は、公式ガイドが@react-native-cookies/cookiesを案内しています。

Androidは事情が逆で、thirdPartyCookiesEnabledが既定でtrueです。認証基盤を別ドメインに置いている構成では、この既定に依存したまま動いてしまい、iOSだけログインが通らないという形で差が表面化します。両OSで同じ検証手順を踏むまで、片側だけの成功を根拠にしないでください。

source.headersのCookieが初回リクエストで終わる制約

もう1つの引き継ぎ手段がsourceのheadersです。ここにCookieヘッダを載せればログイン状態を持ち込めますが、公式ガイドはこれらのCookieが初回リクエストにしか送られないと明記しています。ページ内でリンクを踏んで遷移した先には引き継がれません。

そのため、埋め込み先が複数ページにまたがる導線なら、headers頼みの設計は破綻します。遷移のたびにヘッダを付け直す仕組みを組むか、Cookieストア側へ書き込む方式へ寄せるかを最初に決めておいてください。この判断を後回しにすると、実装が進んだ段階で通信層の作り直しが発生します。

遷移先を絞るoriginWhitelistと審査で効く遷移制御

埋め込んだページからどこへでも遷移できる状態は、認証情報の観点でも審査の観点でも避けたいところです。originWhitelistは既定でhttp://*https://*を許しており、実質すべてのWebページが対象になっています。自社ドメインだけに絞る指定を最初に入れておくと、想定外の遷移がOS側のブラウザへ流れる挙動に変わります。

より細かい制御はonShouldStartLoadWithRequestです。trueを返せば読み込みを続け、falseで止まります。ただしAndroidでは初回ロード時に呼ばれないため、初期URLの検証はここに任せられません。target属性による新規ウィンドウやwindow.openはonOpenWindow側で受けるので、両方を塞いでおく必要があります。iOSではlimitsNavigationsToAppBoundDomainsを使い、Info.plistに登録した最大10ドメインへ遷移先を限定する手もあります。

ストア審査で落ちる構成と受託開発案件で採用してよい実務上の線引き

技術的に動くことと、ストアに並べられることは別です。WebView中心のアプリは、両ストアが名指しで基準を設けている領域にあたります。

Appleの4.2が排除する作り直しただけのWebサイト型アプリ

App Store Review Guidelinesの4.2 Minimum Functionalityは、アプリはWebサイトを詰め直しただけのものを超える機能・コンテンツ・UIを備えるべきだとし、アプリらしくないものはApp Storeにふさわしくないと述べています。続く4.2.2では、カタログを除き、マーケティング資料・広告・Webクリッピング・コンテンツ集約・リンク集を主目的とするアプリを認めないとしています。

この基準に照らすと、既存サイトを1画面のWebViewで包んだだけの構成は通りにくいと考えるのが妥当です。プッシュ通知、生体認証、オフライン時の表示、カメラや位置情報の連携など、ネイティブ側でしか成立しない機能をどれだけ載せられるかが分岐になります。

Google Playが求めるサイト所有者による正式な許諾という条件

Google Playのスパムポリシーには「Webviews and Affiliate Spam」という項があり、アフィリエイト目的の誘導、あるいはサイトの所有者や管理者の許可なくそのサイトのWebViewを提供することを主目的とするアプリを認めないと書かれています。

受託開発では、埋め込み対象が発注者自身のサイトであることがほとんどなので、許諾の点は書面で押さえておけば足ります。むしろ実務で問題になるのは、提携先や外部サービスの画面を埋め込む案件の方です。契約段階で埋め込みの可否を確認しておかないと、実装後に構成の変更を迫られます。

採用してよい条件と見送る判断になる受託開発プロジェクトの実務上の特徴

ここまでを踏まえた判断を言い切ります。react-native-webviewを採用してよいのは、次の3条件がそろう場合です。第1に、埋め込む画面が更新頻度の高い規約・ヘルプ・キャンペーンなど、ストア審査を挟まずに差し替えたい領域に限定されていること。第2に、アプリ全体の主機能はネイティブ側に置かれ、WebViewが補助に留まること。第3に、認証の引き継ぎ方式をCookieストアかヘッダ再付与のどちらかに決めきれていることです。

逆に見送る判断が正しくなるのは、既存サイトをそのまま包んで納品する前提の案件、決済や本人確認のようにOS差が事故に直結する処理をWeb側へ置く構成、そして旧アーキテクチャのまま動く保守案件でWebView側だけ最新版へ上げたい要望が出た場合です。最後の1つは、本体のアーキテクチャ移行という別プロジェクトを呼び込みます。React Native自体を続けるかどうかを含めて迷いがあるなら、React Nativeはオワコンか?離れの実態を更新頻度・案件数・採用状況で検証もあわせてご確認ください。当社ではFlutter / React Nativeによるクロスプラットフォーム開発として、この線引きを含めた構成の相談から実装・ストア申請まで請け負っています。

よくある質問

react-native-webviewは商用アプリで無料で使えますか?

ライセンスはMITで、商用利用に追加の費用はかかりません。npmのパッケージ情報にもMITと記載されています。配布物へのライセンス表示は必要になるため、アプリ内のライセンス一覧に含めておいてください。

npmでインストールすると16系ではなく14系が入るのはなぜですか?

dist-tagsのlatestが14.0.1のままで、16.0.0はnextタグに置かれているためです。メンテナが変更量の大きさを理由に、当面14をlatestとする方針を明記しています。16系を入れる場合は@nextを明示してください。

Expoのプロジェクトで最新版へ上げても問題ありませんか?

SDK 57のバンドル定義は13.16.1を指しています。個別に上げること自体は可能ですが、SDK単位で整合を取る仕組みから外れるため、開発ビルドの作り直しと実機確認を前提にしてください。急ぐ理由がなければ定義に従う方が安全です。

注入したJavaScriptが実行されないのですが原因は何ですか?

まずonMessageが設定されているかを確認してください。未設定だと注入コードごと実行されません。次に、注入する文字列が有効な値へ評価されるか、例外を投げていないかを見ます。Android側での早期注入は公式に不安定と書かれている点も確認材料になります。

Flutterで同じことをする場合のパッケージは何にあたりますか?

Flutterでは公式のwebview_flutterか、機能の広いflutter_inappwebviewが該当します。双方向通信の設計思想は近いものの、API名も版の事情も別物です。詳細はflutter_inappwebviewとは?6.1系の停滞とJS連携・Cookie制御の判断にまとめています。

関連記事

資料請求

RELATED POSTS 関連記事