# RN 和 h5 交互

react-native-webview

yarn add react-native-webview
react-native link react-native-webview

# WebView 的基本属性方法介绍和使用

# 主要属性介绍

  • source: 在 WebView 中载入一段静态的 html 代码或是传入一个 url(可以附带一些 header 选项);
  • automaticallyAdjustContentInsets: 设置是否自动调整内容,默认值为 true;
  • contrntInset: 设置内容所占尺寸大小,格式:{top:number,left:number,bottom:number,right:number};
  • injectedJavaScript(string): 当网页加载之前注入一段 js 代码,其值为字符串形式;
  • startInLoadingState: 是否开启页面加载的状态,值为 true 或 false;
  • bounces: 回弹特性。默认为 true,如果设置为 false,则内容拉到底部或头部都不回弹。
  • scalesPageToFit: 设置网页是否缩放自适应到整个屏幕视图,以及用户是否可以改变缩放页面;
  • scrollEnaled: 用于设置是否开启页面滚动;
  • domStorageEnable: 用于控制是否开启 DOM Storage(存储);
  • javaScriptEnabled: 是否开启 JavaScript,在 ios 中默认是开启的;

# 主要方法介绍

  • onNavigationStateChange: 当导航状态变化的时候调用;
  • onLoadStart: 当网页开始加载时调用;
  • onError:  当网页加载失败时调用;
  • onLoad: 当网页加载结束时调用;
  • onLoadEnd: 当页面加载结束时调用,不管成功还是失败;
  • renderLoading: WebView 组件正在渲染页面时触发的函数,只有 startInLoadingState 为 true 时,函数才起作用;
  • renderError: 监听渲染页面出错的函数;
  • onShouldStartLoadWithRequest: 该方法容许拦截 WebView 加载的 URL 地址,进行自定义处理,该方法通过返回 true 或 false 来决定是否继续加载该拦截到的请求;
  • onMessage: 在 WebView 内部网页中,调用 window.postMessage 可以触发此属性对应的函数, 通过 event.nativeEvent.data 获取接收到的数据,实现网页和 RN 之间的数据传递;
  • injectJavaScript(function): 函数接受一个字符串,该字符串将传递给 WebView,并立即 执行为 JavaScript;

# 通过 url 加载一个页面

render(){
	return(
		<View style={styles.container}>
			<WebView
				ref={webView=>this.webView=webView}
				startInLoadingState={true}
				onNavigationStateChange={e=>this.onNavigationStateChange(e)}
				source={{uri:'https://github.com/xxx'}}
			/>
		</View>
	)
}

# 通过 HTML 加载一个页面

render(){
	return (
		<View>
			<WebView
				ref={webView=>this.webView=webView}
				startInLoadingState={true}
				onNavigationStateChange={e=>this.onNavigationStateChange(e)}
				source={{html:'<h1>demo</h1>'}}
			/>
		</View>
	)
}

# RN WebView 和 H5 之间的通信

# RN WebView 向 H5 页面注入 JS

  • 通过 injectedJavaScript 的方式注入 JS,在 H5 页面加载后立即执行。(WebView 主动触发 H5 的方法,从而实现通信)

# RN 向 H5 发送消息,h5 监听

WebView 绑定 ref,通过 html5 新增的 postMessage 发送消息

onLoadEnd={()=>{
	this.refs.webView.postMessage('RN向H5发送消息');
}} // 页面加载结束调用

在 H5 中注册监听

window.onload = function(){
	document.addEventListener('message', function(msg){
		console.log(msg)
		message = msg.data
	})
}

# h5 向 RN 发消息,RN 通过 onMessage 接收消息

onMessage={(event)=>{console.log(event.nativeEvent.data);}} // data只能是字符串

// h5
window.postMessage('网页向RN发送消息');

# webView js 注入 h5

//  H5
<!-- 页面点击通信 -->
export const invokeMethod = (type='',params = {}, callback)=>{
	if(!window.APP) return false;
	return window.APP.invokeClientMethod(type, params, callback);
}
<!-- 页面加载通信 -->
window.initDataFromApp = function(data){
	// 访问到store
	// window.g_app._store
	// 访问到 dispatch
	window.g_app._store.dispatch({type:  'user/init',  data})
}
(兼容 浏览器cookie)
if(!window.navigator.userAgent.includes('App')){
	const token = cookie.load('JWT');
	if(token){
		window.initDataFromApp({token: token})
	}
}
//  WebView
function clientMethod(){
	var APP =  {
		__GLOVAL_FUNC_INDEX__: 0,
		invokeClientMethod: function(type,params, callback){
			var name;
			if(callback){
				if(typeof callback ===  'function'){
					name= APP.createGlobalFuncForCallback(callback);
				} else{
					name=callback;
				}
			}
			window.ReactNativeWebView.postMessage(JSON.stringify({type,params,callback:name}))
		},
		createGlobalFuncForCallback:  function(callback){
			if(callback){
				var callbackName = '__GLOBAL_CALLBACK__'+(ZGAPP.__GLOBAL_FUNC_INDEX__++);
				window[callbackName] =  callback;
				return callbackName;
			}
			return  null;
		},
		invokeWebMethod: function(callback, args){
			if(callback && typeof  callback==='string'){
				var func  = void 0;
				if((func == window[callback])&& typeof func === 'function'){
					setTimeout(function(){
						func.call(this, args);
					},0)
				}
			}
		}
	}
	window.APP = APP;
	window.webviewCallback = function(data){
		window.APP['invokeWebMethod'](data.callback, data.args);
	};
};
const patchPostMessageJsCode =  `(${String(clientMethod)})()`;
const data = {
	'token': token.jwt,
	'platform':  Platform.OS,
}
const injectedJavaScript = `
	${patchPostMessageJsCode}
	initDataFromApp && initDataFromApp(${JSON.stringify(data)});
`
onMessage=(event)=>{
	var  data =  JSON.parse(event.nativeEvent.data);
	if(!data){
		return;
	}
	const {type,params, callback} = data;
	switch(type){
		case 'xxx':
		...
		break;
		...
	}
}
...
<WebView
	onMessage =  {this.onMessage}
	ref={r=>(this.webref =  r)}
	injectedJavaScript =  {injectedJavaScript}
	source= {{...}}
/>
...