3

I just created a new application with create-react-native-app and I detached it to be able to make a native module.

Then, I created SensorManagerPackage.java next to MainApplication.java containing my package. And then created a module satisfying the ReactContextBaseJavaModule implementation.

But When I start my react-native application and I try to log the content of NativeModules, the result is an empty object. Do you have any idea why it doesn't load ?

MainApplication.java

import android.app.Application;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

import java.util.Arrays;
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() {
      return Arrays.<ReactPackage>asList(
              new MainReactPackage(),
              new SensorManagerPackage()
      );
    }

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

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

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

SensorManagerPackage.java

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.farmingapp.sensors.AmbientTemperatureSensor;
import com.farmingapp.sensors.LightSensor;
import com.farmingapp.sensors.PressureSensor;

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

public class SensorManagerPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new AmbientTemperatureSensor(reactContext));
        modules.add(new LightSensor(reactContext));
        modules.add(new PressureSensor(reactContext));
        return modules;
    }

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

AbstractSensor

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.annotation.Nullable;
import android.util.Log;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

public abstract class AbstractSensor extends ReactContextBaseJavaModule implements SensorEventListener {
    private final ReactApplicationContext reactContext;
    private final SensorManager sensorManager;
    private final Sensor sensor;
    private final int sensorId;
    private double lastReading = (double) System.currentTimeMillis();
    private int interval;

    public AbstractSensor(ReactApplicationContext reactContext, int sensorId) {
        super(reactContext);
        this.sensorId = sensorId;
        this.reactContext = reactContext;
        this.sensorManager = (SensorManager)reactContext.getSystemService(reactContext.SENSOR_SERVICE);
        this.sensor = this.sensorManager.getDefaultSensor(sensorId);
    }

    // RN Methods
    @ReactMethod
    public void setUpdateInterval(int newInterval) {
        this.interval = newInterval;
    }

    @ReactMethod
    public void startUpdates(Promise promise) {
        if (this.sensor == null) {
            // No sensor found, throw error
            promise.reject(new RuntimeException("No sensor found"));
            return;
        }
        promise.resolve(null);
        // Milisecond to Microsecond conversion
        sensorManager.registerListener(this, sensor, this.interval * 1000);
    }

    @ReactMethod
    public void stopUpdates() {
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }

    protected void sendEvent(String eventName, @Nullable WritableMap params) {
        try {
            this.reactContext
                    .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                    .emit(eventName, params);
        } catch (RuntimeException e) {
            Log.e("ERROR", "java.lang.RuntimeException: Trying to invoke Javascript before CatalystInstance has been set!");
        }
    }

    protected abstract WritableMap convertEvent(SensorEvent sensorEvent, WritableMap map);

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        double tempMs = (double) System.currentTimeMillis();
        if (tempMs - lastReading >= interval){
            lastReading = tempMs;

            WritableMap map = Arguments.createMap();

            if (sensorEvent.sensor.getType() == this.sensorId) {
                map.putDouble("timestamp", (double) System.currentTimeMillis());
                sendEvent(this.getName(), this.convertEvent(sensorEvent, map));
            }
        }
    }

}

LightSensor.java

import android.hardware.Sensor;
import android.hardware.SensorEvent;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableMap;

public class LightSensor extends AbstractSensor {
    public LightSensor(ReactApplicationContext reactContext) {
        super(reactContext, Sensor.TYPE_AMBIENT_TEMPERATURE);
    }

    @Override
    public String getName() {
        return "Light";
    }

    protected WritableMap convertEvent(SensorEvent sensorEvent, WritableMap map) {
        map.putDouble("value", sensorEvent.values[0]);
        return map;
    }

}

2 Answers 2

0

Have you updated your manifest and fully linked the library? You haven't included any sample code for your gradle settings and that you bring it into your packages.

https://cmichel.io/how-to-create-react-native-android-library/

Sign up to request clarification or add additional context in comments.

Comments

0

I just found the solution to that problem. The issue came from the fact that the @ReactMethod were declared in the AbstractSensor class.

To fix that I overrided the methods I wanted to expose in the child class and I put the @ReactMethod annotation on them.

And then, because the modules have now some exposed method, they are now visible in the NativeModules object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.