react-native webview怎么加载前端打包出来的SPA静态文件

server/2024/11/14 3:07:06/

react-native webview怎么加载前端打包出来的SPA静态文件

前言

这是一次比较有意思的记录,关于这个react-native加载打包前端的出来的静态文件,网上找了很多文章,没有一个说清楚的,说的都是有点模糊,当我亲自去尝试,踩了比较多坑,先说说,为什么会有这种想法,为什么不用链接的方式引入呢,因为如果以链接的方式引入的时候,加载过程比较慢,而且会产生白屏,再者就是直接崩溃,网咯不行的时候,这时候就会给用户带来非常不好的体验。把前端的文件放到apk里面,直接加载本地,好处,前端文件都在本地,当没网的时候可以渲染骨架,也可以渲染出页面只是显示暂无数据,就不会有H5都是白屏的情况,再者加载本地的前端资源,比加载服务器资源的要快,虽然造成了APK包会偏大,但是用户的体验会好很多,这就是以空间换时间,从而达成目的。

而能够达到以上的需求,如果是我们传统的开发比如react,vue,进行开发,最后进行打包成apk,借助Hbuilderx工具,我有一篇文章就是介绍这个web打包成app的,除了这种方式,我们通常也会选择跨端的方式进行多端开发,如uniapp,react-native。 而unaipp通常也是借助Hbuilderx进行打包成apk,当然也可以打包成本地离线资源再借助android studio进行打包,如果这些方案不想要,你可以直接再android studio新建一个安卓项目,进行加载本地打包。而今天的主角,我用的是react-native进行加载本地资源打包,其实,底层还是安卓的打包,只是别人封装好了插件, 我直接使用。

抛出问题

项目中会遇到我们需要嵌套前端页面进入react-native工程,react-native的webview引入时会遇到一个问题,按照我们平时的引入方法发现,如果是单页面的引入不会有问题,但是如果是一个带有js,css,img这样的静态前端打包出来的静态资源引入时,我们会发现不是和我们想象的一样,他会加载不进来,显示的仅仅是html这个文件,那如何才能把他的静态引入正确导入我们的包里且正确显示在app呢?今天就带着大家解决这个困惑,轻松搞定静态引入h5到我们的webview里.

前端能否加载出来SPA呢?
在这里插入图片描述

官网给出的回复是这样的。
在这里插入图片描述
翻译一下

注意:这目前可能不起作用,如#428和#518中所述。可能的解决方法包括将所有资源与webpack或类似工具捆绑在一起,或运行本地Web服务器。
显示非工作方法有时,您会将HTML文件与应用程序捆绑在一起,并希望将HTML资源加载到您的WebView中。

没有说不行,可能不起作用,(下面会为你讲解),作者将会深入给你讲解。

作者的版本:

“react-native”: “0.75.4”,
“react-native-webview”: “^13.12.3”,

react-native-webview

为了达成以上需求,我们使用react-native-webview。在较新版本的React Native中不再默认包含webview组件,我们需要自己安装。

1. 安装

npm install react-native-webviewreact-native link react-native-webview

