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”的字
這樣就完成了。就是配置配置加配置,最主要是細心啊,期間也碰到毫無頭緒莫名其妙的問題,實在沒有辦法可以重新啟動一下環境試試,我有一次就重啟完成的