[Huawei Developers] Freemind R:
More articles like this, you can visit HUAWEI Developer Forum

Forum link: https://forums.developer.huawei.com/forumPortal/en/home​

Introduction

React Native is a convenient tool for cross platform development, and though it has become more and more powerful through the updates, there are limits to it, for example its capability to interact with and using the native components. Bridging native code with Javascript is one of the most popular and effective ways to solve the problem. Best of both worlds!

Currently not all HMS Kits has official RN support yet, this article will walk you through how to create android native bridge to connect your RN app with HMS Kits, and Scan Kit will be used as an example here.

The tutorial is based on https://github.com/clementf-hw/rn_integration_demo/tree/4b2262aa2110041f80cb41ebd7caa1590a48528a, you can find more details about the sample project in this article:

https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201230857831870061&fid=0101187876626530001

Prerequisites

Basic Android development

Basic React Native development

These areas have been covered immensely already on RN’s official site, this forum and other sources

HMS properly configured

You can also reference the above article for this matter

Major dependencies

RN Version: 0.62.2 (released on 9th April, 2020)

Gradle Version: 5.6.4

Gradle Plugin Version: 3.6.1

agcp: 1.2.1.301

This tutorial is broken into 3 parts:

Pt. 1: Create a simple native UI component as intro and warm up

Pt. 2: Bridging HMS Scan Kit into React Native

Pt. 3: Make Scan Kit into a stand alone React Native Module that you can import into other projects or even upload to npm.

Warm up

Let’s get to it. Before everything, the app looks like this:

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/005/943/868/2640852000005943868.20200519113737.15136678639344255843629307526958:50510624031959:2800:F75DB89CAAC0C3FF1594F04D71D1C7B1735CC6992EBC79E8A9B3B797F3AA8CF6.jpg"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/005/943/868/2640852000005943868.20200519113737.15136678639344255843629307526958:50510624031959:2800:F75DB89CAAC0C3FF1594F04D71D1C7B1735CC6992EBC79E8A9B3B797F3AA8CF6.jpg[/IMG]

Let’s make a simple UI component for warm up! We will add a native android button, which text will change when it is clicked.

First, in our android folder, let us create ReactNativeWarmUpModule.java. For simplicity purpose, you can create this file in the same folder with MainApplication.java

package com.cfdemo.d001rn;

import android.widget.Button;

import androidx.annotation.NonNull;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;

public class ReactNativeWarmUpModule extends SimpleViewManager<Button> {
private static final String REACT_CLASS = "RCTWarmUpView";
private static ReactApplicationContext reactContext;

public ReactNativeWarmUpModule(ReactApplicationContext context) {
reactContext = context;
}

@NonNull
@Override
public String getName() {
return null;
}

@NonNull
@Override
protected Button createViewInstance(@NonNull ThemedReactContext reactContext)
{
return null;
}
}

This part would be easier to do on Android Studio due to auto import feature.

For the name (the REACT_CLASS) of the module, it’s mostly up to you. RCT is an abbreviation of ReaCT and is a popular prefix

Modify createViewInstance to do something

@NonNull
@Override
protected Button createViewInstance(@NonNull ThemedReactContext reactContext) {
Button button = new Button(reactContext);
button.setOnClickListener(v -> ((Button) v).setText("Button Clicked"));
return button;
}

To make it more interactive with the React Native side, we can give it a ReactProp

@ReactProp(name = "text")
public void setText(Button button, String text) {
button.setText(text);
}

We are done with ReactNativeWarmUpModule for now, this is how it looks

package com.cfdemo.d001rn;

import android.widget.Button;

import androidx.annotation.NonNull;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;

public class ReactNativeWarmUpModule extends SimpleViewManager<Button> {
private static final String REACT_CLASS = "RCTWarmUpView";
private static ReactApplicationContext reactContext;

public ReactNativeWarmUpModule(ReactApplicationContext context) {
reactContext = context;
}

@NonNull
@Override
public String getName() {
return REACT_CLASS;
}

@NonNull
@Override
protected Button createViewInstance(@NonNull ThemedReactContext reactContext) {
Button button = new Button(reactContext);
button.setOnClickListener(v -> ((Button) v).setText("Button Clicked"));
return button;
}

@ReactProp(name = "text")
public void setText(Button button, String text) {
button.setText(text);
}
}

