React Native 混合開發與實現

  • 2019 年 10 月 3 日
  • 筆記

關於

前言

隨著 React 的盛行,其移動開發框架 React Native 也收到了廣大開發者的青睞,以下簡稱 RN。通過 RN 我們能夠使用 JavaScript 語言來實現跨平台移動應用的開發,打開了前端工程師通往移動平台的大門。用 RN 官方的介紹來概括它的特點就是:Learn once, write anywhere

如果你了解 React,那麼學習 RN 的話應該會非常輕鬆。因為 RN 和 React 使用了相同的開發語言 JavaScript 和相同的設計理念 React,在 React 的基礎上添加了原生平台的底層支援。這樣,不同平台的適配就交由 RN 去處理,而開發者只需要關注 RN 平台應用開發本身。

本文將從 RN 混合開發(與 iOS、Android 平台交互)的原理和實現進行介紹,結合流程圖的方式讓大家進一步的了解 RN 開發的思想和底層邏輯。

原理與實現

1. 從 Hello world 開始

先來看一個使用 RN 實現的簡單的 Hello world 展示:

上方我們不難看到一些很熟悉的 React 語法,但除此之外我們還能看到其引入了 react-native 庫中的 AppRegistry API 和 Text (文本)組件,這便是 RN 提供給我們用於調用原生平台的 APIs 和 組件,其能夠在不同移動設備上實現一致的功能和邏輯。最後展示在 APP 中的便是 Hello world 文本,而至於 AppRegistry API 後面會做相應介紹。

2. 解刨 React Native 應用的結構

那麼看完 Hello world 示例後,我們應該大致知道了 RN 應用的一個結構,我們用圖例的方式進行解刨說明,如下圖所示:

從圖中可以看到,我們整個的 RN 應用可以分為兩層展示:

  • JavaScript Code 層
  • Native Code 層

也可以理解為所謂的應用層和底層。應用層通過 JavaScript 橋接層 與底層平台進行交互,獲取底層平台的原生 APIs、UI 組件及一些自定義組件等。比如 Hello world 示例中引入的 AppRegistry API 和 Text 組件便是很好的說明。
這樣的分層能夠使應用層的開發變得簡單、高效和跨平台,對於應用的穩定性、運行時的性能來說將和原生平台保持接近。

3. 原生平台調用 React Native 組件

大致了解完 React Native 應用的結構後,我們不妨再來認識下原生平台是如何調用 React Native 組件的。我們 RN 的程式碼要跑在原生 APP 中那必然需要原生 APP 載入運行對應的 RN 組件,以實現混合開發和交互的功能。這裡就要來介紹下剛剛擱置的 AppRegistry API 了。

一般我們的 RN 項目都會有一個入口文件,比如 index.js(老版本會存在兩個:index.ios.js 和 index.android.js)用於註冊根組件並提供給原生平台運行。這裡的註冊根組件就要通過 AppRegistry API 來實現。

我們需要在根組件里調用 AppRegistry 中的 registerComponent 方法進行組件的註冊。註冊完之後原生平台便可以通過 runApplication 方法來運行註冊過的根組件。需要注意的是註冊和運行的組件名稱兩者必須保持一致,這樣才能夠實現載入對應的組件。比如 Hello world 示例中我們註冊的根組件名為 HelloWorldApp,並且注入相應的組件模組。另外同時一個入口文件中,我們也可以註冊多個根組件。

4. 原生載入 React Native 介面

剛剛在介紹原生平台調用 RN 組件時提到了載入對應根組件的功能。那麼是不是原生平台只有通過不斷的調用運行 RN 註冊的根組件才能實現不同頁面的首次載入呢(這裡的載入指原生打開 RN 頁面)?答案是否定的。

除了上述通過調用不同的根組件來實現原生打開不同的 RN 介面外(圖中第二點),我們還可以調用一個根組件來實現。唯一的區別在於我們需要調用時在 initialProperties 中添加區分不同介面的標識位來渲染不同的組件,就好比在 URL 上攜帶不同參數跳轉到同一路由一樣,根據路由上的參數在應用層進行對應組件的渲染。

在 RN 根組件中我們可以通過 this.props 獲取原生平台攜帶過來的參數對象,如示例中的 viewName,再根據 viewName 實現 RN 內部組件的渲染,當然也可以結合 react-navigation 來實現路由模組的切換。至於最終選擇哪種方式載入,決定權還是要看業務的劃分和功能的定義。相比較而言第一種可能更加靈活和便捷。

5. React Native 與原生平台通訊原理

在混合開發模式下,我們不可避免的需要和原生平台進行數據的通訊,那麼在 RN 中,我們如何與原生平台進行通訊呢?如何獲取原生平台提供的數據或將數據傳遞給原生平台呢?下面這張圖便介紹了這一流程。

