一:首先按照https://github.com/lzyzsd/JsBridge配置jsbridge
二:封装jsbridge给rn调用
1:新建WebViewManager继承自SimpleViewManager<BridgeWebView>
2:实现createViewInstance方法 返回一个webview实例
@Override
protected BridgeWebView createViewInstance(final ThemedReactContext reactContext) {
this.reactContext=reactContext;
webView = new BridgeWebView(reactContext);
//注册登录事件registerHandler
webView.registerHandler("callNativePage", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
}
});
return webView;
}
3:设置webview属性接口
@ReactProp(name = "url")
public void setUrl(final BridgeWebView webView,String url) {//这里setText应该高亮
webView.loadUrl(url);
}
4:设置webview给rn的回调方法
我这里设置的是login方法 点击h5页面判断是否登录 如果没有登录跳转到登录页面
实现方法:
1:注册事件给rn调用
@javax.annotation.Nullable
@Override
public Map getExportedCustomDirectEventTypeConstants() {
//第一个Login 注册的名字 第二个registrationName不可以改变 第三个js回调方法
return MapBuilder.of("Login",MapBuilder.of("registrationName","onLogin"));
}
2:点击H5发送事件,改变registerHander方法
webView.registerHandler("callNativePage", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
Log.i(TAG, "js调用原生 " + data);
if(WebViewManager.this.token!=null){
Log.i(TAG, "token 不为空 " + data);
function.onCallBack("回传给js的数据: "+WebViewManager.this.token);
Toast.makeText(reactContext,"token 不为空 " + data,Toast.LENGTH_LONG).show();
}else{
Log.i(TAG, "到登陆页面 " + data);
WritableMap params = Arguments.createMap();
params.putString("from","native");
WebViewManager.this.dispatchEvent(reactContext,"Login",params);//发送事件给RN
}
}
});
private void dispatchEvent(ReactContext reactContext,
String eventName,
@Nullable WritableMap params) {
if (reactContext==null) {
Log.i(TAG, "reactContext==null");
}else{
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
this.webView.getId(),//实例的ID native和js两个视图会依据getId()而关联在一起
eventName,//事件名称
params
);
//原生模块发送事件
// reactContext
// .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
// .emit(eventName, params);
}
}
3:在application里面注册
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
List<ViewManager> modules = new ArrayList<>();
modules.add(new WebViewManager());
return modules;
}
三:rn调用封装的webview
1:引入
var WebViewNative = requireNativeComponent('WebViewManager', H5WebView);
封装好的组件
2:
render() {
return (<View style={{flex:1}}>
<TouchableOpacity activeOpacity={0.8} onPress={this.start}>
<View style={{width:WIDTH,height:50, justifyContent:'center', alignItems:'center'}}>
<Text>主动去掉用H5</Text>
</View>
</TouchableOpacity>
<WebViewNative
ref={(c) => {this.WebViewNative = c;}}
style={{flex:1}}
url="xxx"
token = {this.state.AndroidToken}
onLogin = {this.toLogin}
postMsg={this.state.msg}/>
</View>)
}
WebViewNative.propTypes = {
...View.propTypes,
url: PropTypes.string,
token:PropTypes.string,
onLogin:PropTypes.func,//封装的事件回调
};
tip:
1:再给原生传递属性时只有属性值变化才会从新绘制原生界面,如果只是在rn setState而没有引起属性值变化时是不会调用原生属性方法的。
2:设置原生事件给rn调用时getId 为组件的ID 。
代码比较简单参考:https://github.com/wuyunqiang/RNApp