如何通过React Native WebView加载本地dist目录React Web应用
你提到的Metro打包静态资源加载的思路完全可行,以下是3种可落地的实现方式,适配Monorepo架构下React+React Native的代码复用场景:
方案1:Metro托管静态资源(推荐,适配成本最低)
这是最适配Monorepo架构的方案,不需要修改原生工程配置,配置一次后web端构建完产物可以直接被RN侧引用。
调整Web端构建配置
把Web应用构建工具的资源公共路径改成相对路径,避免本地file协议加载时资源路径404:- Vite项目:配置项
base: './' - Webpack/Rspack项目:配置项
publicPath: './'
构建完成后检查dist/index.html内的资源引用,确保app.js/app.css等资源是./xxx的相对路径格式。
- Vite项目:配置项
配置Metro识别Web静态资源
在mobile工程根目录的metro.config.js中添加web静态资源后缀,让Metro把这些文件识别为静态资产打包,不要按RN业务模块解析:const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); const defaultConfig = getDefaultConfig(__dirname); const config = { resolver: { assetExts: [ ...defaultConfig.resolver.assetExts, 'html', 'htm', 'css', 'svg', 'woff', 'woff2', 'ttf' ] } }; module.exports = mergeConfig(defaultConfig, config);Monorepo场景下可以加个简单的构建脚本,web端执行build生成dist后,自动把dist目录拷贝/软链到mobile工程的固定路径(比如
src/web-dist/),不需要手动同步资源。WebView组件加载本地入口文件
直接用require引用dist下的index.html,不需要手动拼接file协议路径,自动兼容双平台:import { WebView } from 'react-native-webview'; export default function EmbeddedWebPage() { return ( <WebView source={require('./src/web-dist/index.html')} originWhitelist={['*']} allowFileAccess={true} javaScriptEnabled={true} domStorageEnabled={true} /> ); }
方案2:内联HTML字符串注入(仅适合轻量单文件场景)
如果web构建产物是单文件、没有懒加载子资源/拆分chunk,可以直接把JS、CSS内容内联到HTML字符串里,通过WebView的html属性传入,也就是你提到的Metro打包资源后拼接HTML的思路:
const embeddedHtml = ` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style>${require('./src/web-dist/app.css')}</style> </head> <body> <div id="root"></div> <script>${require('./src/web-dist/app.js')}</script> </body> </html> `; // 组件使用 <WebView source={{ html: embeddedHtml, baseUrl: '' }} originWhitelist={['*']} javaScriptEnabled={true} />
注意:该方案不支持懒加载资源、路由跳转等场景,大体积JS内联会增加内存占用,首屏加载速度慢,仅适合非常简单的静态页面。
方案3:原生工程托管静态资源(适合大体积Web产物)
如果web端构建产物体积超过10M,用Metro打包会拖慢RN热更新速度,可以把dist目录直接放到原生工程的静态资源目录下,通过file协议加载:
- Android端:把dist目录拷贝到
android/app/src/main/assets/web-dist/路径下,加载时uri填file:///android_asset/web-dist/index.html - iOS端:把dist目录拖入Xcode工程,选择
Create folder references加入主Bundle,通过原生Bundle API获取资源路径后拼接file协议地址传入
该方案需要写脚本自动同步dist产物到原生目录,配置成本较高,适合web产物体积大的场景。
常见踩坑点
- Android 9及以上版本WebView默认禁止访问本地文件,必须开启
allowFileAccess={true}属性 - Android端默认关闭DOM存储能力,如果web端用到localStorage/IndexedDB,必须开启
domStorageEnabled={true} - 如果web端有接口请求,需要配置
mixedContentMode="compatibility"避免http/https混合内容拦截 - 不要用手动拼接的绝对file路径加载资源,不同版本系统、不同调试模式下路径会有差异,优先用
require引用或者原生API获取资源路径
内容的提问来源于stack exchange,提问作者Vardan

