React Native 中的 Native 模块:function returns "undefined"

Native module in React Native: function returns "undefined"

所以,我正在练习在 Java 中制作原生模块,这些模块可以将函数暴露给 React Native 的 JavaScript 代码。为此,我决定使用一个简单的演示数学库。我的代码如下。

MathOpsModule.java

package com.mb_rn_poc;

import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

public class MathOpsModule extends ReactContextBaseJavaModule {

  @Override
  public String getName() {
    return "MathOps"; // Name of the Native Modules.
  }

  @ReactMethod
  public int add(int a, int b) {
    return (a + b);
  }
}

MathOpsPackage.java

package com.mb_rn_poc;

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.ArrayList;
import java.util.Collections;
import java.util.List;

public class MathOpsPackage implements ReactPackage {

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

@Override
public List<NativeModule> createNativeModules(
      ReactApplicationContext reactContext
) {
    List<NativeModule> modules = new ArrayList<>();
    // Register the MathOps module
    modules.add(new MathOpsModule());
    return modules;
  }
}

MainApplication.java

package com.mb_rn_poc;

import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

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() {
          @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 MathOpsPackage());
          return packages;
        }

        @Override
        protected String getJSMainModuleName() {
          return "index";
        }
      };

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }

  /**
   * Loads Flipper in React Native templates. Call this in the onCreate method with something like
   * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
   *
   * @param context
   * @param reactInstanceManager
   */
  private static void initializeFlipper(
      Context context, ReactInstanceManager reactInstanceManager) {
    if (BuildConfig.DEBUG) {
      try {
        /*
         We use reflection here to pick up the class that initializes Flipper,
        since Flipper library is not available in release mode
        */
        Class<?> aClass = Class.forName("com.mb_rn_poc.ReactNativeFlipper");
        aClass
            .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
            .invoke(null, context, reactInstanceManager);
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        e.printStackTrace();
      }
    }
  }
}

现在,在 React Native 方面,我有这两个文件 -

MathOps.js

import { NativeModules } from 'react-native';

const MathOps = NativeModules.MathOps;

export const add = (a, b) => {
    return MathOps.add(a, b);
}

MainApp.js

import React, { useEffect, useState } from 'react';
import { SafeAreaView, Text, View } from 'react-native';
import { add } from "./NativeWrapper/MathOps";

const MainApp = () => {

    const [state, setState] = useState(0);

    useEffect(() => {
        let sum = add(10, 12);
        console.log({ sum });
        setState(sum);

    }, [])

    return (
        <SafeAreaView>
            <View>
                <Text>
                    {state}
                </Text>
            </View>
        </SafeAreaView>
    );
}

export default MainApp;

问题是,add 函数返回 undefined。因此,屏幕上不会打印任何内容。知道我可能做错了什么吗?

不确定这是什么问题,但有一个解决方法 - 使用回调,如 https://reactnative.dev/docs/native-modules-android 中所述。我做了以下修改-

@ReactMethod
public void add(Double a, Double b, Callback cb) {
    Double sum = a + b;
    cb.invoke(sum);
}
import { /* ... */ NativeModules } from 'react-native';
const { MathModule } = NativeModules;

// ...
// ...

MathModule.add(10, 20, (sum) => {
    alert(sum);
})

它做了我期望的事情 - 警报“30”。

对本机方法的调用是异步的,因此它们不能直接 return 值。

您可以使用回调(如您自己所想),或使用 Promise 以允许更优雅的 async / await 语法(以及更多):

@ReactMethod
public void add(Double a, Double b, Promise promise) {
    Double sum = a + b;
    promise.resolve(sum);
}
import { NativeModules } from 'react-native';

const { MathOps } = NativeModules;

export const add = async (a, b) => {
    return await MathOps.add(a, b);
}

React Native 桥是异步的。我们可以通过以下方式将数据从 Native Side 传递到 Javascript:-

1)Promise:当一个native模块Java/Kotlin方法的最后一个参数是一个Promise时,它对应的JS方法会return一个JS Promise对象。

在Module.java->

@ReactMethod
public void add(Double a, Double b, Promise promise) {            
        Double sum = a + b;
        promise.resolve(sum);
}       

这就是您在 Javascript->

中访问的方式
import { NativeModules } from 'react-native'; 
const { MathOps } = NativeModules;

export const add = async (a, b) => {
    return await MathOps.add(a, b);
}

2。 Callback: 它们也可以用于从本机端异步执行JavaScript。

在Module.java->

@ReactMethod
public void add(Double a, Double b, Callback cb) {            
        Double sum = a + b;
        cb.invoke(sum);
} 

这就是您在 Javascript->

中访问的方式
import { NativeModules } from 'react-native'; 
const { MathOps } = NativeModules;

useEffect(() => {
  MathOps.add(10, 12, (sum) => {
    setState(sum);
  });
}, [])

3。 isBlockingSynchronousMethod(由于性能损失和本机模块的 threading-related 错误,不推荐):您可以将 isBlockingSynchronousMethod = true 传递给本机方法以将其标记为同步方法。

@ReactMethod(isBlockingSynchronousMethod = true)
public Double add(Double a, Double b){
    Double sum = a + b;
    return sum;
}

在js文件中:

import { NativeModules } from 'react-native'; 
const { MathOps } = NativeModules;

export const add = async (a, b) => {
    return await MathOps.add(a, b);
}

4。发射事件:还没有探索太多。