背景介绍:

前段时间花了一些工夫去钻研react-native中webview的通信机制,理解到当中的原理,正好业务中也遇到了rn中webview内嵌h5的页面,发现尽管rn提供了一套相似js的postmessage机制,但在h5和rn之间的通信中往往仅靠这个机制是很难进步开发效率和升高代码的复杂度。
因而基于晋升在rn中开发h5效率的原因下,开发了这个ird-RnBridge。这个库从往年5月份开始构思,设计,而后五月份底实现了v1.0.0,之后在七月份进行了迭代开发,并实现了v1.1.0的功能性版本迭代,足以能反对很多场景的开发和调试。

版本迭代历史

简略介绍:

该桥梁次要是实用在react-native和h5之间的通信场景下,并且在rn侧和h5侧各提供了一套不雷同的api办法汇合以便调用。它提供了几个方面的性能:

1) 安全性校验建设桥梁:
因为rn的很多原生性能是通过webview提供给h5页面调用,如果不甄别嵌入在webview中的h5页面是否平安,而间接全副提供,这会带来很多安全性的问题。因而rnbridge采取了双重校验形式:
首先:h5侧必须调用checkSafety发动建设桥梁的申请,rn会对其发过来的申请进行校验,该校验会交给rn侧解决,如果解决通过,则rnbridge会发送一个token值给到h5侧,以表明桥梁建设胜利;
其次:每次h5和rn的通信,都会带上该token值,rnbridge在rn侧会对其进行匹配,不统一会禁止调用。

h5侧:

      RnBridge.checkSafety({demo: 'demo'}, (data) => {          document.getElementById('demo').style.color = 'blue';          console.log('bridge success:', data);          RnBridge.getSessionStore(['sat2'], (data) => {              const content = document.getElementById('content');              content.innerText = JSON.stringify(data);              console.log('data1', data);          })      });

rn侧:

RnBridge.initWebview(this.webview, {    checkSafety: (params, send) => {       this.veritySafety(params, send);    },});veritySafety(params, send) {    send({isSuccess: true, result: 'welcome'});}

如果不定义checksafeCheck,则rnbridge主动认为是通过,从而主动建设桥梁。

2) rn侧和h5侧互相通信:
rn侧能够通过initWebview来注册提供给h5侧调用的api办法汇合,当建设了桥梁之时,rnbridge会将注册在initWebview中的办法名的汇合发送到h5侧,h5侧只须要间接调用invokeRN就能够调用rn侧的办法。同理rn侧也是。

3) 提供方便的调试形式:
因为h5内嵌在rn的webview之中,h5内的ajax和console都只能通过vconsole这个插件上看到,调试起来不怎么不便。所以rnbridge提供了debug办法并提供了console和ajax两种模式,能够间接将h5中的ajax和console间接在浏览器上看和调试。

console:

ajax:

4) 提供h5侧加载资源的性能参数:
webview加载h5以及h5和rn建设桥梁等参数能够通过sendPerformance和sendPerformanceByType来发动,并最终能够在rn层获取到h5的资源性能参数。

加载性能参数:

资源性能参数:

原理介绍:

这里大略分享一下rnbridge在桥梁建设和相互通信之间的一些设计原理:

  • 平安校验,建设桥梁:

  • h5调用rn办法:

  • rn调用h5办法:

用处介绍:

因为rnbridge在rn侧和h5侧各自都领有一套api办法汇合,所以在调用这些办法之前,须要调用rnbridge的switchMode办法,从而抉择对应的一套api办法汇合;

例如在h5侧:

RnBridge.switchMode({mode: 'h5'});

此时h5的api汇合就会注入到window.RnBridge之中,因而能够全局范畴内随便调用。

在rn侧:

RnBridge.switchMode({mode: 'rn'});

此时rn的api汇合就会注入到RnBridge自身,所以能够通过RnBridge来调用。

这是一个简略的例子:
h5侧:

 RnBridge.switchMode({mode: 'h5'});  RnBridge.initH5({    h1: (params, send) => {      send({isSuccess: true, result: {a2: 39}});    },    h2: (params, send) => {      send({isSuccess: false, result: {a1: 21}});    }});RnBridge.checkSafety({demo: 'demo'}, (data) => {    document.getElementById('demo').style.color = 'blue';});RnBridge.invokeRN({    method: 'a1',    params: {a1: 12},    success: (result) => {        document.getElementById('demo').style.color = 'green';        document.getElementById('demo').innerText = JSON.stringify(result);    },   fail: (result) => {        document.getElementById('demo').style.color = 'red';        document.getElementById('demo').innerText = JSON.stringify(result);    }});

rn侧:

RnBridge.switchMode({mode: 'rn'});export class Demo extends React.Component {    constructor(props) {        super(props);        this.webview = null;    }    render() {        return (            <View style={{flex: 1}}>                <WebView                    originWhitelist={['*']}                    source={{ uri: 'http://192.168.1.101:9001/'}}                    ref={ele => this.webview = ele}                    onMessage={(e) => {                        console.log('e', e.nativeEvent.data);                        RnBridge.listenH5(e.nativeEvent.data);                    }}                    onError={(e) => {                        console.log('error', e)                    }}                    onLoadEnd={() => {                        console.log('load end')                    }}                    onLoadStart={() => {                        console.log('load start')                    }}                />                <View>                    <Text onPress={() => {                        this.handleC()                    }}>click</Text>                </View>            </View>        )    }    componentDidMount() {        console.log('RnBridge', RnBridge);        RnBridge.initWebview(this.webview, {            a1: (params, send) => {                this.handleA(params, send);            },            a2: (params, send) => {                this.handleB(params, send);            },            checkSafety: (params, send) => {                this.veritySafety(params, send);            },            setTitle: (params, send) => {                console.log('title', params);            }        })    }    veritySafety(params, send) {        send({isSuccess: true, result: 'welcome'});    }    handleA(params, send) {        console.log(params);        send({isSuccess: false, result: 'asdf'})    }    handleB(params, send) {        console.log(params);        RnBridge.invokeH5({        });        setTimeout(() => {            send({isSuccess: true, result: 'ok'})        }, 1000);    }    handleC () {        RnBridge.invokeH5({            method: 'h3',            params: {demo: true},            success: (params) => {                console.log('params', params);            },            fail: (params) => {                console.log('fail', params);            }        })    }}

具体的实用介绍能够查看这里:
ird-rnbridge的readme

结尾:

这个工具库是利用自己早晨加班回来后,花休息时间来设计和开发,因而rnbridge可能存在一些不足之处,如有不足之处请提出,自己会利用业余时间继续优化和性能迭代;开源不易,且行且互勉,若感觉勉强还行,请在github中点个star以作激励。