1. 程式人生 > >react-native整合到現有原生專案

react-native整合到現有原生專案

必須具備react-native的開發環境
建立結構目錄

建立一個名為rn_test的資料夾(這個資料夾是存放react-native專案的),在rn_test資料夾中建立名為android的資料夾(是存放android專案的)把原生專案複製進去,這裡我建立了一個新的

引入react-native

在rn專案的根目錄建立package.json檔案,拷貝如下內容:

{
  "name": "MyReactNativeApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  }
}

每次init rn專案的時候會引入大量的依賴包,而我們這次整合到現有專案也要引入這些依賴,在rn跟目錄執行如下命令:
yarn add react-native
會出現很多資訊,如下:
整合
要注意其中標黃的警告資訊,是說還要安裝“[email protected]”,這個版本必須要和警告中給出的版本號一致,如下命令:
yarn add [email protected]
這時目錄結構已經有了變化
目錄
其中的node_modules就是剛才所安裝的依賴。

配置rn專案中的android原生專案

新增react-native的依賴
implementation “com.facebook.react:react-native:+” // From node_modules
在android專案的build.gradle中加入maven入口,必須寫在 “allprojects” 程式碼塊中:

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

這個url的路徑是剛才加入的node_modules資料夾中的位置,…/是返回上一層目錄,在找到node_modules,如果結構有變動這裡要記得變。
宣告網路許可權

個人覺得是因為rn專案要連線node服務,所以要宣告
如果要訪問開發者選單也要新增

新增程式碼

在rn專案的根目錄中建立一個index.js檔案新增如下程式碼:

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

class Shy extends React.Component {
  render() {
    return (
      <View>
        <Text >Shy</Text>
      </View>
    );
  }
}

AppRegistry.registerComponent('MyReactNativeApp', () => Shy);

這個index.js檔案就是主入口,我只在裡邊寫了很簡單的東西。
還需要開啟懸浮窗許可權,這個許可權只是在開發的時候react-native出錯時所彈出的錯誤資訊,所以上線後可以關掉,我是直接寫在了MainActivity中了

private final int OVERLAY_PERMISSION_REQ_CODE = 1;  // 任寫一個值

...

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 );
}

這裡的onActivityResult函式中有個mReactInstanceManager,這個mReactInstanceManager會沒有引用,因為只是彈出錯誤資訊不影響實際業務,所以我註釋了,暫時沒有發現什麼關係。

ReactRootView

這個東西官方並沒有給出白話定義,但是從程式碼可以看出,在Activity中建立了這個ReactRootView,又通過startReactApplication找到了“MyReactNativeApp”,而index.js中的AppRegistry.registerComponent(‘MyReactNativeApp’, () => Shy)也註冊了,切註釋說明名字要相同;所以我覺得就是載入了js檢視。

public class MyReactActivity extends Activity 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")
                .setJSMainModulePath("index")
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        // 注意這裡的MyReactNativeApp必須對應“index.js”中的
        // “AppRegistry.registerComponent()”的第一個引數
        mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null);

        setContentView(mReactRootView);
    }

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

這個MyReactActivity官方也是推薦設定樣式的

<activity
  android:name=".MyReactActivity"
  android:label="@string/app_name"
  android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>

生命週期:
這些函式都是和activity對應的,我碰到過提示引數不對的情況,請重新編譯

@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(this);
    }
    if (mReactRootView != null) {
        mReactRootView.unmountReactApplication();
    }
}

後退按鈕

@Override
 public void onBackPressed() {
    if (mReactInstanceManager != null) {
        mReactInstanceManager.onBackPressed();
    } else {
        super.onBackPressed();
    }
}

開發選單(Ctrl + M)

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

再寫一個從MainActivity跳轉到MyReactActivity的意圖,這樣就足以證明專案中既有原生,又存在js。
開啟服務,執行命令:
yarn start
服務
done完成 就可以通過android studio來啟動專案了,我遇到了這樣的錯誤:
dlopen failed: “/data/data/com.example.shy_4.rn_android_test/lib-main/libgnustl_shared.so” is 32-bit instead of 64-bit
解決方法:
在android專案的根目錄的gradle.properties中新增android.useDeprecatedNdk=true,
在app的build.gradle中新增

defaultConfig {
        ...
        ndk {
            abiFilters "armeabi-v7a", "x86"
        }
        packagingOptions {
            exclude "lib/arm64-v8a/librealm-jni.so"
        }
    }

可以了
就是點選textView跳轉到react-native的js頁面顯示一個“Shy”的字
這樣就完成了。就是配置配置加配置,最主要是細心啊,期間也碰到毫無頭緒莫名其妙的問題,實在沒有辦法可以重新啟動一下環境試試,我有一次就重啟完成的