Turbo Native Modules
This documentation is still experimental and details are subject to changes as we iterate. Feel free to share your feedback on the discussion inside the working group for this page.
Moreover, it contains several manual steps. Please note that this won't be representative of the final developer experience once the New Architecture is stable. We're working on tools, templates and libraries to help you get started fast on the New Architecture, without having to go through the whole setup.
If you've worked with React Native, you may be familiar with the concept of Native Modules, which allow JavaScript and platform-native code to communicate over the React Native "bridge", which handles cross-platform serialization via JSON.
Turbo Native Modules are the next iteration on Native Modules that provide a few extra benefits:
- Strongly typed interfaces that are consistent across platforms
- The ability to write your code in C++, either exclusively or integrated with another native platform language, reducing the need to duplicate implementations across platforms
- Lazy loading of modules, allowing for faster app startup
- The use of JSI, a JavaScript interface for native code, allows for more efficient communication between native and JavaScript code than the bridge
This guide will show you how to create a basic Turbo Native Module compatible with the latest version of React Native.
Turbo Native Modules only work with the New Architecture enabled. To migrate to the New Architecture, follow the Migration guide
You can also setup local library containing Turbo Native Module with one command. Read the guide to Local libraries setup for more details.
How to Create a Turbo Native Moduleβ
To create a Turbo Native Module, we need to:
- Define the JavaScript specification.
- Configure the module so that Codegen can generate the scaffolding.
- Write the native code to finish implementing the module.
1. Folder Setupβ
In order to keep the module decoupled from the app, it's a good idea to define the module separately from the app and then add it as a dependency to your app later. This is also what you'll do for writing Turbo Native Modules that can be released as open-source libraries later.
Next to your application, create a folder called RTNCalculator
. RTN stands for "React Native", and is a recommended prefix for React Native modules.
Within RTNCalculator
, create three subfolders: js
, ios
, and android
.
The final result should look like this:
TurboModulesGuide
βββ MyApp
βββ RTNCalculator
βββ android
βββ ios
βββ js
2. JavaScript Specificationβ
The New Architecture requires interfaces specified in a typed dialect of JavaScript (either Flow or TypeScript). Codegen will use these specifications to generate code in strongly-typed languages, including C++, Objective-C++, and Java.
There are two requirements the file containing this specification must meet:
- The file must be named
Native<MODULE_NAME>
, with a.js
or.jsx
extension when using Flow, or a.ts
, or.tsx
extension when using TypeScript. Codegen will only look for files matching this pattern. - The file must export a
TurboModuleRegistrySpec
object.
- TypeScript
- Flow
// @flow
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import {TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {
add(a: number, b: number): Promise<number>;
}
export default (TurboModuleRegistry.get<Spec>(
'RTNCalculator'
): ?Spec);
import {TurboModule, TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {
add(a: number, b: number): Promise<number>;
}
export default TurboModuleRegistry.get<Spec>(
'RTNCalculator',
) as Spec | null;
At the beginning of the spec files are the imports:
- The
TurboModule
type, which defines the base interface for all Turbo Native Modules - The
TurboModuleRegistry
JavaScript module, which contains functions for loading Turbo Native Modules
The second section of the file contains the interface specification for the Turbo Native Module. In this case, the interface defines the add
function, which takes two numbers and returns a promise that resolves to a number. This interface type must be named Spec
for a Turbo Native Module.
Finally, we invoke TurboModuleRegistry.get
, passing the module's name, which will load the Turbo Native Module if it's available.
We are writing JavaScript files importing types from libraries, without setting up a proper node module and installing its dependencies. Your IDE will not be able to resolve the import statements and you may see errors and warnings. This is expected and will not cause problems when you add the module to your app.