chrispader-release-experiment-nitro-modules
v0.15.2
Published
Insanely fast native C++, Swift or Kotlin modules with a statically compiled binding layer to JSI.
Downloads
288
Maintainers
Readme
react-native-nitro-modules is a core library that contains highly efficient statically compiled JS to C++ bindings.
It uses JSI to generate C++ templates that can bridge virtually any JS type to a C++ type with minimal overhead.
Installation
Inside an app
Install react-native-nitro-modules as a dependency
in your react-native app:
npm i react-native-nitro-modules
cd ios && pod install
Inside a nitro module library
If you are building a nitro module yourself, add react-native-nitro-modules as a peerDependency
into your library's package.json
:
{
...
"peerDependencies": {
...
"react-native-nitro-modules": "*"
},
}
Then install react-native-nitro-modules
as a normal dependency
in your library's example/
app as seen above.
Usage
react-native-nitro-modules can either be used with-, or without nitrogen, or mixed (some objects are automatically generated, some manually).
With Nitrogen
When using Nitrogen, all the bindings are automatically generated. You only need to implement C++, Swift or Kotlin interfaces inside your codebase.
Without Nitrogen
All C++ bindings are bridged to JS using "Hybrid Objects".
A Hybrid Object can have both methods and properties (get and set).
Create a C++ Hybrid Object by inheriting from HybridObject
:
#include <NitroModules/HybridObject.hpp>
using namespace margelo::nitro;
class MyHybridObject: public HybridObject {
public:
explicit MyHybridObject(): HybridObject(TAG) {}
public:
// Property (get)
double getNumber() { return 13; }
// Property (set)
void setNumber(double value) { }
// Method
double add(double left, double right) { return left + right; }
public:
void loadHybridMethods() override {
// Call base method to make sure we properly inherit `toString()` and `equals()`
HybridObject::loadHybridMethods();
// Register all methods that need to be exposed to JS
registerHybrids(this, [](Prototype& prototype) {
prototype.registerHybridGetter("number", &MyHybridObject::getNumber);
prototype.registerHybridSetter("number", &MyHybridObject::setNumber);
prototype.registerHybridMethod("add", &MyHybridObject::add);
});
}
private:
static constexpr auto TAG = "MyHybrid";
};
The MyHybridObject
can then be registered in the HybridObjectRegistry
at app startup:
#include <NitroModules/HybridObjectRegistry.hpp>
// Call this at app startup to register the HybridObjects
void load() {
HybridObjectRegistry::registerHybridObjectConstructor(
"MyHybrid",
[]() -> std::shared_ptr<HybridObject> {
return std::make_shared<MyHybridObject>();
}
);
}
Inside your MyHybridObject
, you can use standard C++ types which will automatically be converted to JS using Nitro's JSIConverter<T>
interface.
The following C++ / JS types are supported out of the box:
Since the JSIConverter<T>
is just a template, you can extend it with any other custom types by overloading the interface.
For example, to add support for an enum, overload JSIConverter<MyEnum>
:
#include <NitroModules/JSIConverter.hpp>
enum class MyEnum {
FIRST = 0,
SECOND = 1
};
namespace margelo::nitro {
template <>
struct JSIConverter<MyEnum> {
static inline MyEnum fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
int intValue = JSIConverter<int>::fromJSI(runtime, arg);
return static_cast<MyEnum>(intValue);
}
static inline jsi::Value toJSI(jsi::Runtime& runtime, MyEnum arg) {
int intValue = static_cast<int>(arg);
return JSIConverter<int>::toJSI(runtime, intValue);
}
};
}
Once the JSIConverter<T>
for MyEnum
is defined, you can use the type MyEnum
in C++ methods, getters and setters of HybridObject
s.
And on the JS side, you can simply treat the returned number
(int) as a MyEnum
:
enum MyEnum {
FIRST = 0,
SECOND = 1
}
const value = myHybridObject.getEnumValue() // <-- typed as `MyEnum` instead of `number`
Make sure to always include the header that defines the JSIConverter<MyEnum>
overload inside the MyHybridObject
file, as this is where the JSIConverter<T>
overloads are accessed from.
Nitrogen can automatically generate such JSIConverter<T>
extensions for enums, TypeScript unions, and even structs/objects - so it is generally recommended to use nitrogen.