React Native + Cordova WebView 演進:Plugin 篇

JulGavin 8年前發布 | 22K 次閱讀 Cordova ReactNative 移動開發 React Native

最近,項目上正在打算使用 React Native 來重寫/重構/演講原來的應用。由于早先使用 Cordova + Ionic 的時候,項目的業務代碼很長一段時間里,主要是由我一個編寫的。與此同時,也不會分配充足的人力,用于重寫現有的業務邏輯。

因此,作為一個咨詢師,我提供了幾個不同的重構方案,并建議客戶使用 React Native + WebView 的形式來進行演進。即在 React Native 里使用 WebView 來嵌入原有的業務邏輯,新的業務邏輯則采用 React Native 進行。考慮到未來的一段時間內, 業務代碼將會繼續采用 WebView 編寫,而技術代碼則用 React Native 編寫,這是比較理想的方案。

而作為演進的其中一個難點是:重寫原有的 Cordova 插件。我們使用到了數量眾多的 Cordova 插件,如 Toast、日期控件等等。這個時候,就需要借助于 React Native WebView 的通信來做這件事。

React Native WebView 通信

早期的 React Native WebView 并不能直接與 WebView 通信,而自 React Native 0.37 版本后,則提供了:

  • onMessage
  • postMessage

兩個方法來與 WebView 進行交互,如下是一個簡單的 DEMO:

...

class xxWebView extends React.Component {
    webview: WebView
    handleMessage = (evt: any) => {
    // doSomething()
    }
    render() {
        return (
            <WebView
                ref={webview => this.webview = webview}
                onMessage={this.handleMessage}
            />
        )
    }
}

在我們的 WebView 里,只需要執行下:

window.postMessage({ plugin: 'TOAST' })

就可以向插件發送信息。因此,對于完成我們的插件來說,只需要做到下面的步驟:

  • 當需要調用原生插件的時候,在 WebView 里調用 window.postMessage 來傳遞,相應的 插件名 + 插件的參數
  • React Native 通過 onMessage 來處理對應的類型,并調用對應的插件
  • 當需要返回結果時,通過 webview.postMessage 來傳遞參數,并帶上相應的 插件名 + 返回結果
  • 在 WebView 端 ,如果想獲取返回的結果,則需要 window.document.addEventListener 來監聽 message 事件
  • 最后,再根據返回的值來做相應的處理。

接著,讓我們來看一個簡單的日期控件的 DEMO。

Cordova WebView 調用 React Native 日期控件

WebView

重寫這段邏輯前,先讓我們來看看原有的邏輯代碼:

function onSuccess(date) {
// 更新時間
}

datePicker.show(options, onSuccess, null);

我們通過 options 來傳遞參數,而 onSuccess 則是成功的回調。不過,由于已經沒有 Cordova 的機制,這里的 success 和 error 的回調就沒有啥用了。

因此,在 WebView 上這段邏輯就變成了:

$rootScope.$on('Bridge.datePicker', function(event, data) {
// 更新時間
});

BridgeHelper.datePicker(options);

//BridgeHelper.js 中的相關代碼

window.postMessage(JSON.stringify({
  command: 'DATE_PICKER',
  payload: options
}));

同時,我們有一個全局的監聽函數,在這里面判斷是否有對應的 command 類型。如果是我們需要的 DATE_PICKER,并且是成功地修改值,便會發出這樣的一個廣播,上面的代碼就可以成功地更新時間。

window.document.addEventListener('message', function (e) {
  var data = JSON.parse(e.data);
  if(data.command  && data.command === 'DATE_PICKER' && data.success) {
    $rootScope.$broadcast('Bridge.datePicker', data)
  }
});

這個原理與之前提到的 Ionic 與 Cordova 插件編寫:基于事件與廣播的機制 是相似的,通過全局事件來控制邏輯。

React Native

在 React Native 端,則也是對相應的 handleMessage 進行處理,然后調用相應的組件來處理,如下是調用系統的控件:

DatePickerHandler.showDatePicker = (payload, webView) => {
  const showPicker = async (options, webView) => {
    try {
      const { command, year, month, day } = await DatePickerAndroid.open(options);
      if (command === DatePickerAndroid.dismissedcommand) {
    //
      } else {
        const date = new Date(year, month, day);
        webView.postMessage(JSON.stringify({
          command: 'DATE_PICKER',
          success: true,
          date,
        }));
      }
    } catch ({ code, message }) {
      console.warn('Cannot open date picker', message);
    }
  };

  showPicker(options, webView);
};

通過這樣復雜的工作,我們就可以完成大部分的工作。

 

來自:http://www.phodal.com/blog/react-native-inside-cordova-webview-with-plugin/

 

 本文由用戶 JulGavin 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!