在 RN 中,我們可以引用 react-native 模組中的 NativeModules API 來進行數據通訊,調用的方法是 NativeModules.模組名稱.介面名稱,而原生平台返回數據到 RN 平台是基於回調,程式碼如下:

import { NativeModules } from 'react-native';  const userInfo = NativeModules.UserInfo; // 獲取自定義用戶資訊模組  console.log(userInfo.userName); // 列印用戶名  const router = NativeModules.Router; // 獲取自定義路由模組  // 調用原生路由跳轉方法  router.openHome('參數', (res) => {      console.log(res); // 列印返回數據  });  

通過 NativeModules 我們可以靈活的獲取或傳遞數據給原生平台,同時我們也可以根據業務需要編寫不同的 Bridge 方法來實現數據通訊模組的封裝,比如用戶資訊模組、路由跳轉模組及網路請求模組等。

6. Redux 架構

在 RN 項目中,除了與原生平台通訊和交互的功能外,RN 平台自身也需要實現一些數據狀態的管理。這裡我們還得認識下 Redux 架構。

 

 

Redux 是一個用於管理 React 應用狀態的容器,在 RN 中也同樣適用。其採用單一數據流的方式來實現數據的管理,唯一改變 state 的方法是提交 action 操作。這樣的架構使得我們的 RN 項目數據易於維護或擴容,改變數據的流程容易追蹤和捕獲。需要了解的具體關鍵字如下:

 

具體文檔可以參考:http://cn.redux.js.org/
當然你也可以使用其他第三方庫實現類似的架構,比如 mobx、dva 等。

7. CSS-in-JS

除了 Redux 架構,RN 中還加入了 CSS in JS 的概念,將原本關注點分離的理念轉移到了關注點混合上,使得我們可以在 JS 中寫 CSS 程式碼,但這並不違背之前關注點分離的理念。

現在隨著組件化概念的流行,對從組件層面維護 CSS 樣式的需求日益增大,CSS-in-JS 就是在組件內部使用 JavaScript 對 CSS 進行了抽象,可以對其聲明和加以維護。這樣不僅降低了編寫 CSS 樣式帶來的風險,也讓開發變得更加輕鬆。它和 CSS Modules 的區別是不再需要 CSS 樣式文件。

結合 JSX 語法,在 RN 中書寫和維護 CSS 變得更加便捷,也是 Web 組件化不斷發展的必然產物。

8. React Native 中 的 Flex 布局

另外,在開發 RN 項目時,官方推薦使用的布局方式是 Flex 布局,因為 Flexbox 可以在不同螢幕尺寸上提供一致的布局結構,這也解決了跨平檯布局呈現的問題。

相比我們客戶端使用的 Flex 布局,RN 中的 Flex 布局有稍許的不同,比如 flexDirection 的默認值是 column 而不是 row,flex 也只能指定一個數字值等。關於 Flex 布局的介紹可以參考:Flex 布局教程:語法篇Flex 布局教程:實例篇

9. React Native 的熱部署

最後我們介紹下 RN 中的熱部署,這也是選擇 RN 開發 APP 的一個重要原因之一。相比傳統 APP 更新,大都需要第三方審核的流程,而這個流程可能會很慢或者不及時,遇到需要緊急修復的 bug 無法及時更新而導致直接的經濟損失是很常見的問題,而 RN 的熱部署可以一定程度上解決或減輕這一問題的影響。那麼其實現原理是怎樣的呢?

上圖左側部分便展現了用戶訪問 RN 應用的熱部署流程。首先用戶訪問 APP,APP 會向 RN 伺服器請求資源包,如果資源包未更新則讀取本地快取資源,如果開發者為了解決 bug 重新更新了伺服器上的資源包,那麼 APP 拉去後會快取起來,待用戶下次進入後再進行更新。這便是 RN 熱部署的流程。

在本地開發時,我們不難發現當我們在運行起來的 RN 項目中修改程式碼時,再次從 APP 進入 RN 頁面,本地終端會再次載入一次更新後的資源數據,這也是 RN 熱部署的體現。

同樣線上的熱部署則需要將我們打包後的 RN 資源上傳到伺服器上供 APP 讀取來實現。

我們可以手動執行打包、上傳發布流程,當然為了減少人為干預,實現前端自動化,我們也可以把這塊流程交給構建平台去自動打包部署,這便需要搭建一個後台系統進行管理。

結語

本文介紹了 React Native 混合開發的原理與實現邏輯。只有先了解原理,才能高效的投入項目的開發中,而關於 RN 自身的功能實現大家可以直接閱讀官方文檔,這裡我也額外提供一些關於 RN 的參考資料:

註:本文部分圖例參考自《React Native 移動開發實戰》一書