最新版React Native環境搭建

語言: CN / TW / HK

工欲善其事,必先利其器。搭建React Native開發環境,需要安裝以下輔助工具。 - Node.js:React Native需要藉助Node.js來建立和執行JavaScript程式碼。 - 原生開發工具及環境:React Native的執行需要依賴原生Android和iOS環境,因此需要分別安裝原生Android和iOS的開發環境。 - 其他開發工具:程式碼編輯器Visual Studio Code或WebStorm,遠端除錯具Chrome瀏覽器等。

一、基礎環境

1.1 安裝Node.js

首先,我們需要安裝Homebrew,Homebrew是一款Mac OS平臺下的軟體包管理工具,擁有安裝、解除安裝、更新、檢視、搜尋等很多實用的功能,Homebrew的安裝命令如下:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

安裝完Homebrew之後,接下來就是安裝Node 、Watchman和 Yarn等必須的工具。

``` brew install node brew install watchman

使用nrm工具切換淘寶源

npx nrm use taobao

npm install -g yarn ```

需要注意的是,如果還在使用舊版本React Native工具(0.60.0版本以下),為了避免衝突,請使用下面的命令先解除安裝。 npm uninstall -g react-native-cli

1.2 新增Android原生環境

由於React Native專案的編譯執行需要依賴原生平臺,所以在搭建React Native開發環境過程中,需要事先搭建好原生Android和iOS的開發環境。

在搭建原生Android開發環境過程中,由於Android專案的開發和執行需要依賴Java環境,如果還沒有安裝Java環境,可以從JDK官網下載作業系統對應的JDK版本然後進行安裝。安裝成功之後,可以使用java -version命令來驗證Java開發環境,如下圖所示。

image.png

同時,為了方便後面專案中使用Java的命令列,還需要在.bash_profile檔案中配置環境變數,如下所示。

```

如果你不是通過Android Studio安裝的sdk,則其路徑可能不同,請自行確定清楚

export ANDROID_HOME=/Users/XXX/Library/Android/sdk export PATH=${PATH}:${ANDROID_HOME}/tools export PATH=${PATH}:${ANDROID_HOME}/platform-tools export PATH=${PATH}:${ANDROID_HOME}/emulator export PATH=${PATH}:${ANDROID_HOME}/tools/bin ```

如果配置檔案使用的是~/.zshrc,那麼可以使用下面的命令使上面的配置生效。

source ~/.zshrc

接下來,我們還需要安裝Android開發工具Android Studio和Android開發套件Android SDK Tools。

首先,從Android官網下載最新的Android Studio,安裝完成之後,第一次啟動會自動下載Android SDK,下載Android SDK需要在Android Studio的設定板中配置Android SDK Tools的路徑。

image.png

同樣,為了方便在專案中使用Android命令列工具,還需要配置一下Android系統環境變數。

export ANDROID_HOME="/Users/xxx/Android/sdk" export PATH=${PATH}:${ANDROID_HOME}/tools export PATH=${PATH}:${ANDROID_HOME}/platform-tools

1.3 新增iOS原生環境

眾所周知,開發iOS應用需要macOS作業系統支援,所以如果經濟條件允許最好準備一臺Mac電腦。也只有這樣,才能使用React Native開發可以同時執行在iOS和Android裝置上的跨平臺應用,發揮React Native跨平臺應用開發的優勢。

由於使用React Native開發iOS端的應用時需要Xcode 7及更高版本的支援,如果本地還沒有安裝Xcode應用程式,可以從App Store上下載最新的Xcode進行安裝,

image.png

需要說明的是,Xcode安裝程式必須通過Apple官網或者App Store進行下載,否則容易出現程式碼植入和程式碼洩漏的風險。比如,2015年9月發生的XcodeGhost非法程式碼植入事件,就是因為開發者使用的是非官方的Xcode安裝程式引起的。

同時,React Native專案的原生iOS部分使用的是CocoaPods來管理第三方依賴庫,所以在搭建iOS開發環境時還需要安裝CocoaPods庫管理工具。如果還沒有安裝CocoaPods,可以使用下面的命令進行安裝。

brew install cocoapods

由於React Native專案的執行需要依賴ruby的2.7.5版本,所以請確保本地已經安裝了ruby依賴。如果本地安裝了多個ruby版本,那麼可以使用下面的命令進行切換。

rvm use ruby-2.7.5 --default

二、建立示例專案

2.1 建立專案

React Native支援使用命令和IDE整合開發工具兩種方式來建立專案。其中,使用命令列方式初始化React Native專案如下所示。

npx react-native init RNDemos

需要注意的是,初始化React Native專案時,專案名稱不能包含中文、空格和特殊符號,也不能使用JavaScript關鍵字作為專案名,如 class、native、new等。 同時,React Native在初始化專案時還支援指定版本和專案模板,如下所示。

//指定版本 npx react-native init AwesomeProject --version 0.66.0 //指定模版 npx react-native init AwesomeTSProject --template react-native-template-typescript

當然,除了命令列方式外,我們更推薦使用VSCode或WebStrom等視覺化編輯工具來建立React Native專案。

