React Native has developed quite well this year. Many companies have started to use RN to develop React Native. I see many VIDEOS and practical courses about RN on MOOCs. I also learned RN by myself before, and I feel it is quite quick to get started. I also plan to continue learning. Let’s get to the point:

If you have written a lot of Android Native projects and want to use RN to implement some page functions, how do you access them? React Native Chinese also has reference, but I still have some problems following the article. I feel it is not suitable for beginners to use. Next I’m going to document some of my own access. I hope I can give some friends who are engaged in this to make some reference

Prerequisites for access:

  • Android native projects already exist
  • The RN environment is set up

The knowledge points recorded in this article are:

  • The Android project loads the RN page
  • RN to call the native method, which can be called back if the result is needed

Let’s take a quick look at what Android projects look like with RN:

Next, implement access

  • Step 1: Open the created Android project with Android Studio and run the following command in Terminal:

    1. npm init
    2. NPM install – save the react
    3. NPM install – save the react – native
    4. The curl – o. flowconfig raw.githubusercontent.com/facebook/re…

    Create NPM init (name, version); create NPM init (version); You can Copy the package.json file from the React Native project and change the name of the file to the same value. For the other three commands, press Enter one by one. Then from the React Copy a index in Native project. The android. Js, noting that needs to be AppRegistry. RegisterComponent (‘ RNComponent ‘() = > RNComponent); The second parameter is the same as the package.json name (I changed it to RNComponent, you can call it anything else).

  • Step 2: Now that React Native is almost done, the Android side needs to create an Activity to load all RN pages. Here I created MyReactActivity. You need to add some dependencies to Android before creating them. Otherwise, some classes will not be found. Let’s start configuring the Android project

    Step1. Add the following to build.gradle for the entire project:

    allprojects {
            repositories {
    
                mavenLocal()
                jcenter()
                maven {
                    // All of React Native (JS.Obj-C sources, Android binaries) is installed from npm
                    url "$rootDir/node_modules/react-native/android"
                }
            }
        }
    
        task clean(type: Delete) {
            delete rootProject.buildDir
        }Copy the code

    Compile “com.facebook.react:react-native:+” in builde.gradle of moudle

    android {
        compileSdkVersion 25
        buildToolsVersion "25.0.2"
        defaultConfig {
            applicationId "com.reactnative"
            minSdkVersion 16
            targetSdkVersion 25
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
    
        splits {
            abi {
                reset()
                enable true
                universalApk true  // If true, also generate a universal APK
                include "armeabi-v7a"."x86"
            }
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
        configurations.all {
            resolutionStrategy.force 'com. Google. Code. Findbugs: jsr305:3.0.0'
        }
    }
    
    dependencies {
        compile fileTree(dir: 'libs'.include: ['*.jar'])
        androidTestCompile('com. Android. Support. Test. Espresso: espresso - core: 2.2.2', {
            exclude group: 'com.android.support', module: 'support-annotations'
        })
        compile 'com. Android. Support: appcompat - v7:25.0.1'
        testCompile 'junit: junit: 4.12'
    
        compile "com.facebook.react:react-native:+"  // From node_modules
    }
    Copy the code
  • Following step 2 above, start creating MyReactActivity with the following code;

import com.facebook.react.ReactActivity;

public class MyReactActivity extends ReactActivity{

    @Override
    protected String getMainComponentName() {
        return "RNComponent"; }}Copy the code

There is a way of creating, it is like this, which both created MyReactActivity is ok, because ReactActivity DefaultHardwareBackBtnHandler interface and implementation.

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")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();


        mReactRootView.startReactApplication(mReactInstanceManager, "RNComponent".null);

        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed(); }}Copy the code
  • Next, create MainApplication with 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()
          // Add the package manager we created); }};@Override
  public ReactNativeHost getReactNativeHost() {
      return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this./* native exopackage */ false); }}Copy the code
  • Ok, finally in the AndroidManifest file, add some permissions and declare MainApplication and MyReactActivity
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.reactnative">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/>

    <application
        android:name=".MainApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>


        <activity
            android:name=".MyReactActivity"
            android:configChanges="orientation|screenSize"
            android:theme="@style/NoActionBar"
            />

        <activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>


    </application>

</manifest>Copy the code

When declaring MyReactActivity, you need to give it a style without ActionBar. Modify it in styles.xml:

  <style name="NoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>Copy the code

So far, there is no accident, generally can load RN page, the effect is as follows:

The simple access to this point is done, but in a normal project, RN would have to call some native methods and expect results. For example, if RN wants to find the path to some image in the system’s album, Android provides a way to find it and calls back the result to RN

Next, the process of implementing the interaction begins

  • The first step, need to write a class to inherit ReactContextBaseJavaModule
