Skip to content
tezvyn:
Menu

Building a custom native module

Source: interviewHardHow cards are made

Summary

Bridging native SDKs to JS.

Key points

write native classes in Kotlin/Java and Swift/Objective-C, expose methods via the module macros, register the module, and import via NativeModules with promises or events.

What's really being asked

Whether you understand the structure of a native module: writing platform code, exposing it asynchronously across the bridge, registering it, and consuming it from JavaScript.

The full answer

You implement the module twice, once per platform. On Android you create a class extending ReactContextBaseJavaModule, give it a name via getName, and annotate methods with ReactMethod; you register it through a ReactPackage added to the app's package list. On iOS you create a class with the RCT_EXPORT_MODULE macro and expose methods with RCT_EXPORT_METHOD in Objective-C, or use the appropriate bridging setup for Swift. Because the bridge is asynchronous, exported methods cannot return values directly; you pass results back through a promise (resolve and reject blocks) or callbacks, and for continuous data you emit events via an event emitter that JS subscribes to. You map types carefully, since only bridge-serializable types cross. On the JS side you access the module through NativeModules.YourModule and wrap it in a friendly JS API. With the new architecture you would instead define a Turbo Native Module with a typed spec and codegen, but the conceptual steps mirror the legacy bridge.

The mistakes people make

Forgetting to register the module in a ReactPackage or via the export macro, so JS sees undefined. Expecting an exported method to return a value synchronously across the asynchronous bridge. Not handling threading, running heavy native work on the main thread. Passing non-serializable types. Ignoring events for streaming data and trying to poll.

What usually comes next

How do promises versus callbacks versus events differ here, what changes under the new architecture with Turbo Modules and JSI, how do you handle threading with getMethodQueue, and how do you type the JS API.

A concrete example

For a hardware SDK that reads a sensor: on Android a ReactContextBaseJavaModule exposes a ReactMethod readSensor(promise) that calls the vendor SDK and resolves the promise with the value; on iOS an equivalent RCT_EXPORT_METHOD does the same with resolve and reject. Both register through their package or macro. In JS you import NativeModules.SensorModule and call await SensorModule.readSensor(), and for live readings you subscribe to a 'sensorUpdate' event from the module's emitter.

Interview question

Why must a method exported from a custom native module return its result via a promise, callback, or event rather than a direct return value?

  • a.JavaScript cannot read return values from native code at all
  • b.Promises are required only on iOS, while Android can return synchronously
  • c.The React Native bridge is asynchronous, so native results are passed back through resolve/reject, callbacks, or emitted eventsCorrect
  • d.Native modules are only allowed to mutate global state, not return values
Why?

The bridge between JS and native runs asynchronously, so exported methods deliver results through promises, callbacks, or events rather than synchronous returns. This is a cross-platform constraint of the legacy bridge, not an iOS-only rule.

Just read this? Test yourself on what you have been reading.

Read the original → reactnative.dev

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on react-native — each one lists the topics its interview covers.

See open roles