我这里就不详细说面这个webview了,rn的webview安装配置api请参考(https://github.com/react-native-webview/react-native-webview)

2. 使用

react-native-webview的使用非常简洁,就像使用任何一个react组件一样。

import React from 'react'
import { WebView } from 'react-native-webview'const App = () => {return (<WebViewsource={{uri: 'https://www.juejin.cn'}}style={{flex: 1}}/>)
}
export default App

3.加载前端SPA文件

1.rn工程根目录新建bundle文件夹

在RN项目根目录中创建public文件,public文件下创建Static.bundle文件夹

在这里插入图片描述

2.这个bundle文件夹里放置前端的所有静态文件

在这里插入图片描述

3.android配置

打开根目录/android/app/build.gradle,添加以下内容,这里只是把public下的所有的文件拷贝到安卓的src/main/assets目录下不包括public文件夹(注意)

android {…sourceSets {main {assets.srcDirs = ['src/main/assets','../../public']}}
4.RN页面加载
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { WebView } from 'react-native-webview';
import { useWindowDimensions } from 'react-native';const DetailsScreen = ({ route, navigation }: any) => {const { itemId, message } = route.params || {};const { width, height } = useWindowDimensions();const handleConsoleMessage = (event: any) => {console.log(event.nativeEvent.data); // 这里会打印你在 HTML 文件中 console.log 的内容}return (<View style={styles.container}><Button title="Go back" onPress={() => navigation.goBack()} /><WebVieworiginWhitelist={['*']}source={{ uri: 'file:///android_asset/Static.bundle/index.html' }} //这里只考虑安卓javaScriptEnabled={true}onMessage={handleConsoleMessage}domStorageEnabled={true}useWebKit={true}scalesPageToFit={false}allowFileAccess={true}style={{ width, height }}onError={(e) => console.log('Error loading HTML:', e.nativeEvent)}startInLoadingState={true}renderLoading={() => <View><Text>加载中...</Text></View>}onLoadStart={(e) => console.log('Loading URL:', e.nativeEvent.url)}onLoadEnd={() => console.log('HTML loaded')}allowsInlineMediaPlayback={true} // 允许嵌入的多媒体播放mixedContentMode="always" // 允许加载非 HTTPS 内容allowingReadAccessToURL="*"decelerationRate={'normal'}onHttpError={(syntheticEvent) => {const { nativeEvent } = syntheticEvent;console.log('HTTP Error: ', nativeEvent);}}/></View>);
};const styles = StyleSheet.create({container: {flex: 1,backgroundColor: 'red',},mainContent: {flexDirection: 'row',flex: 1,padding: 10,},leftPanel: {width: '45%',backgroundColor: '#123c76',padding: 15,borderRadius: 8,marginRight: 10,},attendanceBox: {alignItems: 'center',marginBottom: 20,},attendancelobo: {alignItems: 'center',marginBottom: 20,},attendanceText: {color: '#ffffff',fontSize: 24,fontWeight: 'bold',},
});export default DetailsScreen;
5.主要容易出现的问题
1.加载的路径不对会出现这种情况

请添加图片描述

2.安卓内置的webview太低,无法解析js新的语法(会白屏)

如果浏览器能正常打开,而安卓不能打开,报错 Uncaught SyntaxError: Unexpected token (

在这里插入图片描述

查看目前安卓使用的webview偏低

在这里插入图片描述

三种解决方案,一种是升级安卓的内置的webview,一种是使用第三方的webview SDK进行加载如腾讯的TBS X5内核webview加载页面。还有一种方案就是前端进行打包ES降级别,到降ES5

3.前端的打包(会白屏)(大部分人都卡在了这里)

一个是一定是hash路由。
本地请求跨域。这个需要服务进行运行。

在这里插入图片描述

4.怎么判断前端的打包是否能够加载出来

本地无法加载出来

在这里插入图片描述

需要开启服务进行解析,这种采用webview直接加载是加载不出来的。

在这里插入图片描述

前端打出来的是一个静态资源包,本地路径直接访问就能加载出来,就说明直接加载就可以

在这里插入图片描述

这是我成功加载出来,因为设备的安卓webview太低,我用手机的。

在这里插入图片描述

5.开启一个本地服务也能解决

对于,无法解决打包问题的前端同学,我这边还有一个解决方案。
看这里,利用react-native-static-server,开启一个服务,官方推荐的一种方法。然后webview的地址为这个服务的地址就行了。
在这里插入图片描述

https://github.com/react-native-webview/react-native-webview/blob/master/docs/Guide.md#basic-inline-html
参考:
https://github.com/birdofpreyru/react-native-static-server

6.其它问题

如果是其它问题,只能通过调试看看浏览器报错。

3. 调试

最后来讲讲如何调试webview,毕竟前端程序员要是没有console.log基本和瞎了差不多

使用chrome调试android的webview
  1. 运行安卓模拟器,并进入webview页面
  2. 在chrome地址栏中输入并访问chrome://inspect/#devices
  3. 在页面中点击inspect按钮,即可打开控制台。

4. React Native与WebView通信

只显示内容显然不够用,我们经常有在RN与WebView间通信的需求。

先给我们的index.html添加一个节点

<body>……<p id="run-first">empty</p>
</body>
3.1 React Native => WebView
1. injectedJavaScript

injectedJavaScript可以在webview加载完页面后执行js,注意传入的是字符串。在iOS上还必须加上onMessage属性,否则不能触发。重新build之后,就可以看到效果了。类似的,还有一个injectedJavaScriptBeforeContentLoaded属性,不同点是这个属性的方法会在页面加载前触发。

import { SafeAreaView, Platform } from 'react-native'
import WebView from 'react-native-webview'const App = () => {const runFirst = `const el = document.getElementById('run-first');el.innerText = 'run first!'`return (<SafeAreaViewstyle={{flex: 1,backgroundColor: '#fff',}}><WebViewsource={{uri: `${Platform.OS === 'android' ? 'file:///android_asset/' : ''}Static.bundle/index_.html`,}}originWhitelist={['*']}style={{flex: 1,}}injectedJavaScript={runFirst}onMessage={() => {}}/></SafeAreaView>)
}export default App
2. postMessage

postMessage可以让我们手动触发发送数据到webview,注意发送的数据必须为字符串类型,在webview中通过data字段接收。

在rn组件中创建refWebView绑定到WebView上,并通过调用postMessagewebview发送数据

import { SafeAreaView, Platform, View, Pressable, Text } from 'react-native'
import WebView from 'react-native-webview'
import { useRef } from 'react'const App = () => {const runFirst = `const el = document.getElementById('run-first');el.innerText = 'run first!'`const refWebView = useRef<WebView | null>(null)const onPress = () => {refWebView.current.postMessage('message from react native')}return (<SafeAreaViewstyle={{flex: 1,backgroundColor: '#fff',}}><View><Pressable onPress={onPress}><Text>Post Message</Text></Pressable></View><WebViewref={refWebView}source={{uri: `${Platform.OS === 'android' ? 'file:///android_asset/' : ''}Static.bundle/index_.html`,}}originWhitelist={['*']}style={{flex: 1,}}injectedJavaScript={runFirst}onMessage={() => {}}/></SafeAreaView>)
}
3.2 WebView => React Native

从WebView发送数据到RN,使用window.ReactNativeWebView.postMessage。同样的,只能发送字符串类型,rn组件中使用onMessage来接收。

index.html中新增一个send message按钮,绑定sendMessage方法。

<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><p id="run-first">empty</p><p>Hello,React Native WebView</p><button onclick="sendMessage()">send Message</button>
</body>
<style>body {height: 100%;width: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;}
</style>
<script>const sendMessage = () => {window.ReactNativeWebView.postMessage('message from webview')}document.addEventListener('message', (msg) => {const el = document.getElementById('run-first')el.innerText = msg.data})window.addEventListener('message', (msg) => {const el = document.getElementById('run-first')el.innerText = msg.data})
</script>
</html>

在rn组件中,使用onMessage监听,并通过设置状态直接反映到屏幕上。

import { SafeAreaView, Platform, View, Pressable, Text } from 'react-native'
import WebView from 'react-native-webview'
import { useRef, useState } from 'react'const App = () => {const runFirst = `const el = document.getElementById('run-first');el.innerText = 'run first!'`const refWebView = useRef<WebView | null>(null)const onPress = () => {refWebView.current.postMessage('message from react native')}const [msgFromWV, setMsgFromWV] = useState('')return (<SafeAreaViewstyle={{flex: 1,backgroundColor: '#fff',}}><View><Pressable onPress={onPress}><Text>Post Message</Text></Pressable><Text>{msgFromWV}</Text></View><WebViewref={refWebView}source={{uri: `${Platform.OS === 'android' ? 'file:///android_asset/' : ''}Static.bundle/index_.html`,}}originWhitelist={['*']}style={{flex: 1,}}injectedJavaScript={runFirst}onMessage={event => {setMsgFromWV(event.nativeEvent.data)}}/></SafeAreaView>)
}export default App

最后总结

遇到问题一定不要抓瞎,一定要找到问题所在,如果是常见问题报错,可以直接搜出来,如果还是解决不了,一定要会调试,根据调试出来的信息进行解决,看看官网,看看有没有人跟你遇到一样的问题。如果都没有,就针对你的报错问题,进行排除解决,因为如果是跨端开发,你要排除是安卓问题,还是后台问题,再看看是否是前端的问题,再去解决对应的前端问题,前端搞跨端一定要懂调试,调试,调试,不能抓瞎,不管搞什么,都应该懂调试!!!

觉得不错的话,可以点个攒,也可以关注我,后续会持续更新关于React-native的文章哦。欢迎讨论

本篇文章参考:在React Native中使用WebView的全面指南在React Native中使用WebView的全面指南 rea - 掘金


http://www.ppmy.cn/server/141746.html

相关文章

java实现中小企业的erp系统

项目介绍 技术架构: springboot3jdk17mybatis-plusmysql8kotlinvueuniappelementui等

A20红色革命文物征集管理系统

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

[Linux]:IO多路转接之epoll

1. IO 多路转接之epoll 1.1 epoll概述 epoll是Linux内核为处理大规模并发网络连接而设计的高效I/O多路转接技术。它基于事件驱动模型&#xff0c;通过在内核中维护一个事件表&#xff0c;能够快速响应多个文件描述符上的I/O事件&#xff0c;如可读、可写、异常等&#xff0c;…

Vue vs React:两大前端框架的区别解析

在现代前端开发中&#xff0c;Vue.js 和 React.js 是两个最受欢迎的框架和库。我们常常面临选择它们的困惑。虽然这两者在本质上都是为了构建用户界面而设计的&#xff0c;但它们在设计理念、使用方式和生态系统等方面有着显著的区别。今天&#xff0c;我们将通过深入分析这两个…

ubuntu 24.04运行chattts时cuda安装错误原因分析

使用ubuntu 24.04&#xff0c;按照2noise/ChatTTS官方流程安装依赖时报错。ChatTTShttps://github.com/2noise/ChatTTS 这是因为cuda版本不对&#xff0c;ChatTTS目前的版本&#xff0c;要求支持cuda 12.4及以上&#xff0c;但是如果nvidia显卡驱动版本较老&#xff0c;无法支…

【kafka】大数据编写kafka命令使用脚本,轻巧简洁实用kafka

kafka是大数据技术中举足轻重的技术&#xff0c;市面上也有很多kafka的ui界面&#xff0c;但是都会占用比较大的内存和性能&#xff0c;这里我编写好了一个fakfa的脚本集成了kafka常见的命令使用。脚本资源放在文章顶部可自行拿取。 《Kafka 命令大全系统脚本使用指南》 在大数…

从零创建vue+elementui+sass+three.js项目

初始化&#xff1a; vue init webpack projectnamecd projectnamenpm install支持sass: npm install sass --save-dev npm install sass-loader7.1.0 --save-dev npm install node-sass4.12.0 --save-devbuild/webpack.base.conf.js添加 rules: [...,{test: /\.scss$/,loade…

【MATLAB源码-第292期】基于matlab的4ASK调制解调窄带通信系统仿真,输出各节点波形图以及误码率曲线图。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 窄带通信系统是指带宽较小、频谱利用效率较低的通信系统。与宽带通信系统相比&#xff0c;窄带系统的特点是信号的带宽相对较窄&#xff0c;因此需要更精确的调制技术来实现有效的通信。在窄带通信中&#xff0c;常见的调制方…