In the application scenarios of React Native, sometimes only part of the pages of an APP are implemented by React Native. For example, many modules under the home page of the commonly used Ctrip APP are implemented by React Native. This development mode is called hybrid development.
Some other application scenarios for hybrid development:
Add RN pages to the original project and native pages to the RN project
RN modules are embedded in native pages
Embedded native modules in RN pages
All of the above are in the category of React Native hybrid development. How to implement React Native hybrid development?
In this article, I will introduce you to the process of React Native hybrid development, the technologies you need to master, and some experience and skills. The video tutorial on React Native and Android hybrid development will accompany this article.
React Native hybrid development on existing Android applications and React Native hybrid development on existing iOS applications will be introduced in this part of the tutorial.
There are several main steps to integrating React Native into an existing Android application:
- First, you need to have a React Native project;
- Add dependencies for existing Android apps like React Native.
- Create index.js and add your React Native code;
- Create an Activity to host React Native. In this Activity, create a ReactRootView as a container for the React Native service.
- Start the React Native Packager service and run the React Native application.
- (Optional) Add more React Native components as required.
- Run, debug, package, and publish applications;
- Promotion raise, marry Bai Fumei, to the peak of life! ;
1. Create a React Native project
Before doing hybrid development, we first needed to create a React Native project without Android and iOS modules. There are two ways to create a React Native project:
- through
npm
Install react Native to add a React Native project. - through
react-native init
To initialize a React Native project;
throughnpm
Install react-Native to add a React Native project
Step 1: Create a directory named RNHybridApp and add a package.json to this directory containing the following information:
{
"name": "RNHybrid"."version": "0.0.1"."private": true."scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"}}Copy the code
Step 2: Add react-native to package.json
Execute in this directory:
npm install --save react-native
Copy the code
After executing the above command, you should see the following warning:
NPM WARN [email protected] requires a peer of [email protected] but none is installed to tell us that we need to install [email protected]:
NPM install - save [email protected]Copy the code
At this point, a React Native project without Android and iOS modules has been created. See the React Native/Android hybrid development video for more on the issues encountered during this process
NPM creates node_modules in your directory. Node_modules is very large and is dynamically generated. It is recommended to add it to the.gitignore file.
Initialize a React Native project with a React -native init
In addition to the above methods, we can also initialize a React Native project with the react-native init command.
react-native init RNHybrid
Copy the code
The above command initializes a completed React Native project called RNHybrid, and then we delete the Android and ios directories in it and replace them with existing Android and ios projects.
2. Add the dependencies required by React Native
We have created a React Native project above. Now let’s look at how to integrate the React Native project with our existing one.
Before the fusion, we need to put existing Native projects under the RNHybrid we created. For example, I have an Android project named RNHybridAndroid, and put it under the RNHybrid directory:
RNHybrid ├ ─ ─ RNHybridAndroid ├ ─ ─ package. The json ├ ─ ─ node_modules └ ─ ─ the gitignoreCopy the code
Step 1: Configure Maven
Next, we need to add the React to existing RNHybridAndroid project Native dependence, in RNHybrid/RNHybridAndroid/app/build. Gradle file add the following code:
dependencies {
compile 'com. Android. Support: appcompat - v7:23.0.1'. compile"com.facebook.react:react-native:+" // From node_modules
}
Copy the code
Then, we provide RNHybridAndroid project configuration to use local React Native maven directory, in RNHybrid/RNHybridAndroid/build. Gradle file add the following code:
allprojects {
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/.. /node_modules/react-native/android"}... }... }Copy the code
Tip: To make sure you have configured the directory correctly, run Gradle sync in Android Studio to see if it says “Failed to resolve: Com.facebook. react:react-native:0.x.x” is displayed. If there is no error, the configuration is correct. See the React Native/Android hybrid development video for more on the issues encountered during this process
Step 2: Configure permissions
Check your project’s Androidmanifest.xml file to see if it has the following permissions:
<uses-permission android:name="android.permission.INTERNET" />
Copy the code
If not, you need to add the above permissions to androidmanifest.xml.
Also, if you need to use RN’s Dev Settings feature:
You need to add the following code to the androidmanifest.xml file:
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
Copy the code
Tip: The above image is the DevSettings function in the RN debugger. Opening this function will bring up a screen shown above, which is DevSettingsActivity.
Step 3: Specify compatible architectures for NDK (important)
Android cannot load so libraries of multiple architectures at the same time. Currently, many third-party Android SDKS support abi completely, which may include armeABI, ArmeabI-V7A,x86, ARM64-V8A, and X86_64. Unrestricted direct references will automatically compile APK that supports the five ABI’s, and Android devices will choose one of these ABI’s in preference, such as ARM64-V8A, but crash if other SDKS do not support this abi. The diagram below:
How to solve it:
Add the following code to your app/gradle file:
defaultConfig {
....
ndk {
abiFilters "armeabi-v7a"."x86"}}Copy the code
The code above means that the packaged SO library is limited to armeabi-V7A and x86. See the React Native/Android hybrid development video for more on the issues encountered during this process
Libgnustl_shared. so” is 32-bit instead of 64-bit
3. Create index.js and add your React Native code
Now that we’ve added the React Native dependency to the RNHybridAndroid project through the above two steps, let’s develop some JS code.
Create an index.js file in the RNHybrid directory and add the following code:
import { AppRegistry } from 'react-native';
import App from './App';
AppRegistry.registerComponent('App1', () => App);
Copy the code
The above code, AppRegistry. RegisterComponent (‘ App1, () = > App); The purpose is to register a component called App1 with React Native, and I’ll show you how to load and display this component in Android in step 4.
Also, in the code above we refer to an app.js file:
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View
} from 'react-native';
type Props = {};
export default class App extends Component<Props> {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
this is App
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
}
});
Copy the code
The app.js file represents our React Native page, which displays the text content of this is App.
This is how the React Native code was added for this demo. You can also add more React Native code and components as needed.
4. Create an Activity for React Native as a container
After steps 3 and 4 above, we have added the React Native dependencies to the RNHybridAndroid project, created some React Native code and registered a component called App1, Let’s learn how to use the App1 component in the RNHybridAndroid project.
Create RNPageActivity
First we need to create an Activity to act as a React Native container,
public class RNPageActivity 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")
.setJSMainModulePath("index") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); / / this"App1"Name and we have to in the index. Js registered in the name of the consistent AppRegistry. RegisterComponent () mReactRootView. StartReactApplication (mReactInstanceManager,"App1", null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() { super.onBackPressed(); }}Copy the code
Parameters that
setBundleAssetName
: When you pack itassets
The name of the JS bundle from which the App will load the JS bundle after the App release.setJSMainModulePath
: the filename of the main entry in the JS bundle, which we created aboveindex.js
File;addPackage
Add a Native Moudle to RN, which we added in the code abovenew MainReactPackage()
This is a must, in addition, if we create some other Native Moudle will also need to passaddPackage
To register them in RN. It’s important to point out that RN also provides one in addition to this methodaddPackages
Method is used to add Native Moudle to RN in batches.setUseDeveloperSupport
: Set RN to enable developer mode (debugging, reload, dev memu).setInitialLifecycleState
: This method is used to set the life cycle state in which RN is initializedLifecycleState.RESUMED
This is associated with the lifecycle state of the Activity container described below.mReactRootView.startReactApplication
: Its first argument ismReactInstanceManager
The second parameter is we are inindex.js
The name of the component registered in. The third parameter accepts oneBundle
As the initialization data passed to JS when RN is initialized, its specific usage will be in **React Android Hybrid development tutorial** in the specific explanation;
In the mediumAndroidManifest.xml
Register an RNPageActivity
Android requires that every Activity to be opened be registered in androidmanifest.xml:
<activity
android:name=".RNPageActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
Copy the code
In the above code, we add a @ to RNPageActivity style/Theme. AppCompat. Light. NoActionBar types of Theme, this also is the React Native UI components required by the subject.
Add the Activity’s lifecycle callback to the ReactInstanceManager
A ReactInstanceManager can be shared by multiple Activities or fragments, so we need to call back to the ReactInstanceManager’s methods during the Activity’s life cycle.
@Override
protected void onPause() {
super.onPause();
if(mReactInstanceManager ! = null) { mReactInstanceManager.onHostPause(this); } } @Override protected voidonResume() {
super.onResume();
if(mReactInstanceManager ! = null) { mReactInstanceManager.onHostResume(this, this); } } @Override public voidonBackPressed() {
if(mReactInstanceManager ! = null) { mReactInstanceManager.onBackPressed(); }else {
super.onBackPressed();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mReactInstanceManager ! = null) { mReactInstanceManager.onHostDestroy(this); }if (mReactRootView != null) {
mReactRootView.unmountReactApplication();
}
}
Copy the code
As you can see from the above code, there is a method onBackPressed that is not part of the Activity lifecycle. The main purpose of this method is to pass the event to JS when the user clicks the phone’s back button. If JS consumes the event, Native will no longer consume it. If the JS is not consumption this event as an RN callback invokeDefaultOnBackPressed code.
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
Copy the code
See the React Native/Android hybrid development video for a more detailed explanation of this process
Add developer menu
RN has a nice tool developer menu that we use a lot when debugging RN apps. Let’s add the open menu to RNHybridAndroid.
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (getUseDeveloperSupport()) {
if(keyCode = = KeyEvent. KEYCODE_MENU) {/ / Ctrl + M open an RN developers menu mReactInstanceManager showDevOptionsDialog ();return true; }}return super.onKeyUp(keyCode, event);
}
Copy the code
Listen on Ctrl + M to open the RN developer menu.
RN also provides the ability to quickly load JS by double-clicking on R, which can be turned on with the following code:
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (getUseDeveloperSupport()) {
if(keyCode = = KeyEvent. KEYCODE_MENU) {/ / Ctrl + M open an RN developers menu mReactInstanceManager showDevOptionsDialog ();return true;
}
boolean didDoubleTapR = Assertions.assertNotNull(mDoubleTapReloadRecognizer).didDoubleTapR(keyCode, getCurrentFocus());
if(didDoubleTapR) {/ / double R reload JS mReactInstanceManager. GetDevSupportManager () handleReloadJS ();return true; }}return super.onKeyUp(keyCode, event);
}
Copy the code
See the React Native/Android hybrid development video for a more detailed explanation of this process
Use ReactActivity as an RN container
In the above code we are through ReactInstanceManager to create and load JS, and then rewrite the Activity lifecycle to ReactInstanceManager callback, in addition, rewrite onKeyUp to enable the developer menu and other functions.
In addition, if you look at RN’s source code, you will find an Activity called ReactActivity in RN’s SDK. This Activity is an RN container officially packaged by RN. In addition, in a project initialized with the React-native init command, you’ll find a MainActivity that inherits from ReactActivity, so we’ll encapsulate an RN container by inheriting from ReactActivity.
public class ReactPageActivity extends ReactActivity implements IJSBridge{
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "App1"; }}Copy the code
In addition, we need to implement a MainApplication and add the following code:
public class MainApplication extends Application implements ReactApplication {
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
protected String getJSMainModuleName() {
return "index"; }}; @Override public ReactNativeHostgetReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false); }}Copy the code
The main purpose of this code is to provide the ReactNativeHost for the ReactActivity. If you look at the source code, you will find that the ReactActivityDelegate is used in the ReactActivity. The ReactNativeHost provided in MainApplication is used in the ReactActivityDelegate:
protected ReactNativeHost getReactNativeHost() {
return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost();
}
Copy the code
Add MainApplication to androidmanifest.xml
<application
android:name=".MainApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">...Copy the code
This is done by inheriting ReactActivity as an RN container.
So what are the characteristics of these two ways:
- through
ReactInstanceManager
The way: flexible, customizable; - Through inheritance
ReactActivity
The way: simple, customizable poor;
See the React Native/Android hybrid development video for a more detailed explanation of this process
5. Run React Native
After the above steps, we have completed adding RN to an existing Android project RNHybridAndroid, We also created an RNPageActivity and a ReactPageActivity Activity to load our RN component App1 registered in JS.
Next let’s start the RN server and run the RNHybridAndroid project to open RNPageActivity or ReactPageActivity to see the effect:
npm start
Copy the code
Run the above command at the root of RNHybrid to start an RN local service:
Then we open AndroidStudio, click the Run button or use the shortcut Ctrl+R to install RNHybridAndroid on the emulator:
6. Add more React Native components
We can add more React Native components as needed:
import { AppRegistry } from 'react-native';
import App from './App';
import App2 from './App2';
AppRegistry.registerComponent('App1', () => App);
AppRegistry.registerComponent('App2', () => App);
Copy the code
Then, load the RN component with the specified name as needed in Native.
7. Debug, package, and publish applications
debugging
Debugging this hybrid RN application is the same as debugging a pure RN application, which is based on the RN developer menu mentioned above. In addition, you can learn more RN debugging skills by learning The React Native technical intensive and high-quality online APP development courses.
packaging
RNHybridAndroid: RNHybridAndroid: RNHybridAndroid: RNHybridAndroid: RNHybridAndroid: RNHybridAndroid: RNHybridAndroid: RNHybridAndroid
react-native bundle --platform android --dev false --entry-file index.js --bundle-output RNHybridAndroid/app/src/main/assets/index.android.bundle --assets-dest RNHybridAndroid/app/src/main/res/
Copy the code
Parameters that
--platform android
: indicates that the package is exported to Android.--dev false
: represents the developer mode of closing JS;-entry-file index.js
: represents the entry file of JSindex.js
;--bundle-output
: this is followed by the location to which the JS bundle is exported.--assets-dest
: Followed by some of the packaged resource files exported to the location;
Note: the JS bundle must be placed in the assets directory of your Android language. This corresponds to setBundleAssetName(“index.android.bundle”).
Release application
After wrapping up RN code and generating JS bundles and placing them in assets, we can release our RN hybrid Android application via Android Studio or command.
React Native’s signature package for APK has been published in my previous post. If you need to check it out, I won’t repeat it in this post.
Learn more about React Native hybrid development and learn how to React Native hybrid Development with Android.
reference
- React Native technology highlights and high quality live APP development
- React Native releases the APP’s signature package APK
- Integration with Existing Apps