1. 程式人生 > >React-Native開發二 Android 已有專案整合React-Native

React-Native開發二 Android 已有專案整合React-Native

1 前言

之前寫過一篇RN的環境搭建教程和新建一個新的RN專案的文章
https://blog.csdn.net/qiyei2009/article/details/78820207
但是其實在實際開發中,在已有的android專案中整合RN情況更普遍,這篇文章就是一個怎麼在已有Android專案中引入RN的例子

2 整合步驟

首先搭建好Android開發環境,並有一個新建的或者已經存在的Android專案
在未建立ReactNative專案大概是這個樣子
這裡寫圖片描述
接著建立ReactNative Module用於存放我們RN相關的內容,極大程度的與原生開發解耦

1 在應用中新增js程式碼


在專案根目錄輸入以下命令

npm init

這裡寫圖片描述
在這中間要求輸入包名,其他的預設即可
這一步完成之後,在專案的根目錄下就會生成package.json這個檔案
接下來還需要把啟動指令碼放進去:

"start": "node node_modules/react-native/local-cli/cli.js start"

注意下啟動指令碼的路徑,如果整合的專案目錄結構不一樣的話會報找不到啟動指令碼之類的錯誤,到時根據具體目錄結構修改就好了。

2 安裝React 和React Native
根目錄輸入以下命令

npm install --save react react-native

這裡寫圖片描述
大約一兩分鐘的樣子(如果卡到這裡了,看看安裝時是不是忘了配置映象),完成之後你的根目錄下會多了一個node_modules的資料夾,裡面存放了下載好的React 和React Native。

要是控制檯輸出了版本不一致的警告資訊,例如:

npm WARN [email protected]0.45.1 requires a peer of [email protected]16.3.1 but none was installed.

則繼續執行 npm i -S [email protected] (這裡版本跟警告資訊一致)。
這裡寫圖片描述

3 下載.flowconfig檔案(非必須)

curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig

第三步curl命令,其實質是下載.flowconfig配置檔案,這個檔案用於約束js程式碼的寫法。非必需,可
這裡寫圖片描述

4 新建index.android.js
專案根目錄下建立index.android.js檔案,目錄內容如下:

'use strict';
import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';
class EssayJokeReactNativeDemo extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.hello}>Hello, EssayJoke React-NativeDemo</Text>
      </View>
    )
  }
}
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});
AppRegistry.registerComponent('EssayJokeReactNativeDemo', () => EssayJokeReactNativeDemo);

到這裡js部分的都弄的差不多了,現在來看整個專案的目錄結構如下:
這裡寫圖片描述
這裡寫圖片描述
之前將CordovaDemo改成了Cordova,其他的沒有變
ReactNative Module就是我們ReactNative相關開發的內容都放在該module下

5 ReactNative Module引入依賴RN依賴
在build.gradle引入以下依賴

def com_facebook_react_react_native = "com.facebook.react:react-native:+"
api com_facebook_react_react_native // From node_modules.

在專案根目錄build.gradle新增依賴倉庫地址

allprojects {
    repositories {
        …
        maven {
            // All of React Native (JS, Android binaries) is installed from npm
            url "$rootDir/node_modules/react-native/android"
        }
    }
}

這裡maven路徑官網上寫的是 r o o t D i r / . . / n o d e m o d u l e s / r e a c t n a t i v e / a n d r o i d rootDir後面的..的,它指的路徑就是專案根目錄下的node_modules下的路徑

6 新建Activity作為原生與RN的跳轉
在較老的RN版本中,我們新建一個Activity實現DefaultHardwareBackBtnHandler介面,大體類似下面

public class MyReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {

    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();

        // 注意這裡的HelloWorld必須對應“index.android.js”中的
        // “AppRegistry.registerComponent()”的第一個引數
        mReactRootView.startReactApplication(mReactInstanceManager, "test", null);

        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostPause(this);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostResume(this, this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

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

較新的RN版本,例如RN0.55 我們直接繼承ReactActivity即可

/**
 * @author Created by qiyei2015 on 2018/6/8.
 * @version: 1.0
 * @email: [email protected]
 * @description:
 */
public class ReactNativeDemoActivity extends ReactActivity{

    private static final String MAIN_COMPONENT = "EssayJokeReactNativeDemo";


    /**
     * 返回在index.android.js 中註冊的元件名
     * @return
     */
    @Nullable
    @Override
    protected String getMainComponentName() {
        return MAIN_COMPONENT;
    }

}

新建一個Activity,讓其繼承ReactActivity,並重寫getMainComponentName(),返回我們在index.android.js
中註冊的HelloWorld這個元件。

在Application中初始化一下

/**
 * Email: [email protected]
 * Created by qiyei2015 on 2017/5/8.
 * Version: 1.0
 * Description:
 */
public class BaseApplication extends Application implements ReactApplication{
    private static final String TAG = " Sophix";

    /**
     * ReactNative的host
     */
    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
            return Arrays.<ReactPackage>asList(
                    new MainReactPackage()
            );
        }
    };


    @Override
    public void onCreate() {
        super.onCreate();
        ....
    }

    /**
     * ReactNative的host
     * @return
     */
    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    ....
}

在manifest.xml配置如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.qiyei.reactnative">

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

</manifest>

由於需要訪問 DevSettingsActivity 介面,也需要在 AndroidManifest.xml 中宣告

7 同步編譯
該步驟可能會遇到以Warning:Conflict with dependency ‘com.google.code.findbugs:jsr305’. Resolved versions for app (3.0.0) and test app (2.0.1) differ. See http://g.co/androidstudio/app-test-app-conflict for details.ild.bundle裡面加入:

allprojects {
    ...
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
    }
}

8 在ReactNative Module新建assets目錄
主要用於儲存一些bundle檔案

3 執行專案

有了以上準備,我們就直接來執行專案吧
1 啟動server
在根目錄下輸入以下命令

npm start

或者

react-native start

都可以啟動後臺服務
這裡寫圖片描述

如果卡在了以上介面,直接在根目錄下執行以下命令

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

注意,需要將index.android.bundle生成的目錄指定對
這裡寫圖片描述
完成之後assets目錄下會生成以下兩個檔案
這裡寫圖片描述
2 監測server是否可以訪問
在電腦的瀏覽器中訪問以下地址,如果可以訪問,一般來說server就啟動成功了

http://localhost:8081/index.android.bundle?platform=android

3 執行APP
點選跳轉到RN介面,執行效果如下:
這裡寫圖片描述
注意,執行過程中可能會有一些不順利的地方,可以搜尋網路上的答案解決

原始碼參考 https://github.com/qiyei2015/EssayJoke 中ReactNative部分