Okay, so on the C++ JNI side, we implement this injectModuleIntoJSGlobal native method. It takes this memory address of the runtime pointer as an argument, and then it reinterpret casts it. Then it creates an object that we can use to store our binding on. And then we call a function that we've generated called RealmJSIInit. It's a lot of generated C++ that will basically store the binding between our C++ library and JSI. And finally, we set a property on the global that we can access from JavaScript afterwards.
On iOS, we have to do it a little more dirty in the sense that we need to access the runtime field of the RCT CXX bridge, which is a private API, and we declare this with a simple point pointer. And later on, we basically, again, we declare a blocking synchronous function that we can call from JavaScript. We get the JSI runtime pointer from the bridge, and then we cast it, and then we create the export subject. Again, we call the RealmJSIInit function to populate it, and finally, we store it on the global so we can access it from JavaScript. Then finally return.
The latest and the last alternative that I'm going to introduce is NitroModules. It's the new kid on the block introduced by Marcello and Mark Rosevie. It's very fast in synthetic benchmarks. It supports C++, Swift, Kotlin. It's much more expressive in the code generation part than the other alternatives. It leverages JSI native state and sets external memory pressure correctly. It also supports both the new and the old architecture as of a few days ago, which I'll get back to. The only drawback that I can see right now from using this is it requires app developers like your library users to install a peer dependency called React Native NitroModules, but I believe this is fixable in the future.
My conclusion is that, or at least as of a few days ago, would be to use the backwards compatible TurboNative module pattern. This is the blessed official way of doing things, but NitroModules changed and it doesn't anymore only support the new architecture. So I would say use NitroModules if you feel adventurous, but then who am I kidding? You're using React Native, so of course you feel adventurous. So basically, the last advice before I go, pre-building is a way of taking a part of your native code and building it on your machine instead of the end users machine. The benefit of this is lowering the build time on your library users' machines and also the complexity on their build chains. Another benefit is you get type failures in your development time instead of doing it on the developers' machines, like your users' machines. One limitation of Xcode and CocoaPods is that they cannot drive a CMake project. And this is a way to get about that is to basically use CMake to generate an Xcode project that can basically pre-build an XE framework, for example. That's what we're doing in Realm. Then one limitation here on the Android side is that these are in decay, like all of these pre-builds are in decay ABI specific, which means you either have to ship multiple pre-builds, one per in decay, but usually it's not a super big problem because in decay versions doesn't change that often. Either that, you need to either then, if you don't ship multiple, then you need to declare, I guess, what in decay version your library is compatible with.
Comments