package com.reactnative;

import android.content.Context;
import android.text.TextUtils;
import android.widget.Toast;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.uimanager.IllegalViewOperationException;

public class MyNativeModule extends ReactContextBaseJavaModule {

    private Context mContext;

    public MyNativeModule(ReactApplicationContext reactContext) {
        super(reactContext);

        mContext = reactContext;
    }

    @Override
    public String getName() {

        The name returned is required in RN code to call methods of the class.
        return "MyNativeModule";
    }

    The function cannot return a value, because the native code being called is asynchronous. The native code can only be called through a callback or send a message to Rn.

    @ReactMethod
    public void rnCallNative(String msg) {

        Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
    }

    /** * The method created for the JS call passes the result of the network request back to JS ** @param url
     * @param callback
     */
    @ReactMethod
    public void getResult(String url, final Callback callback) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
// Simulate the operation of network request data
                    String result = "I'm asking for results.";
                    callback.invoke(true, result);

                } catch (Exception e) {

                }
            }
        }).start();
    }

    @ReactMethod
    public void tryCallBack(String name, String psw, Callback errorCallback, Callback successCallback) {
        try {
            if (TextUtils.isEmpty(name) && TextUtils.isEmpty(psw)) {
                // Callback on failure
                errorCallback.invoke("user or psw is empty");
            }
            // Callback on success
            successCallback.invoke("add user success");
        } catch (IllegalViewOperationException e) {
            // Callback on failureerrorCallback.invoke(e.getMessage()); }}/** * Callback to android data ** @param callback
     */
    @ReactMethod
    public void renderAndroidData(Callback callback) {
        callback.invoke("android data"); }}Copy the code

The first thing to note here is that the getName() method returns the alias that will be needed in RN’s JS to call native methods. Second, any method that needs to be called by RN needs to be annotated at @reactMethod. The third place, the native provided method return type is void, relatively simple such as rnCallNative(String MSG) RN call, is toast. If you want to return a result, you need a Callback, like renderAndroidData(Callback Callback)

Ok, now that the native method is done, we need to create a class to implement the ReactPackage and add the class we created to the list of native modules. As follows:

public class MyReactPackage implements ReactPackage {

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {

        List<NativeModule> modules = new ArrayList<>();
        // Add the class we created to the list of native modules
        modules.add(new MyNativeModule(reactContext));
        return modules;
    }


    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {

        // The return value needs to be modified
        return Collections.emptyList();
    }


    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {

        // The return value needs to be modified
        returnCollections.emptyList(); }}Copy the code

We also need to add the package manager we created in MainApplication, as follows:

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(),
                    // Add the package manager we created
                    newMyReactPackage() ); }};@Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        SoLoader.init(this./* native exopackage */ false); }}Copy the code

RN then calls the Native method in index.android.js.

  • Import {NativeModules} from ‘react-native’;

  • Call native methods can so to write NativeModules. MyNativeModule. RnCallNative (‘ call native methods of demos’);

Display the entire code of index.android.js;

export default class RNComponent extends Component {

    //Construct the constructor (props) {super(props);
        //The initial statethis.state = {
            title: ' '}; } render() {tryCall = (a)= > {
                 var rnToastAndroid = NativeModules.MyNativeModule;
                 rnToastAndroid.tryCallBack("luo"."131", (errorCallback) => {
                         alert(errorCallback)
                     },
                     (successCallback) => {
                         alert(successCallback);
                     });
             };
             androidback = (a)= > {

                 var ANdroidNative = NativeModules.MyNativeModule;
                 ANdroidNative.renderAndroidData((Callback) => { alert(Callback); });
             };

             return (

                 <View style={styles.container}>
                     <Text style={styles.welcome}
                           onPress={this.call_button.bind(this} > React Native calls! </Text> <Text style={styles.instructions} onPress={()=> Androidback ()} > Get android callback data </Text> <Text style={styles.instructions}> {NativeModules.MyNativeModule.rnCallNative(this.state.title)}
                     </Text>

                     <Text style={styles.instructions} onPress={()=>tryCall()}>
                         trycallAndroid
                     </Text>
                 </View>
             );
         }

         call_button(a) {

             NativeModules.MyNativeModule.rnCallNative('Call native method Demo'); }}const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
    },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10,
    },
    instructions: {
        textAlign: 'center',
        color: '# 333333',
        marginBottom: 5,}});

AppRegistry.registerComponent('RNComponent', () => RNComponent);
Copy the code

Take a look at the entire project catalog:

Final operation result:

So far, the introduction of Native access to RN and interaction with RN is basically over. If you are not quite clear about it, you can download the demo and combine it with this article. The Demo addressgithub