git : https://github.com/react-native-webview/react-native-webview
react-native: https://reactnative.cn/docs/webview#nativeconfig
在APP中,渲染html
npm install react-native-webview
yarn add react-native-webview
import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';
export default class App extends Component {
render() {
return (
<View style={{flex:1}}>
<WebView source={{ uri: 'https://www.baidu.com' }} />
</View>
)
}
}
渲染html字符串
{/* ... */}
<WebView
originWhitelist={['*']}
source={{ html: `<h1>这里是一个标题</h1>` }}
/>
{/* ... */}
automaticallyAdjustContentInsets
控制是否调整放置在导航条、标签栏或工具栏后面的web视图的内容。默认值为true
contentInset {top: number, left: number, bottom: number, right: number}
设置网页内嵌边距
injectedJavaScript
这个属性的作用是设置一个在网页加载之前执行的 js 代码。
mediaPlaybackRequiresUserAction
设置页面中的HTML5音视频是否需要在用户点击后再开始播放。默认值为true
scalesPageToFit
设置是否要把网页缩放到适应视图的大小,以及是否允许用户改变缩放比例。
source 常用
在WebView中指定加载内容html或者url,可以指定header,method等
originWhitelist 属性
webview中唤起app
// 唤起支付宝、支付宝香港、云闪付
<WebView
originWhitelist={['http://*', 'https://*', 'intent://*', 'alipays://*', 'alipayhk://*', 'uppaywallet://']}
/>
startInLoadingState
强制WebView在第一次加载时先显示loading视图。默认为true
domStorageEnabled(android)
布尔值,指定是否开启DOM本地存储
javaScriptEnabled(android)
布尔值,指定WebView中是否启用JavaScript。只在Android上使用,因为在iOS上默认启用了JavaScript。
mixedContentMode(android)
指定混合内容模式。即WebView是否应该允许安全链接(https)页面中加载非安全链接(http)的内容,
‘never’ (默认) - WebView不允许安全链接页面中加载非安全链接的内容
‘always’ - WebView允许安全链接页面中加载非安全链接的内容。
‘compatibility’ - WebView会尽量和浏览器当前对待此情况的行为一致
userAgent(android)
为WebView设置user-agent字符串标识。这一字符串也可以在原生端用WebViewConfig来设置,但js端的设置会覆盖原生端的设置。
allowsInlineMediaPlayback(ios)
指定HTML5视频是在网页当前位置播放还是使用原生的全屏播放器播放。 默认值为false,视频在网页播放还需要设置webkit-playsinline
bounces(ios)
指定滑动到边缘后是否有回弹效果。
decelerationRate(ios)
指定一个浮点数,用于设置在用户停止触摸之后,此视图应以多快的速度停止滚动。也可以指定预设的字符串值,如"normal"和"fast",
scrollEnabled(ios)
是否启用滚动
injectJavaScript
函数接受一个字符串,该字符串将传递给WebView,并立即执行为JavaScript
onError
加载失败时回调
onLoad
完成加载时回调
onLoadEnd
加载成功或者失败都会回调
onLoadStart
开始加载的时候回调
onMessage 实现网页和RN之间的数据传递
在 webview 内部的网页中调用 window.postMessage 方法时可以触发此属性对应的函数,从而实现网页和 RN 之间的数据交换。 设置此属性的同时会在 webview 中注入一个 postMessage 的全局函数并覆盖可能已经存在的同名实现。
网页端的 window.postMessage 只发送一个参数 data,此参数封装在 RN 端的 event 对象中,即 event.nativeEvent.data。data 只能是一个字符串。
renderError
返回一个视图用来提示用户错误
renderLoading
返回一个加载指示器
renderLoading={() => {
return <View><Text>这是自定义Loading...</Text></View>
}}
onShouldStartLoadWithRequest(ios)
请求自定义处理,返回true或false表示是否要继续执行响应的请求
onNavigationStateChange
在webView状态发生改变的时候回调webView的event信息,event信息里包含了url, title, loading, canGoBack, canGoForward.
html的引入不同方式
<WebView
//不同的source情况
// source={{ uri: 'http://johnyu.cn' }}
// source={{ html: '<h1>Hello world</h1>' }}
// source={require('./index.html')} //此方式不会进行html解析
//文件位于android/src/main/assets/下
source={{uri:'file:///android_asset/index.html'}}
injectedJavaScript={runFirst}
onMessage={(this._receive)}
/>
import React, { Component } from 'react';
import { View, ScrollView, SafeAreaView } from 'react-native';
import { WebView } from 'react-native-webview';
export default class App extends Component {
constructor(props) {
super(props);
this.state = { webViewHeight: 0 };
}
{/* 根据内容计算 WebView 高度 */}
onWebViewMessage = (event) => {
this.setState({ webViewHeight: Number(event.nativeEvent.data) });
}
render() {
return (
<View style={{ flex: 1 }}>
<View style={{ height: 100, backgroundColor: 'yellow' }}></View>
<View style={{ height: this.state.webViewHeight }}>
<WebView
originWhitelist={['*']}
source={{ html: `<p>这里是一个标题</p>` }}
injectedJavaScript='window.ReactNativeWebView.postMessage(document.documentElement.scrollHeight)'
onMessage={this.onWebViewMessage}
/>
</View>
<View style={{ height: 100, backgroundColor: 'green' }}></View>
</View>
)
}
}
这个其实很简单,只需要在 header 中设置 meta 标签即可。
<WebView
originWhitelist={['*']}
source={{ html: `
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>这里是一个标题</p>
</body>
</html>
` }}
injectedJavaScript='window.ReactNativeWebView.postMessage(document.documentElement.scrollHeight)'
onMessage={this.onWebViewMessage}
/>
html
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div style="text-align: center">
<button id="button">发送数据到react native</button>
<p style="text-align: center">收到react native发送的数据: <span id="data"></span></p>
</div>
<script>
var data = 0;
function sendData(data) {
if (window.originalPostMessage) {
window.postMessage(data);
} else {
throw Error('postMessage接口还未注入');
}
}
window.onload = function () {
document.addEventListener('message', function (e) {
document.getElementById('data').textContent = e.data;
});
document.getElementById('button').onclick = function () {
data += 100;
sendData(data);
}
}
</script>
</body>
</html>
RN
import React from 'react';
import {
View,
Text,
StyleSheet,
WebView
} from 'react-native';
export default class Web extends React.Component {
constructor(props) {
super(props);
this.state = {
webViewData: ''
}
this.data = 0;
}
sendMessage() {
this.refs.webview.postMessage(++this.data);
}
handleMessage(e) {
this.setState({webViewData: e.nativeEvent.data});
}
render() {
return (
<View style={styles.container}>
<View style={{width: 375, height: 220}}>
<WebView
ref={'webview'}
source={require('./index.html')}
style={{width: 375, height: 220}}
onMessage={(e) => {
this.handleMessage(e)
}}
/>
</View>
<Text>来自webview的数据 : {this.state.webViewData}</Text>
<Text onPress={() => {
this.sendMessage()
}}>发送数据到WebView</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 22,
backgroundColor: '#F5FCFF',
},
});
注:
rn向html发送数据,html接收
rn向html发生数据可以通过postMessage函数实现。如下
sendMessage() {
this.refs.webview.postMessage(++this.data);
}
//在html中注册事件接收rn发过来的数据并显示在html中
document.addEventListener('message', function(e) {
document.getElementById('data').textContent = e.data;
});
html向rn发送数据,rn接收
在html中我们定义了一个按钮,并添加事件向rn发送数据
//window.postMessage向rn发送数据
document.getElementsByTagName('button')[0].addEventListener('click', function() {
window.postMessage('这是html发送到RN的消息');
});
当html中调用了window.postMessage函数后,WebView的onMessage函数将会被回调,用来处理html向rn发送的数据,可以通过e.nativeEvent.data获取发送过来的数据。
//接收HTML发出的数据
_onMessage = (e) => {
this.setState({
message: e.nativeEvent.data,
})
}
<WebView
// 配置白名单,确保能够正常唤起app
originWhitelist={['http://*', 'https://*', 'intent://*', 'alipays://*', 'alipayhk://*', 'uppaywallet://']}
onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest}
/>
onShouldStartLoadWithRequest=(request)=>{
// short circuit these
if (!request.url ||
request.url.startsWith('http') ||
request.url.startsWith("/") ||
request.url.startsWith("#") ||
request.url.startsWith("javascript") ||
request.url.startsWith("about:blank")
) {
return true;
}
// blocked blobs
if(request.url.startsWith("blob")){
Alert.alert("Link cannot be opened.");
return false;
}
// list of schemas we will allow the webview
// to open natively
if(request.url.startsWith("tel:") ||
request.url.startsWith("mailto:") ||
request.url.startsWith("maps:") ||
request.url.startsWith("geo:") ||
request.url.startsWith("alipays:") ||
request.url.startsWith("alipayhk:") ||
request.url.startsWith("uppaywallet:") ||
request.url.startsWith("sms:")
){
Linking.openURL(request.url).catch(er => {
Alert.alert("Failed to open Link: " + er.message);
});
return false;
}
// let everything else to the webview
return true;
}