react-native中IOS的webview和js层通讯 - UIWebview

前言

在9012的最后一篇写到了在rn中安卓的webview的通讯原理,而做为0202年的第一篇,继续讨论上年rn中webview通讯剩下的部分。react

背景:

对于webview,了解过的人都知道在ios端会存在两种类型的webview(UIWebview和WKWebview),而他们之间的区别主要以下:ios

  • 时间上的差别:UIwebview是在ios2以后才有,Wkwebview是在ios8以后才有;
  • UIwebview占用的内存较大,而WKwebview侧是内存占有很少,所以性能会比前者好;
  • WKwebview拥有高达60FPS滚动刷新率(滚动时每秒可达到60次渲染,通常最多64次)及内置手势;
  • WKwebview比UIwebview拥有更多H5的特性;
  • WKwebview提供了加载网页的进度属性;
  • WKwebview在app和web通讯方面比UIwebview要好;
  • WKWebView没有作缓存处理,因此对网页须要缓存的加载性能要求没那么高的仍是能够考虑UIWebView.

RN中IOS的webview结构:

大体流程:

在ios中,应用层会设置rn中webview的某个属性,而weview会经过webview.iso.js进行处理,若是该属性是原生底层直接拥有的,那么就直接往下传递,若是该属性不是底层所拥有的,则须要经过在webview.ios.js层处理成底层组件所拥有的属性,而后再往下传递下去,由RCTWebview或者RCTWKWebview进行处理。web

例如:
source属性:webview层设置了source -----> webview.ios.js往下传递 ------> RCTWebviewManager.m能接受到该属性,而后继续往下传递 -----> RCTWebview进行处理该属性;segmentfault

onLoadStart属性:webview层设置了onLoadStart ----> webview.ios.js对该属性进行处理,包装成_onLoadingStart,而后传给RCTWebviewManager ----> RCTWebviewManager.m能接受到该属性,而后继续往下传递 -----> RCTWebview进行处理该属性;浏览器

大概的流程图:

image.png

UIWebview的相关知识:

ios和js的交互
  • stringEvaluatingJavascriptFromString:该方法时可让ios层执行js代码;

语法形式:缓存

- (void)injectJavaScript:(NSString *)script
{
  [_webView stringByEvaluatingJavaScriptFromString:script];
}

当js层传递js字符串给ios的时候,ios就会用stringEvaluatingJavascriptFromString这个方法执行这个script。app

  • shouldStartLoadWithRequest: 该方法是用来对webview中的url进行拦截,而后判断是否打开这个url连接,须要返回一个boolean值。当webview中存在一个url连接,就会触发这个方法,而后对url进行判断,若是是返回boolean,则能够打开url的连接,不然不行。

image.png

生命周期

对于uiwebview来讲,通常有三个生命周期他们分别是:post

  • shouldStartLoadWithRequest:页面在准备加载资源;
  • webViewDidFinishLoad:页面资源完成加载完毕;
  • didFailLoadWithError:资源加载失败;

rn中UIWebview和js之间的通讯机制:

在webview之中通讯最为重要,经过postMessage向rn层传递信息,rn层只须要message就行,相反也行。该实现的逻辑是在资源加载完成的时候执行的,就是在webviewDidFinishLoad
image.png性能

内嵌页面向rn传递信息和接受信息:ui

window.postMessage(data); 
document.addEventListener('message', (event) => {});

rn层向内嵌页面传递信息:

<Webview
   onMessage={event => {}}
   ref={(_ref) => {this.webview = _ref}}
   ...
/>
this.webview.postMessage(data)

细心的朋友此处应该能够发现出这里的postMessage和平时咱们调用的不太同样:
通常状况下:window.postMessage(data, origin);
内嵌在webview之中:window.postMessage(data);
缘由是由于在uiwebview之中从新定义了window.postMessage,原来的postmessage已经被赋予到originMessage之中,因此若是在内嵌页面中出现了postmessage(data),放在浏览器会报错,放在rn的webview就会没事。

当页面资源加载完成以后,就会触发webviewDidFinishLoad这个生命周期,在这个生命周期内,会作几件事情:

image.png

其中从新定义postmessage的js代码:

image.png

大概的意思就是将内嵌页面调用postmessage的信息存在messagequeue之中(以字符串形式放进去),而后经过定义window.location的值来传递信息给原生成,其中window.location的格式是:
'%@://%@?' + encodeURIComponent(messageQueue.shift());" ,当中的两个%@会被RCTJSNavigationScheme和kPostMessageHost代替从而造成新的url地址(不是经常使用的http协议的地址,是指定的特殊协议)

例如:'react-js-navigation://postMessage?' + encodeURIComponent('{"A":1}') ===> "react-js-navigation://postMessage?%7B%22A%22%3A1%7D";因为内嵌页面没有window,因此只能用document来监听webview传来的信息。

postmessage的信息如何传递给原生层:每当webview之中出现url的请求,都会触发shouldStartLoadWithRequest,此时就会由

image.png

大概就是判断url的host是否为kPostMessageHost,若是是则认为是postmessage传来的,而后执行_onMessage方法,而这个方法事由上层js定义的:
image.png

webview如何将信息传递给内嵌页面:
image.png

大概就是经过document.dispatchEvent发起一个事件,而后在内嵌页面之中由document进行监听;

下面就是整一块uiwebview的通讯流程:
image.png

因此若是要js层调用原生层能力,能够经过协议请求,而后在原生对该协议进行拦截处理,从而判断是否调用原生能力。

以上就是对uiwebview的一个比较浅的概述,下一篇会继续介绍一下rn中wkwebview的通讯原理。

相关文章
相关标签/搜索