此文是我的出版書籍《React Native 精解與實戰》連載分享,此書由機械工業出版社出版,書中詳解了 React Native 框架底層原理、React Native 組件布局、組件與 API 的介紹與代碼實戰,以及 React Native 與 iOS、Android 平台的混合開發底層原理講解與代碼實戰演示,精選了大量實例代碼,方便讀者快速學習。
書籍配套視頻教程「80 節實戰課精通 React Native 開發」:此視頻課程建議配合書籍學習,書籍中原理性的東西講解的比較清晰,而視頻教程對於組件、API 等部分的代碼實戰開發講解比較直觀。
書籍所有相關資料請訪問:http://rn.parryqiu.com
本章繼續介紹 Android 平台下的混合開發原理以及實戰,同時我們還可以深入理解React Native 與 Android 平台的通信機制。
12.1 Android 平台混合開發簡介
與 iOS 平台的混合開發一樣,有時我們遇到 React Native 框架沒有提供的原生 Android 平台 API 時,我們就需要自己來進行 React Native 平台與 Android 平台的混合開發。
同樣,混合開發還可以利用起來現有的 Android 原生平台的代碼,並可以用於開發一些高性能、多線程的需求場景。
React Native 框架的設計同樣為 Android 原生平台提供了混合開發的可能性,這部分依然屬於 React Native 開發高階的部分,在開發前需要掌握了 Android 原生平台的開發語言及開發流程,不過不了解的話也可以學習一下,了解 React Native 平台與 Android 平台的通信原理。
學習的方法我們還是在原理講解的時候結合一個實際的小實例結合代碼進行講解,而不是僅僅空洞地講解概念性的東西,便於大家理解。最后我們還將完成一個更加貼近實際的小實例,來加深 React Native 框架與 Android 平台混合開發的理解與運用。
12.2 Android 平台混合開發原理詳解
我們按照學習 iOS 平台混合開發的模式,這里我們繼續結合一個小的實例來學習 React Native 平台與 Android 平台混合開發的原理與方法。
Android 平台的混合開發主要包含如下幾個主要步驟:
- 在 Android 項目中通過原生代碼實現提供給 React Native 調用的原生功能;
- 在 Android 項目中將編寫好的功能模塊進行注冊;
- 定義功能模塊的 Android 包;
- 在 React Native 項目中通過 JavaScript 代碼調用混合開發實現的 Android 平台原生功能。
完整代碼在本書配套源碼的 12-02 文件夾。
12.2.1 Android 原生代碼實現
先通過 React Native CLI 初始化一個空項目,項目名稱為 NativeAndroidModule,項目初始化的流程如圖 12-1 所示。

圖 12-1 Android 混合開發項目初始化
使用 Android 平台的開發工具 Android Studio 打開項目文件夾中的 android 文件夾,在 Android Studio 中選擇導入此文件夾即可,如圖 12-2 所示。

圖 12-2 Android Studio 導入項目
注意,如果你是第一次打開此項目文件夾,Android Studio 會自動下載 Gradle 並使用 Gradle 進行項目的構建,此過程要確保你的網絡環境沒有任何阻礙並需要耐心等待加載完畢,加載過程如圖 12-3 所示。

圖 12-3 Gradle 初始化並進行項目的構建
項目使用 Android Studio 導入后打開如圖 12-4 所示。

圖 12-4 Android Studio 打開項目后的項目結構
新建的 Android 原生平台的類需要繼承於React Native 框架提供的父類 ReactContextBaseJavaModule,這里我們新建的類命名為 MyModule。
如果沒有導入 ReactContextBaseJavaModule 的包,Android Studio 會提示你進行包的引入,如圖 12-5 所示。

