4

所以,我正在练习用 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。因此,屏幕上不会打印任何内容。知道我可能做错了什么吗?

4

2 回答 2

5

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

您可以使用回调(正如您自己想出的那样),也可以使用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);
}
于 2021-08-20T14:12:28.910 回答
0

不确定这是什么问题,但有一种解决方法 - 使用回调,如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”。

于 2021-07-03T04:06:44.503 回答