0

When using native modules, it was possible to use them within existing native apps without the necessity of creating a new module:

There are two ways to write a native module for your React Native application:

  1. Directly within your React Native application’s iOS/Android projects

  2. As a NPM package that can be installed as a dependency by your/other React Native applications (https://reactnative.dev/docs/native-modules-intro)

With Turbo Modules, this option is not mentioned at all within the documentation. I know that Turbo Modules are quite cutting-edge, but is it possible to use Turbo Modules directly within native apps, just like native modules? I'd prefer a solution that will still work with CodeGen, if there is one.

Why do I want this? I'm trying to integrate React Native into my existing iOS and Android apps (Brownfield). By using native modules directly within my native apps, I can easily access old implementations/data without having to port them over into standalone modules.

I've tried to move the implementation of the <ModuleName>Spec.java into my existing android app, but this way the class extending TurboReactPackage is not able to return a new instance as soon as getModule is called.

Edit: I got it working. See my command if you want to know how.

flokol120
  • 167
  • 1
  • 2
  • 12

1 Answers1

0

By doing some tinkering I figured out, that I can just follow the documentation but do everything inside my existing react native project. I have to provide my own OnLoad.cpp and CMakeLists.txt however. This can be done by following the c++-Documentation of React Native Turbo Modules.

Here is some more detailed information on how I achieved this:

Add this to your apps build.gradle file:

android {
    ...
    externalNativeBuild {
        cmake {
            path "src/main/jni/CMakeLists.txt"
        }
    }
}

After that place the following two files under src/main/jni:

CMakeLists.txt:

# Copyright (c) Meta Platforms, Inc. and affiliates.
cmake_minimum_required(VERSION 3.13)
project(appmodules)
include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake)

OnLoad.cpp:

/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
#include <DefaultComponentsRegistry.h>
#include <DefaultTurboModuleManagerDelegate.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <rncli.h>
#include <<YourModuleNameHere>Spec.h>

namespace facebook {
namespace react {

void registerComponents(
    std::shared_ptr<ComponentDescriptorProviderRegistry const> registry) {
  rncli_registerProviders(registry);
}

std::shared_ptr<TurboModule> cxxModuleProvider(
    const std::string &name,
    const std::shared_ptr<CallInvoker> &jsInvoker) {
  return nullptr;
}

std::shared_ptr<TurboModule> javaModuleProvider(
    const std::string &name,
    const JavaTurboModule::InitParams &params) {
  auto module = <YourModuleNameHere>Spec_ModuleProvider(name, params);
  if(module != nullptr) {
    return module;
  }
  return rncli_ModuleProvider(name, params);
}

} // namespace react
} // namespace facebook

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
  return facebook::jni::initialize(vm, [] {
    facebook::react::DefaultTurboModuleManagerDelegate::cxxModuleProvider =
        &facebook::react::cxxModuleProvider;
    facebook::react::DefaultTurboModuleManagerDelegate::javaModuleProvider =
        &facebook::react::javaModuleProvider;
    facebook::react::DefaultComponentsRegistry::
        registerComponentDescriptorsFromEntryPoint =
            &facebook::react::registerComponents;
  });
}

The important part within the OnLoad.cpp is this part in the javaModuleProvider-Function:

...
  auto module = <YourModuleNameHere>Spec_ModuleProvider(name, params);
  if(module != nullptr) {
    return module;
  }
...

That way your Module will be loaded. Keep in mind to update <YourModuleNameHere> to fit your module name (both in the import and within javaModuleProvider).

flokol120
  • 167
  • 1
  • 2
  • 12
  • Hi, could you expand a little on adding the OnLoad.cpp and CMakeLists.txt files? I was able to get the turbo module inside my existing app working on iOS, but am struggling for Android. I added the two files to src/main/jni but then got a bit lost when the c++ documentation starts modifying those files with different paths. If you could add some info on what you did that'd be great. Thanks. – Tom Oakley Aug 30 '23 at 10:50
  • @TomOakley I've extended my solution. Hope this helps. Don't hesitate to ask, if something is still unclear. – flokol120 Aug 31 '23 at 11:07