Cordova + Ionic + React Native
let source;
if (__DEV__) {
source = require(`./www/index.html`);
} else {
source = Platform.OS === 'ios' ? require(`./www/index.html`) : { uri: `file:///android_asset/www/index.html#${baseUrl}` };
}
WebView 的生命周期:
onNavigationStateChange={this.onNavigationStateChange}
onMessage={this.handleMessage}
onLoad={this.onWebviewLoad}
onLoadStart={this.onWebviewLoadStart}
跨域问题:
WebView复制:
rm -rf ios/assets/src/components/ui/www
mkdir -p ios/assets/src/components/ui/www
cp -a src/components/ui/www ios/assets/src/components/ui/
WebView <-> React Native <-> Native
RN: injectJavaScript/PostMessage WebView: PostMessage Native: RCTBridge RN:
原始的 Cordova Native 和 WebView 的通访方式
let js = 'var event = new CustomEvent("' + action + '", {detail: ' + JSON.stringify(detail) + '});';
js += 'window.document.dispatchEvent(event);';
webView.injectJavaScript(js);
dispatch_async(dispatch_get_main_queue(), ^{
[self sendEventWithName:@"NATIVE_INVOKE" body: @{@"injectedJS": javascript}];
});
private void executeJS(String injectedJS) {
WritableMap params = Arguments.createMap();
params.putString("injectedJS", injectedJS);
sendEvent(Zhaohu.getInstance().getReactContext(), NATIVE_INVOKE, params);
}
最麻烦的部分是 Cordova 插件
原始代码:
$rootScope.$on('RNBridge.datePicker', function(event, data) {
});
RNBridgeHelper.datePicker(options);
插件桥
function datePicker(options) {
function handler(event) {
event.target.removeEventListener('message', handler);
var data = JSON.parse(event.data);
$rootScope.$broadcast('RNBridge.datePicker', data);
}
window.document.addEventListener('message', handler);
window.postMessage(JSON.stringify({
action: action,
payload: payload
}));
}
WebView
<WebView
source={source}
...
onMessage={this.handleMessage}
/>
WebViewHandler.handleWebViewMessage = (evt, webView) => {
const event = JSON.parse(evt.nativeEvent.data);
const action = event.action;
const payload = event.payload
...
switch (action) {
case 'DATE_PICKER': {
return DatePickerHandler.showDatePicker(payload, webView);
}
}
...
}
DatePickerHandler.showDatePicker = (payload, webView) => {
const showPicker = async (options, webView) => {
try {
const { action, year, month, day } = await DatePickerAndroid.open(options);
if (action === DatePickerAndroid.dismissedAction) {
webView.postMessage(JSON.stringify({
type: 'DATE_PICKER',
success: false,
}));
}
} catch ({ code, message }) {
console.warn('Cannot open date picker', message);
}
};
showPicker({
date: new Date(payload.date),
maxDate: new Date(payload.maxDate),
}, webView);
};
第三方封装的 TabBar 都会绑定 View,所以只能自己去实现
<View style={{flex: isLoadingVisible ? 0 : 1, paddingBottom: 49}}>
<WebView
...
/>
</View>
<View>
<TabBar>
<TabBar.Item
...
onPress={() => {
}}
title='首页'>
</TabBar.Item>
</TabBar>
</View>
window.postMessage(JSON.stringify({
action: 'RN_BACK'
}));
RNBackHandler.handleRNBack = () => {
Actions.pop();
};
WebView 打开 RN
let js = 'var event = new CustomEvent("' + action + '", {detail: ' + JSON.stringify(detail) + '});';
js += 'window.document.dispatchEvent(event);';
webView.injectJavaScript(js);