此文是我的出版書籍[《React Native 精解與實戰》](http://rn.parryqiu.com/)連載分享,此書由機械工業出版社出版,書中詳解了 React Native 框架底層原理、React Native 組件佈局、組件與 API 的介紹與代碼實戰,以及 React Native... ...
此文是我的出版書籍《React Native 精解與實戰》連載分享,此書由機械工業出版社出版,書中詳解了 React Native 框架底層原理、React Native 組件佈局、組件與 API 的介紹與代碼實戰,以及 React Native 與 iOS、Android 平臺的混合開發底層原理講解與代碼實戰演示,精選了大量實例代碼,方便讀者快速學習。
書籍還配套了視頻教程「80 節實戰課精通 React Native 開發」,此視頻課程建議配合書籍學習,書籍中原理性的東西講解的比較清晰,而視頻教程對於組件、API 等部分的代碼實戰開發講解比較直觀。
書籍相關所有資料請訪問:http://rn.parryqiu.com
本章將詳細講解在 React Native 框架下,iOS 平臺混合開發的原理以及詳細實現方法,並依然通過案例進行實際應用學習。本章需要具備 iOS 平臺開發語言 Objective-C 或 Swift 以及 iOS 核心類庫的基本知識。
11.1 iOS 平臺混合開發簡介
當我們需要使用一些 iOS 平臺的 API,而 React Native 框架目前還沒有提供對應的 JavaScript API 時,我們就需要自己編寫 React Native 框架與 iOS 平臺結合的混合開發代碼,使得 React Native 框架可以直接與 iOS 平臺的原生代碼進行通信。
混合開發的其他使用場景還包括對一些現有的 Objective-C、Swift 或者 C++ 代碼進行復用,或者編寫一些用於圖片處理、資料庫或一些其他高級特性的高性能或多線程的代碼。React Native 都開放了對應的介面供開發者調用。
接下來在原理講解的章節,我們通過結合一個簡單的實例詳細講解一下 React Native 中與 iOS 平臺混合開發的通信機制,這部分內容稍顯複雜,可能需要反覆閱讀理解其底層原理,並結合小實例進行體會學習,在第二部分還將有一個真實的混合開發示例,繼續加深你對混合開發的理解。
這部分內容屬於 React Native 開發的高階內容,即使不掌握也不影響你在學習了 React Native 基礎知識後進行 App 的開發,不過理解並掌握了這部分的話,更加有助於你理解 React Native 的底層原理與實現。
11.2 iOS 平臺混合開發原理詳解
這一章節,我們通過實現在 React Native 框架中調用我們在 Objective-C 中編寫的原生代碼,Objective-C 中的函數返回了一個簡單的字元串,React Native 框架中通過 JavaScript 代碼將字元串獲取到在 View 中的 Text 組件上顯示。功能雖然簡單,但是我們主要是通過此簡單功能的實現流程,深入學習 React Native 中與 iOS 平臺結合的混合開發原理。
iOS 平臺混合開發實現的過程包括如下幾個過程:
- 在 iOS 平臺的原生代碼中定義混合開發的入口,用於與 React Native 中的 JavaScript 代碼進行通信;
- 設置 iOS 平臺下項目的編譯必備設置;
- 在 React Native 項目中通過 JavaScript 代碼調用混合開發實現的 iOS 平臺原生功能。
完整代碼在本書配套源碼的 11-02 文件夾。
11.2.1 iOS 原生代碼實現
原生模塊使用 Objective-C 的類定義來實現與 React Native 框架通信的協議介面 RCTBridgeModule,註意 RCT 是 ReaCT 取的幾個大寫字母的縮寫。
首先我們通過 React Native CLI 命令初始化一個空的項目,命令執行如圖 11-1 所示。
圖 11-1 初始化一個空項目
使用 Xcode 打開 ios 文件夾下的 xcodeproj 項目文件,後續的混合開發我們將在 Xcode 中進行。
我們將我們混合開發的模塊命名為 MyModule,併在 Xcode 中分別建立兩個對應的文件,一個為頭文件 MyModule.h,另一個為使用 Objective-C 來實現的類 MyModule.m。建立時可以在 Xcode 新建視窗中選擇文件類型,如圖 11-2 所示。
圖 11-2 Xcode 下新建文件選擇類型
頭文件 MyModule.m 文件中初始化的代碼使用如下代碼。
1. #import "RCTBridgeModule.h"
2.
3. @interface MyModule : NSObject <RCTBridgeModule>
4.
5. @end
代碼第一行導入了 React Native 框架與原生代碼通信的協議頭文件 RCTBridgeModule.h。
為了通過類對 RCTBridgeModule.h 的實現,類中還需要包含 RCT_EXPORT_MODULE() 的巨集定義,RCT_EXPORT_MODULE() 中還可以傳入參數,命名自定義原生組件的名稱,如我們之前定義的文件名為 MyModule,這裡可以通過傳遞參數重新定義模塊名稱,RCT_EXPORT_MODULE(RenameMyModule) 這樣就將導出的模塊命名成了 RenameMyModule。如果不傳遞參數,那麼就使用類文件的名稱,即 MyModule.m 的名稱 MyModule。如果模塊類文件包含 RCT 開頭的文件名,那麼最終的模塊名稱將自動不包含 RCT 字元串。
MyModule.m 文件中的代碼實現如下。
1. #import "MyModule.h"
2.
3. @implementation MyModule
4.
5. // 需要包含的巨集定義
6. RCT_EXPORT_MODULE()
7.
8. // 定義了一個返回的字元串
9. - (NSDictionary *)constantsToExport {
10. return @{@"hello": @"你好,這是我編寫的第一個 iOS 原生模塊!"};
11. }
12.
13. // 定義了一個可被調用的函數
14. RCT_EXPORT_METHOD(squareMe:(NSString *)number:(RCTResponseSenderBlock)callback) {
15. int num = [number intValue];
16. callback(@[[NSNull null], [NSNumber numberWithInt:(num*num)]]);
17. }
18.
19. @end
此段代碼定義了一個固定的字元串輸出,方法為 constantsToExport,返回了名稱為 hello 的字元串。第二個定義了一個可以供 React Native 的 JavaScript 代碼調用的函數,函數功能非常簡單,就是將傳遞過來的 int 參數進行平方計算,計算後將計算的值返回。
函數的定義需要使用巨集命令 RCT_EXPORT_METHOD 進行顯式地定義。定義的函數都會被非同步地調用,所以函數的定義不是直接使用 return 返回一個值,和固定的字元串返回不一樣。
squareMe 是定義了此函數的函數名稱,參數為一個 NSString 型的值,名稱為 number,另一個參數為函數的回調函數,用於獲取原生代碼的執行結果。
函數的 callback 第一個參數為錯誤的返回(這裡沒有錯誤就返回了一個 null),第二個為計算後的值,供函數回調使用。
11.2.2 iOS 項目編譯設置
如上代碼都編寫完成後,在 Xcode 中執行項目編譯,點擊 Xcode 中的 Build 命令,如圖 11-3 所示。
圖 11-3 Xcode 項目的編譯
如果在編譯時遇到 fatal error: 'RCTBridgeModule.h' file not found 的錯誤,即 'RCTBridgeModule.h 文件找不到的問題,錯誤如圖 11-4 所示。
圖 11-4 RCTBridgeModule.h 文件找不到的錯誤
解決的方法為在 Xcode 的項目設置“Build Settings”選項卡下找到“Header Search Paths”設置節點,並確認在其中包含瞭如圖 11-5 所示的定義,即添加了 $(SRCROOT)/../node_modules/react-native/React 值的定義併在下拉選項中選擇了“recursive”。
圖 11-5 設置 Xcode 的 Search Paths
進行瞭如上的設置後,再次編譯項目即可解決此錯誤問題。