Creating a surrounding light sensor module (using Native Module) for Android device in React Native

Shayan Chatterjee
Engineering at Bajaj Health
4 min readJul 24, 2022

A couple of days ago, I was working on a task in a React Native app where I need to automatically turn on the torch/flash light of the device when the user turns on the camera within the app and the surrounding environment has dim/dark light. The flash/torch light should be auto turned off again if the surrounding light becomes significantly brighter.

Naturally, I looked for some package in react native which can provide me some data about my surrounding’s light condition. Unfortunately, I did not get any such package/library which provides such functionality. So I did some research about this topic and came across SensorManager API for android. Basically SensorManager lets you access the device’s sensors.

Checkout the SensorManager API docs — Docs Link

The hurdle here is that I can get the surrounding light data from the SensorManager but I need this value in my React Native JavaScript end so that I can turn on/off the flash light off the device based on the value.

Naturally, I had to write my own Native Module for android to perform this job. If you are new to Native Modules in React Native, check out their docs — Native Modules Intro . In short, sometimes as a developer we want to access some Native APIs of the device which are not available in Javascript. From their docs —

The NativeModule system exposes instances of Java/Objective-C/C++ (native) classes to JavaScript (JS) as JS objects, thereby allowing you to execute arbitrary native code from within JS.

I will list down the approach I have used —

  1. Create a Native Module which will implement the SensorEventListener interface. This interface provides two methods onSensoryChanged(SensorEvent event)and onAccuracyChanged(Sensor sensor, int accuracy), which we need to override in our module.
  2. Create a method which will send some kind of event with the current surroundings light value to the Javascript end.
  3. Register a listener at Javascript side which will listen to the value changes to the device’s surrounding environment.
  4. Lastly, turn on/off the device’s torch light based on the light value we receive from the listener.

Step 1 and Step 2 —

First, create the LightSensorModule. Inside android/app/src/main/java/com/<yourappname>, create a file called LightSensorModule.java (you can name it whatever you want).

What it does —

a. It implements SensorEventListener interface and overrides its two methods onSensorChanged and onAccuracyChanged. We are interested in the method onSensorChanged which will give us the value whenever the sensor value changes.

b. In the constructor of our module, we are initializing our SensorManager API of TYPE_LIGHT for our case. Check out all the type of sensors present here.

c. We are creating two methods called startLightSensor and stopLightSensorwhich we will be invoking from our JavaScript side. startLightSensor registers a listener for the sensor manager of the device. stopLightSensor unregisters/destroys the invoked listener.

d. onSensorChanged overridden method receives the sensor event value in its param, inside it we are creating a map with key lightValue and storing the corresponding sensor event value with it.

e. In our last process, we are passing the map to a method called sendEvent which uses the DeviceEventManagerModule to send events with some event properties. This is the event for which we will listen to at our Javascript end and ultimately fetch the lightValue from it.

Next, we have to create a package. Inside android/app/src/main/java/com/<yourappname>, create a file called LightSensorPackage.java where we are creating our NativeModules and declaring which module we need to add (in our case LightSensorModule which we just created above)

For the last process in this step, to register the LightSensorModulepackage, you must add LightSensorPackage to the list of packages returned in ReactNativeHost's getPackages() method. Open up your MainApplication.java or MainApplication.kt file, which can be found in the following path: android/app/src/main/java/com/your-app-name/

 @Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings(“UnnecessaryLocalVariable”)
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new LightSensorPackage());
return packages;
}

This ends our codes for native side. We now need to invoke these created methods in our JavaScript end.

Step 3 and 4-

Here, we are first starting our light sensor on the mount of the component inside the useEffect hook and also listening to the event with the name LightSensor which we are emitting from our native side code. The event value will be an object with a key lightValue that has the actual value of light (in unit called lux). Refer the below table to get an overall idea of the type of light values we can expect based on the surrounding environment.

Source — Interpreting lux values

Now, based upon the light value I can turn on/off the device’s torch light or you can do any logic as per your requirement. Lastly, we should stop the sensor from running in the background when not in use, hence invoking our second method stopLightSensor when the component unmounts.

So, that’s about it! We have created our Native Modules in android which uses our device’s light sensor to interpret the light value and we also checked how we can receive that value in our JavaScript end and perform any logic.

I have also published an npm package for the same called react-native-ambient-light-sensor. Check this out and use it if you want in your application!

Also you can checkout the complete GitHub repo link for the package here.

Hope you have enjoyed reading this :)

--

--

Shayan Chatterjee
Engineering at Bajaj Health

Software Engineer @ Bajaj Finserv Health | React and React Native Developer