Abílio Azevedo.

Creating a native module for React Native to read the proximity sensor

Cover Image for Creating a native module for React Native to read the proximity sensor
Abílio Azevedo
Abílio Azevedo

💡 TLDR

Learn how to build a React Native module to access device proximity sensors. This guide covers integrating native iOS and Android code into React Native using modules. It demonstrates reading proximity data, returning it to JavaScript callbacks, and updating UI based on sensor changes. Discover the differences between native proximity sensor APIs on each platform. This is an essential tutorial for accessing native device hardware and capabilities in React Native apps.

React Native Development

React Native is an open-source framework that allows the development of cross-platform mobile apps using JavaScript and React. It is widely used by developers to build iOS and Android apps with a shared codebase. This saves time and resources since it allows developers to reuse a large part of the code between the two platforms.

Integration with Native Development

In some cases, it may be necessary to access specific native platform resources that are not directly available in React Native. For this, React Native provides a bridge that allows communication between JavaScript code and native platform code. There are two main ways to do this:

- Native Modules: Developers can create custom native modules in Objective-C (for iOS) or Java (for Android) and then expose those modules to JavaScript. This allows the JavaScript code to directly call native methods to perform platform-specific tasks.

- Native Views: In addition to native modules, it is possible to embed native UI components into your React Native app. This is useful when you need a highly customized user experience or want to directly integrate with third-party native libraries.

react-native-architecture Source: https://react-native-course.elazizi.com/about-react-native

Turbo Module and Fabric:

In 2018, React Native introduced two new architectures to improve performance and efficiency:

- Turbo Module: Turbo Module is an upgrade to the native modules architecture that aims to significantly improve JavaScript performance when calling native methods. It makes use of static compilation to speed up communication between JavaScript and native code.

- Fabric: Fabric is a new rendering architecture that aims to improve performance and responsiveness of user interfaces in React Native apps. It was designed to be lighter and more scalable, making apps faster and more resource efficient.

xplat-implementation-diagram-7611cf9dfb6d15667365630147d83ca5 Source: https://reactnative.dev/architecture/xplat-implementation

Learn more at: https://reactnative.dev/architecture/overview

Proximity Sensor

Did you know that among the various sensors your phone has, one of them is the proximity sensor? It's through it that your phone turns off the screen when answering a call and bringing it close to your face so as not to overheat next to your skin.

What other applications can we have for this sensor?

  • N26 uses it in its app to hide and show values.
  • You can create a flap bird style app
  • You can add a feature and flip through the pages of an ebook.

Therefore, let's create an RN library for IOS and Android to expose the native proximity sensor APIs. But first, let's understand the differences between the IOS and Android systems for this scenario:

IOS

On IOS the proximity sensor API return is a boolean:

true = Near

false = Far

and it behaves according to the graph below, with a buffer range.

Proximity Sensor Graph Source: https://itnext.io/ios-proximity-sensor-as-simple-as-possible-a473df883dc9

The native API documentation is here

IOS Simulators

The IOS simulators are included in Xcode, Apple's official IDE. They simulate the iOS operating system and device hardware like iPhones and iPads fully in software.

The simulators are fast and easy to use, but do not accurately reproduce real hardware. Some APIs that rely on specific hardware may not work properly. Simulators are best for testing app logic and interface.

For testing our module on iOS, we will have to use a physical device since the proximity sensor is not available on the iOS simulator.

ANDROID

On Android the proximity sensor API return is a numeric value from 0 to 10 cm, but on some devices it can also return a boolean value.

The native Android API documentation is here.

Android Emulators

The Android emulators are included in Android Studio, the official IDE. They run a virtual machine with a full version of the Android system. They emulate both software and hardware, including processor, GPU, camera, and sensors.

For testing our module on Android, we will be able to use the emulator since the proximity sensor is available.

Creating a Native Module

To create the native module in React Native it is recommended to use the react-native-builder-bob library.

It is a CLI that provides a module scaffold in React Native.

Let's start with the following command:

❯ npx create-react-native-library@latest react-native-proximity-sensor

We will have to answer some questions and select the module option we want to build. I chose a native module (Native Module) because I want at a later opportunity to migrate it to the newer Turbo Module version. CLI Module Builder

As well as the languages we want to use in our module. Module Builder 2

After these steps, our base project will be generated. In it we have the folders:

  • ios and android: where the native module codes will be.

  • example: where a sample application for testing the module is located.

  • src: where the javascript/typescript files of the module are located.

  • lib: where the transpiled files are after the build.

  • And the rest of the files are configuration.

Module Builder

This project uses turbo.build to build the packages and yarn workspaces to manage the project's applications. Therefore, at the root of the project you can run the command:

❯ yarn

And all dependencies will be installed, including the example project pods.

And to run the example project just run:

❯ yarn example ios

❯ yarn example android

Let's get to code

I won't go into detail on each part of the code, just the main ones so I don't drag on too much. Feel free to access the repository with the complete code and send me questions and suggestions.

iOS Code

In the ProximitySensor.m file we have a method to initialize sensor updates. As this initialization has to be done in the main thread, we need to make an async call to the main queue. You may notice that we have a RCT_EXPORT_METHOD decorator that will indicate this function will be exposed to the JS thread. Proximity Sensor IOS

With this we will have a callback function proximityStateDidChange, which will be called whenever the sensor value changes: Proximity Sensor IOS 2

Android Code

In the ProximitySensorModule.java file, we add the following import to access the sensor APIs.

import android.hardware.Sensor;

And we activate the proximity sensor:

Proximity Sensor Android

And so, in the callback function when the sensor changes, we build our logic to send an event to JS. In JS we will receive an object with the distance key and another timestamp key with a configurable interval: Proximity Sensor Android 2

Javascript Code

Now that we have events with sensor data being sent by native code, we can create a listener to monitor sensor changes in JS:

Proximity JS code

And in our example app we can consume this listener and when there is a proximity change from far to near and back to far again (is_double_toggle), we can change the visibility state of the balance: Proximity Sensor JS Code 2

Working on iOS

Here we see our module working on the iPhone (physical device): ProximitySensorIOS

Working on Android (Emulator)

Here we see our module working on Android (emulator): ProximitySensorAndroid

The NPM package can be found here.

The package repository is here. Who is excited to convert this module to React Native's new architecture? Feel free to send your contribution!

That is All Folks See you next time, folks!


More posts

Cover Image for The Phychology of Money

The Phychology of Money

Morgan Housel offers valuable insights on financial management and decision-making. The author emphasizes that financial success depends more on behavior than on intelligence or technical knowledge. Housel highlights the importance of long-term vision and resilience in the face of market volatility, encouraging us to focus on sustainability rather than short-term gains.

Cover Image for Bellsant

Bellsant

I've been at the forefront of developing a cutting-edge health and wellness app. Our tech stack combines React Native for cross-platform mobile development with a serverless NodeJS backend, leveraging AWS Lambda for scalability and cost-efficiency.

Abílio Azevedo
Abílio Azevedo

NewsLetter

I will send the content posted here. No Spam =)

Experienced Software Engineer with degree in Electrical Engineering with over 10 years of hands-on expertise in building robust and scalable mobile, web and backend applications across various projects mainly in the fintech sector. Mobile (React Native), Web (React and Next.JS) and Backend (Node.JS, PHP and DJANGO). My goal is to create products that add value to people. - © 2024, Abílio Azevedo