等待React Native專案構建成功之後,系統還會自動安裝專案所需的第三方依賴庫。接著,再使用VSCode或WebStrom開啟React Native專案,如下圖所示。

image.png

2.2 執行專案

執行React Native專案之前,需要配置好原生開發環境。即執行iOS 需要正確安裝和配置Xcode工具,執行Android App需要正確安裝和配置Android Studio和Android SDK Tools。 同時,為了能夠正常的執行專案,還需要在專案執行之前啟動模擬器或者真機裝置。啟動模擬器或真機後,我們可以使用如下的命令來檢視連線情況。

xcrun simctl list devices //檢視可用的iOS裝置 adb devices //檢視可用的Android裝置

然後,在專案的根目錄執行執行如下命令即可啟動React Native專案。

//啟動iOS yarn ios或者yarn react-native run-ios //啟動Android yarn android或者yarn react-native run- android

此命令會對專案的原生部分進行編譯,同時在後臺啟動Metro服務對 JavaScript程式碼進行實時打包處理。當然,Metro服務也可以使用yarn start命令單獨啟動。如果此命令無法正常執行,可以使用Android Studio或者Xcode開啟對應的原生工程來檢視報錯資訊。如果沒有任何錯誤提示,那麼執行效果如下圖所示。

image.png

2.3 除錯專案

除錯是軟體開發過程中重要的步驟,也是保證軟體質量的重要手段。應用除錯不僅可以幫助開發者快讀的定位軟體中存在的問題,同時也是初學者快速理解軟體功能的重要途徑。

由於React Native專案主要使用React前端語言進行開發,所以除錯React Native需要使用到Chrome的DevTools,而Chrome瀏覽器預設就集成了這一工具。React Native集成了對Chrome的DevTools的支援,開發者可以很容易地使用它除錯React Native應用。

使用真機開發時,除錯應用只需要晃動下裝置即可開啟除錯選項。如果開發使用的是模擬器,那麼可以使用快捷鍵來開啟除錯功能,Android模擬器除錯的快捷鍵是【Command +M】,iOS模擬器的快捷鍵是【Command +D】,如下圖所示。

image.png

需要說明的是,如果是使用真機進行除錯,需要除錯的真機和開發程式的電腦處於同一個Wi-Fi網路,否則將會出現無法連線的情況。 接著,只需要點選螢幕上的【Debug】選項即可開啟遠端除錯功能。開啟遠端除錯時,系統會自動開啟Chrome瀏覽器的除錯介面,如下圖所示。

image.png

然後,依次點選【Chrome選單】→【選擇更多工具】→【選擇開發者工具】,或者使用快捷鍵【Command +Option +I】即可開啟除錯視窗,開始除錯。

image.png 如果大家有前端開發的基礎,那麼React Native開發可以做到快速上手。

三、整合到原生應用

3.1 整合到原生Android應用

首先,在原生Android專案的根目錄下執行yarn init命令建立一個名為package.json的空檔案。然後,根據提示輸入對應的配置資訊。等待命令執行完成之後,會發現原生Android專案的根目錄多了一個package.json檔案,該檔案就是。 接著,使用如下命令新增React和React Native執行環境的支援指令碼。

yarn add react react-native

執行完命令後,會發現Android專案的根目錄下多了一個node_modules資料夾,裡面包含了React Native開發也執行所需的依賴模組,原則上這個檔案目錄是不能複製、移動和修改的。並且,node_modules資料夾中的內容是不需要上傳倉庫的,所以還需要將node_modules檔案目錄記錄到.gitignore檔案中。 接下來,使用文字編輯器開啟package.json檔案,配置React Native的啟動指令碼,如下程式碼。

"scripts": { "start": "yarn react-native start", },

到此,React Native所需的環境就配置完成了。此時,package.json檔案的全部內容如下所示。

{ "name": "AndroidDemo", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "react": "^17.0.1", "react-native": "^0.66.0" }, "scripts": { "start": "yarn react-native start" } }

然後,在Android專案的根目錄下建立一個index.js檔案,用於作為React Native模組的入口,程式碼如下。

``` import React from 'react'; import {AppRegistry, StyleSheet, Text, View} from 'react-native';

class HelloWorld extends React.Component { render() { return ( Hello, React Native ); } }

const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', }, hello: { fontSize: 20, textAlign: 'center', margin: 10, }, });

AppRegistry.registerComponent('MyReactNativeApp', () => HelloWorld); ```

接下來,我們使用Android Studio開啟原生Android專案,並在app目錄的build.gradle檔案的dependencies程式碼塊中新增React Native和JSC引擎依賴,如下所示。

dependencies { ... implementation "com.facebook.react:react-native:+" implementation "org.webkit:android-jsc:+" }

如果不指定依賴的版本,那麼預設使用的是package.json檔案中React Native對應的版本。然後,在專案的build.gradle檔案的allprojects程式碼塊中新增React Native和JSC引擎的路徑,如下所示。

