原生 Android 集成 React Native
使用 React Native 從零開始開發(fā)一款移動應(yīng)用是一件很愜意的事情,但對于一些已經(jīng)上線的產(chǎn)品,完全摒棄原有應(yīng)用的歷史沉淀,全面轉(zhuǎn)向 React Native 是不現(xiàn)實的。因此,使用React Native去統(tǒng)一原生Android、iOS應(yīng)用的技術(shù)棧,把它作為已有原生應(yīng)用的擴展模塊,是目前混合開發(fā)的最有效方式。
首先,在原生Android項目目錄下執(zhí)行以下命令創(chuàng)建一個package.json文件。
yarn init
然后,根據(jù)提示輸入對應(yīng)的配置信息。等待命令執(zhí)行完成之后,我們會發(fā)現(xiàn)Android項目的根目錄多了一個package.json文件。
接下來,使用如下命令添加React和React Native運行環(huán)境的支持腳本。
yarn add react react-native
執(zhí)行完命令后,會發(fā)現(xiàn)Android項目的根目錄下多了一個node_modules文件夾,里面包含了React Native開發(fā)也運行所需的依賴模塊,原則上這個目錄是不能復(fù)制、移動和修改的。
接下來,使用文本編輯器打開package.json文件,配置React Native的啟動腳本,如下代碼。
"scripts": {
"start": "yarn react-native start",
},
此時,package.json文件的完整內(nèi)容如下所示。
{
"name": "AndroidDemo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"react": "^17.0.1",
"react-native": "^0.63.4"
},
"scripts": {
"start": "yarn react-native start"
}
}
然后,在Android項目的根目錄下創(chuàng)建一個index.js文件,該文件是React Native的入口文件,代碼如下。
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}>Hello, React Native</Text>
</View>
);
}
}
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對應(yīng)的版本。然后,在項目的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清單文件,添加網(wǎng)絡(luò)權(quán)限代碼,如下所示。
<uses-permission android:name="android.permission.INTERNET" />
如果需要訪問開發(fā)者調(diào)試菜單,還需要在AndroidManifest.xml清單文件中注冊DevSettingsActivity界面,如下所示。
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
接下來,新建一個Activity作為React Native的容器頁面,并在Activity中創(chuàng)建一個ReactRootView對象,然后在這個對象之中啟動React Native應(yīng)用代碼,如下所示。
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】快捷鍵自動導(dǎo)入缺失的語句,并且BuildConfig是編譯時自動生成的,無需額外引入。
由于React Native應(yīng)用調(diào)試還需要懸浮窗權(quán)限,所以在需要在Android項目的代碼中添加懸浮窗權(quán)限邏輯,如下所示。
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作為應(yīng)用的主頁面,如下所示。
<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目錄下創(chuàng)建一個assets資源文件夾,然后執(zhí)行如下打包命令。
react-native bundle --platform android --entry-file index.js --bundle-output app/src/main/assets/index.android.bundle --dev false
接著,執(zhí)行yarn start命令啟動React Native服務(wù),重新運行原生Android項目即可看到如下圖所示。