圖 12-5 Android Studio 提示導入缺失的包
新建后的文件代碼如下所示。
1. import com.facebook.react.bridge.ReactContextBaseJavaModule;
2.
3. public class MyModule extends ReactContextBaseJavaModule {
4.
5. }
在繼承了 ReactContextBaseJavaModule 父類后,需要實現方法 getName 返回模塊名稱,並在添加了類的構造函數,以及實現了調用 Android 原生 API 保持屏幕常亮並關閉常亮的兩個方法 keepScreenAwake 和 removeScreenAwake。完整的 MyModule.java 代碼如下。
1. package com.nativeandroidmodule;
2.
3. import com.facebook.react.bridge.ReactApplicationContext;
4. import com.facebook.react.bridge.ReactContextBaseJavaModule;
5. import com.facebook.react.bridge.ReactMethod;
6.
7. public class MyModule extends ReactContextBaseJavaModule {
8.
9. ReactApplicationContext reactContext;
10.
11. public MyModule(ReactApplicationContext reactContext) {
12. super(reactContext);
13. this.reactContext = reactContext;
14. }
15.
16. @Override
17. public String getName() {
18. return "MyModule";
19. }
20.
21. @ReactMethod
22. public void keepScreenAwake() {
23. getCurrentActivity().runOnUiThread(new Runnable() {
24. @Override
25. public void run() {
26. getCurrentActivity().getWindow().addFlags(
27. android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
28. }
29. });
30. }
31.
32. @ReactMethod
33. public void removeScreenAwake() {
34. getCurrentActivity().runOnUiThread(new Runnable() {
35. @Override
36. public void run() {
37. getCurrentActivity().getWindow().clearFlags(
38. android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
39. }
40. });
41. }
42. }
同樣,其他的 Android 平台的原生方法都可以按照此形式進行添加,添加后即可在 React Native 的 JavaScript 代碼中調用。
12.2.2 Android 原生模塊注冊
接下來我們需要創建一個類來實現 ReactPackage 的接口函數,實現原生模塊的注冊,這里我們命名此文件名為 MyModulePackage.java,並實現接口中的 createNativeModules 與createViewManagers 兩個方法。這里我們使用函數 createNativeModules 來進行模塊的注冊,另一個函數 createViewManagers 進行空值返回即可。
最終的完整代碼如下,注意代碼第 19 行的定義。
1. package com.nativeandroidmodule;
2.
3. import com.facebook.react.ReactPackage;
4. import com.facebook.react.bridge.NativeModule;
5. import com.facebook.react.bridge.ReactApplicationContext;
6. import com.facebook.react.uimanager.ViewManager;
7.
8. import java.util.ArrayList;
9. import java.util.Collections;
10. import java.util.List;
11.
12. public class MyModulePackage implements ReactPackage {
13. @Override
14. public List<NativeModule> createNativeModules(
15. ReactApplicationContext reactContext) {
16. List<NativeModule> modules = new ArrayList<>();
17.
18. modules.add(new
19. MyModule(reactContext));
20.
21. return modules;
22. }
23.
24. @Override
25. public List<ViewManager> createViewManagers(ReactApplicationContext
26. reactContext) {
27. return Collections.emptyList();
28. }
29. }
12.2.3 Android 包定義
在項目中的 MainApplication.java 文件中,需要包含上我們自己開發的原生包,添加在 getPackages 函數中即可。
1. package com.nativeandroidmodule;
2.
3. import android.app.Application;
4.
5. import com.facebook.react.ReactApplication;
6. import com.facebook.react.ReactNativeHost;
7. import com.facebook.react.ReactPackage;
8. import com.facebook.react.shell.MainReactPackage;
9. import com.facebook.soloader.SoLoader;
10.
11. import java.util.Arrays;
12. import java.util.List;
13.
14. public class MainApplication extends Application implements ReactApplication {
15.
16. private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
17. @Override
18. public boolean getUseDeveloperSupport() {
19. return BuildConfig.DEBUG;
20. }
21.
22. @Override
23. protected List<ReactPackage> getPackages() {
24. return Arrays.<ReactPackage>asList(
25. new MainReactPackage(),
26. //包含上我們自定義的原生組件包
27. new MyModulePackage()
28. );
29. }
30.
31. @Override
32. protected String getJSMainModuleName() {
33. return "index";
34. }
35. };
36.
37. @Override
38. public ReactNativeHost getReactNativeHost() {
39. return mReactNativeHost;
40. }
41.
42. @Override
43. public void onCreate() {
44. super.onCreate();
45. SoLoader.init(this, /* native exopackage */ false);
46. }
47. }
包含的方式在代碼的第 27 行,Android 原生端開發完畢后的文件結構如圖 12-6 所示。

圖 12-6 Android 端開發完畢文件結構
