1. 程式人生 > >《React Native 精解與實戰》書籍連載「Android 平臺與 React Native 混合開發」

《React Native 精解與實戰》書籍連載「Android 平臺與 React Native 混合開發」

此文是我的出版書籍《React Native 精解與實戰》連載分享,此書由機械工業出版社出版,書中詳解了 React Native 框架底層原理、React Native 元件佈局、元件與 API 的介紹與程式碼實戰,以及 React Native 與 iOS、Android 平臺的混合開發底層原理講解與程式碼實戰演示,精選了大量例項程式碼,方便讀者快速學習。

書籍配套視訊教程「80 節實戰課精通 React Native 開發」:此視訊課程建議配合書籍學習,書籍中原理性的東西講解的比較清晰,而視訊教程對於元件、API 等部分的程式碼實戰開發講解比較直觀。

本章繼續介紹 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 平臺的混合開發主要包含如下幾個主要步驟: 1) 在 Android 專案中通過原生程式碼實現提供給 React Native 呼叫的原生功能; 2) 在 Android 專案中將編寫好的功能模組進行註冊; 3) 定義功能模組的 Android 包; 4) 在 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 端開發完畢檔案結構