react-native爬坑(1)————給現有的Android專案整合
公司專案需要頻繁更新,因此考慮使用react-native給現有的Android專案進行功能補充。研究了2天,官網的資料坑太多,網上的部落格也不適用最新的版本,跑不起來,網上翻了n多篇資料,終於能夠執行起來,開心。現在將react-native整合的詳細跳坑步驟寫一下;
(1)前提:需要按照官網的步驟,搭建環境先,還沒搭建好的可以參考中文官網的,這個沒坑:https://reactnative.cn/docs/getting-started/
(2)使用的react-native版本:0.57.5
下面開始給我們的現有Android專案整合react-native
1、用Androidstudio開啟我們的Android專案,開啟下方的 Terminal 命令視窗,預設是我們的工程根目錄;使用yarn init命令建立package.json檔案,需要填寫響應的資訊,這裡我填了name後全部回車跳過,最後生成。
2、接下來需要安裝依賴和 node_modules,還是在根目錄下,輸入yarn add react-native,安裝 React 和 React Native 模組。等待幾分鐘後,可以看到完成的資訊。
往上滾動,看上面的資訊,會有warning提示的一句話:
意思就是react-native0.57.5版本需要依賴react的版本是16.6.1,官網說要保持一致性,既然警告了,就安裝對應的版本唄,接下來執行yarn add
要注意:我現在安裝的版本是0.57.5,如果以後更新了這個版本,對應的react版本應該也會更改,所以要記得要去看warning資訊,檢視對應的react版本。
看一下我們的package.json檔案,出現了剛才我們安裝的版本,如果版本號前有^符號,把它去掉,固定一下版本;
3、在build.gradle新增倉庫:這裡記得不要按官網新增的路徑,有坑。直接複製下面的就行了
allprojects { repositories { maven { url "https://maven.google.com" } jcenter() maven { // All of React Native (JS, Android binaries) is installed from npm url "$rootDir/node_modules/react-native/android" } } }
dependencies {
compile 'com.facebook.react:react-native:+'
}
4、建立js檔案,我直接用了官網的例子,js檔案預設要放在根目錄下,實際開發不同。
import React from "react";
import { AppRegistry, StyleSheet, Text, View } from "react-native";
class HelloWorld extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.hello}>HelloWorld,終於爬出坑了!</Text>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center"
},
hello: {
fontSize: 20,
textAlign: "center",
margin: 10
}
});
AppRegistry.registerComponent("MyReactNativeApp", () => HelloWorld);
5、建立MyReactActivity
public class MyReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
private final int OVERLAY_PERMISSION_REQ_CODE = 1; // 任寫一個值
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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);
}
}
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")//繫結的是app/src/main/assets中的bundle檔案
.setJSMainModulePath("index")//js檔名
.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();
}
@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);
}
@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
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
}
}
}
}
}
<!-- 聯網許可權 -->
<uses-permission android:name="android.permission.INTERNET" />
<activity
android:name=".MyReactActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>
如果需要訪問 DevSettingsActivity
介面(即開發者選單),則還需要在 AndroidManifest.xml
中宣告:
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
這樣就差不多了,在執行Android專案前,我們需要生成bundle檔案,也就是編譯js程式碼。
5、構建bundle檔案;這裡是我爬了最久的坑,官網和網上的資料都說要執行yarn start命令,但是我一直會卡在
就不動了。於是找了很久的資料,才發現其實不需要執行這個start命令,而是在package.json檔案中新增另外一句bundle-android命令;
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"bundle-android": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output app/src/main/assets/index.android.bundle --assets-dest app/src/main/res/"
}
該命令有2個資料夾路徑,其實就是我們的assets資料夾(要保證專案的assets路徑和命令中的資料夾路徑一致,不然會報找no such file or directory),bundle檔案會在這個命令之後在assets檔案下生成,我們在app/src/main下建立assets資料夾,然後直接在Terminal視窗執行這個命令:yarn bundle-android
6、執行我們的Android專案到真機或模擬器。需要許可權,這裡點選允許。
點選跳轉到MyReactActivity頁面,發現報錯了。
是以為我們沒有新增ndk的支援,在build.gradle檔案中新增
defaultConfig {
ndk{
abiFilters "armeabi-v7a","x86"
}
}
然後編譯,重新執行到真機,成功了!
總結:雖然過程比較艱辛,但是現在總結看來其實也不難弄,要注意的是,如果修改了js檔案,要重新執行yarn bundle-android命令新的js程式碼才能生效。寫的感覺比較詳細了,接下來繼續踩其他坑。