Skip to content
tezvyn:
Menu

Building a native module from scratch

Source: interviewHardHow cards are made

Summary

bridging JS to platform APIs.

Key points

write a native module class with exported methods or constants, register it via a package, then expose a typed JS wrapper.

WHAT THIS TESTS It checks that you grasp the native-to-JavaScript boundary: how platform capabilities like battery level get surfaced to React, and the registration plumbing required on each side.

A GOOD ANSWER COVERS On the native Android side you create a module class, for example BatteryModule, extending the React Native module base class. You give it a name via getName, and you expose data either as constants through getConstants or as methods. Methods that read live values should return results asynchronously using a Promise or callback because the call crosses into JavaScript. You then create a ReactPackage, for instance BatteryPackage, that returns your module from createNativeModules, and register that package in the app's MainApplication package list. The iOS side mirrors this with an RCT module exporting methods. On the JavaScript side you read NativeModules.Battery in the legacy architecture, or under the New Architecture you write a codegen spec file describing the TurboModule and let codegen generate the interfaces. You typically wrap the raw module in a small typed JS file so consumers get clean types and a stable API.

COMMON WRONG ANSWERS Confusing a native module, which exposes methods and data, with a native UI component, which renders a view. Returning live values synchronously. Forgetting package registration so the module is undefined at runtime.

LIKELY FOLLOW-UPS How does a TurboModule differ from a legacy native module? On which thread do module methods run, and how do you avoid blocking it? How do you emit events back to JS?

ONE CONCRETE EXAMPLE BatteryModule exposes getBatteryLevel returning a Promise. Android reads the system battery via BatteryManager off the main thread and resolves the promise. You register BatteryPackage in MainApplication, then in batteryModule.ts call NativeModules.Battery.getBatteryLevel(), exporting an async function with a number return type for the rest of the app.

Interview question

When a native module method reads a live device value to return to JavaScript, why should it use a Promise or callback rather than a direct return?

  • a.Because Promises are required to register the module in the package list
  • b.Because native code cannot return primitive values to JavaScript at all
  • c.Because synchronous returns are blocked by the Metro bundler
  • d.Because crossing the native-to-JS boundary is asynchronous, so results are delivered via promise or callbackCorrect
Why?

Values crossing from native into JavaScript are delivered asynchronously, so a Promise or callback is the correct pattern. Native code can return constants synchronously via getConstants, and package registration is unrelated to whether methods are async.

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