Now, to register the ViewManager, we’ll have to create a ReactPackage. You can put it in different places, but also for simplicity, you can put it in the same folder with ReactNativeWarmUpModule.

package com.cfdemo.d001rn;

import androidx.annotation.NonNull;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.Collections;
import java.util.List;

public class ReactNativeWarmUpPackage implements ReactPackage {

@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
return null;
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

Put ReactNativeWarmUpModule into createViewManagers

package com.cfdemo.d001rn;

import androidx.annotation.NonNull;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.Arrays;
import java.util.List;

public class ReactNativeWarmUpPackage implements ReactPackage {

@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();;
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new ReactNativeWarmUpModule(reactContext)
);
}
}

Since we will not register any other Native Modules for now, let's also give it an empty list

Collections.emptyList();

Next, we’ll add the package to our MainApplication.java, import the Package, and add it in the getPackages() function

import com.cfdemo.d001rn.ReactNativeWarmUpPackage;
…
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new ReactNativeWarmUpPackage());
return packages;
}

At this point, our native UI component is ready! So, how do we actually use it in React Native? There are a couple ways to invoke it, the simplest way would be to add this in the file where you want it to be

const RNWarmUpView = requireNativeComponent('RCTWarmUpView')

In the sample project it looks like this

//…
import { RNRemoteMessage } from 'react-native-hwpush';
import { getLastLocation, parseLocation, getLocationPermission } from '../../Helpers/LocationHelper'
import * as R from 'ramda'

const RNWarmUpView = requireNativeComponent('RCTWarmUpView')

export default class App extends Component {

constructor(props) {
//…

Then we render it

render() {
const { displayText, region } = this.state
return (
<View style={styles.container}>
<Text style={styles.textBox}>
{displayText}
</Text>
<RNWarmUpView style={styles.nativeModule}/>
<MapView
style={styles.map}
region={region}
showCompass={true}
showsUserLocation={true}
showsMyLocationButton={true}
>
</MapView>
</View>
);
}

Now the app looks like this, you can see the big grey area, which is actually our button here

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/005/943/868/2640852000005943868.20200519112326.72582431538888069239975036986247:50510624031959:2800:4F67A819666332E9A5E7DB8684901E4E348D9DFA43F503C58E8F9CFA5A349FB2.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/005/943/868/2640852000005943868.20200519112326.72582431538888069239975036986247:50510624031959:2800:4F67A819666332E9A5E7DB8684901E4E348D9DFA43F503C58E8F9CFA5A349FB2.png[/IMG]

Now we set the ReactProp we gave it earlier

<RNWarmUpView
style={styles.nativeModule}
text={"Render in Javascript"}
/>

Reload and it'd looks like this

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/005/943/868/2640852000005943868.20200519115517.81750702635137775009961565141895:50510624031959:2800:4DC203BC816BE886437674A559584DADB92F07AF9FCA354614F1C54A260E06E2.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/005/943/868/2640852000005943868.20200519115517.81750702635137775009961565141895:50510624031959:2800:4DC203BC816BE886437674A559584DADB92F07AF9FCA354614F1C54A260E06E2.png[/IMG]

Click on the button:

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/005/943/868/2640852000005943868.20200519115850.14411504055970828610753381599672:50510624031959:2800:32846E3C0E24594E6444ECACB356B8EC6F26F2C4E7B1FA003345B6880C94FE82.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/005/943/868/2640852000005943868.20200519115850.14411504055970828610753381599672:50510624031959:2800:32846E3C0E24594E6444ECACB356B8EC6F26F2C4E7B1FA003345B6880C94FE82.png[/IMG]

And we have finished the warm up!

Pt. 1 of the tutorial is done, please feel free to ask questions. You can also check out the repo of the sample project on github: https://github.com/clementf-hw/rn_integration_demo, and raise issue if you have any question or any update.