allprojects { repositories { maven { url "$rootDir/../node_modules/react-native/android" } maven { url("$rootDir/../node_modules/jsc-android/dist") } ... } ... }

然後,開啟AndroidManifest.xml清單檔案,新增網路許可權程式碼,如下所示。

<uses-permission android:name="android.permission.INTERNET" />

如果需要訪問開發者除錯選單,還需要在AndroidManifest.xml清單檔案中註冊DevSettingsActivity介面,如下所示。

<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />

接下來,新建一個Activity作為React Native的容器頁面,並在Activity中建立一個ReactRootView物件,然後在這個物件之中啟動React Native應用程式碼,如下所示。

``` public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {

private ReactRootView mReactRootView;

private ReactInstanceManager mReactInstanceManager;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    SoLoader.init(this, false);
    mReactRootView = new ReactRootView(this);
    mReactInstanceManager = ReactInstanceManager.builder()
            .setApplication(getApplication())
            .setCurrentActivity(this)
            .setBundleAssetName("index.android.bundle")
            .setJSMainModulePath("index")
            .addPackage(new MainReactPackage())
            .setUseDeveloperSupport(BuildConfig.DEBUG)
            .setInitialLifecycleState(LifecycleState.RESUMED)
            .build();
    mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null);
    setContentView(mReactRootView);
}

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
        mReactInstanceManager.showDevOptionsDialog();
        return true;
    }
    return super.onKeyUp(keyCode, event);
}

} ```

可以使用Android Studio的【Alt + Enter】快捷鍵自動匯入缺失的語句,並且BuildConfig是編譯時自動生成的,無需額外引入。 由於React Native應用除錯還需要懸浮窗許可權,所以在需要在Android專案的程式碼中新增懸浮窗許可權邏輯,如下所示。

``` private final int OVERLAY_PERMISSION_REQ_CODE = 1;

private void requestPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE); } } }

@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == OVERLAY_PERMISSION_REQ_CODE) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { // SYSTEM_ALERT_WINDOW permission not granted } } } mReactInstanceManager.onActivityResult( this, requestCode, resultCode, data ); } ```

接下來,我們在AndroidManifest.xml清單檔案中註冊MyReactActivity,此處我們直接使用MyReactActivity替換MainActivity作為應用的主頁面,如下所示。

<activity android:name=".MyReactActivity" android:theme="@style/Theme.AppCompat.Light.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>

完成上述操作後,我們在src/main目錄下建立一個assets資原始檔夾,然後執行如下打包命令。

react-native bundle --platform android --entry-file index.js --bundle-output app/src/main/assets/index.android.bundle --dev false

接著,執行yarn start命令啟動React Native所需的服務,然後重新執行原生Android專案即可看到效果,如圖下圖所示。

image.png

3.2 整合到原生iOS應用

在原生iOS專案中整合React Native的步驟和Android是一樣的。首先,需要在原生iOS專案的根目錄下建立一個package.json檔案,然後新增如下指令碼程式碼。

{ "name": "RNiOS", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "react": "^17.0.1", "react-native": "^0.66.0" }, "scripts": { "start": "yarn react-native start" } }

然後,執行yarn install命令安裝React Native需要的依賴包。接著,我們再新建一個index.js檔案作為React Native部分的入口,程式碼如下。

``` import React from 'react'; import {AppRegistry,StyleSheet,Text,View} from 'react-native';

class ReactHost extends React.Component { render() { return ( 2048 High Scores ) } } AppRegistry.registerComponent('MyReactNativeApp', () => ReactHost); ``` 然後,在iOS專案的根目錄下使用pod init命令建立一個Podfile檔案,新增如下依賴包指令碼。

```

target的名字一般與你的專案名字相

pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" pod 'React', :path => '../node_modules/react-native/' pod 'React-Core', :path => '../node_modules/react-native/' pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'

pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon" pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'

pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

end ```

需要說明的是,上面的指令碼是啟動React Native部分所必須的,並且每個版本會有細微的區別。完成上述配置之後,使用pod install命令安裝所需的依賴包。 接著,使用Xcode開啟原生iOS專案,在ViewController.m啟動檔案中新增如下程式碼。

``` - (IBAction)highScoreButtonPressed:(id)sender { NSLog(@"High Score Button Pressed"); NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];

RCTRootView *rootView =
  [[RCTRootView alloc] initWithBundleURL: jsCodeLocation
                              moduleName: @"RNHighScores"
                       initialProperties:
                         @{
                           @"scores" : @[
                             @{
                               @"name" : @"Alex",
                               @"value": @"42"
                              },
                             @{
                               @"name" : @"Joel",
                               @"value": @"10"
                             }
                           ]
                         }
                           launchOptions: nil];
UIViewController *vc = [[UIViewController alloc] init];
vc.view = rootView;
[self presentViewController:vc animated:YES completion:nil];

} ```

當上面的程式碼被執行時,應用會開啟React Native的index.js頁面,並且將從原生iOS部分獲取的資料也顯示到螢幕上。最後,使用yarn start命令啟動Node.js服務,重新執行原生iOS專案即可看到效果,如圖下圖所示。

image.png