Skip to content

Commit 133eada

Browse files
committed
feat: add support for TurboModule
Note that this requires some adjustments to your `build.gradle`: ```diff diff --git a/example/android/build.gradle b/example/android/build.gradle index 0c6c69d..2ed70f1 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,6 +1,7 @@ buildscript { def androidTestAppDir = "../node_modules/react-native-test-app/android" apply(from: "${androidTestAppDir}/dependencies.gradle") + apply(from: "${androidTestAppDir}/test-app-util.gradle") repositories { mavenCentral() @@ -8,8 +9,12 @@ buildscript { } dependencies { - classpath "com.android.tools.build:gradle:$androidPluginVersion" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + classpath("com.android.tools.build:gradle:${androidPluginVersion}") + + if (isNewArchitectureEnabled(project)) { + classpath("com.facebook.react:react-native-gradle-plugin") + classpath("de.undercouch:gradle-download-task:5.1.0") + } } } ```
1 parent 9145b17 commit 133eada

38 files changed

+1044
-337
lines changed

android/app/build.gradle

Lines changed: 113 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@ buildscript {
66

77
plugins {
88
id("com.android.application")
9-
id("kotlin-android")
10-
id("kotlin-kapt")
9+
id("org.jetbrains.kotlin.android") version "${kotlinVersion}"
10+
id("org.jetbrains.kotlin.kapt") version "${kotlinVersion}"
1111
}
1212

1313
// `react-native run-android` is hard-coded to look for the output APK at a very
1414
// specific location. See
1515
// https://github.com/react-native-community/cli/blob/6cf12b00c02aca6d4bc843446394331d71a9749e/packages/platform-android/src/commands/runAndroid/index.ts#L180
1616
buildDir = "${rootDir}/${name}/build"
1717

18-
def reactNativeDir = findNodeModulesPath(rootDir, "react-native")
19-
def reactNativeVersion = getReactNativeVersionNumber(rootDir)
18+
def reactNativeDir = findNodeModulesPath("react-native", rootDir)
19+
def reactNativeVersion = getPackageVersionNumber("react-native", rootDir)
2020

2121
repositories {
2222
maven {
@@ -51,11 +51,14 @@ apply(from: "${projectDir}/../../test-app.gradle")
5151
applyTestAppModule(project)
5252

5353
project.ext.react = [
54-
appName : getAppName(),
55-
applicationId: getApplicationId(),
56-
enableFabric : isFabricEnabled(rootDir),
57-
enableFlipper: getFlipperVersion(rootDir),
58-
enableHermes : true,
54+
abiSplit : false,
55+
appName : getAppName(),
56+
applicationId : getApplicationId(),
57+
architectures : ["arm64-v8a", "armeabi-v7a", "x86", "x86_64"],
58+
enableFabric : isFabricEnabled(project),
59+
enableFlipper : getFlipperVersion(rootDir),
60+
enableHermes : true,
61+
enableNewArchitecture: isNewArchitectureEnabled(project),
5962
]
6063

6164
project.ext.signingConfigs = getSigningConfigs()
@@ -106,6 +109,70 @@ android {
106109
resValue "string", "app_name", project.ext.react.appName
107110

108111
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
112+
113+
if (project.ext.react.enableNewArchitecture) {
114+
externalNativeBuild {
115+
ndkBuild {
116+
arguments "APP_PLATFORM=android-${project.ext.minSdkVersion}",
117+
"APP_STL=c++_shared",
118+
"NDK_TOOLCHAIN_VERSION=clang",
119+
"GENERATED_SRC_DIR=${buildDir}/generated/source",
120+
"NODE_MODULES_DIR=${reactNativeDir}/..",
121+
"PROJECT_BUILD_DIR=${buildDir}",
122+
"REACT_ANDROID_DIR=${reactNativeDir}/ReactAndroid",
123+
"REACT_ANDROID_BUILD_DIR=${reactNativeDir}/ReactAndroid/build"
124+
cFlags "-Wall", "-Werror", "-frtti", "-fexceptions", "-DWITH_INSPECTOR=1"
125+
cppFlags "-std=c++17"
126+
targets "reacttestapp_appmodules"
127+
}
128+
}
129+
if (!project.ext.react.abiSplit) {
130+
ndk {
131+
abiFilters(*project.ext.react.architectures)
132+
}
133+
}
134+
}
135+
}
136+
137+
if (project.ext.react.enableNewArchitecture) {
138+
externalNativeBuild {
139+
ndkBuild {
140+
path "${projectDir}/src/main/jni/Android.mk"
141+
}
142+
}
143+
144+
def reactAndroidProjectDir = project(":ReactAndroid").projectDir
145+
def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
146+
dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
147+
from("${reactAndroidProjectDir}/src/main/jni/prebuilt/lib")
148+
into("${buildDir}/react-ndk/exported")
149+
}
150+
def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
151+
dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
152+
from("${reactAndroidProjectDir}/src/main/jni/prebuilt/lib")
153+
into("${buildDir}/react-ndk/exported")
154+
}
155+
156+
afterEvaluate {
157+
//preBuild.dependsOn("generateCodegenArtifactsFromSchema")
158+
preDebugBuild.dependsOn(packageReactNdkDebugLibs)
159+
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
160+
161+
// Due to a bug in AGP, we have to explicitly set a dependency
162+
// between configureNdkBuild* tasks and the preBuild tasks. This can
163+
// be removed once this issue is resolved:
164+
// https://issuetracker.google.com/issues/207403732
165+
configureNdkBuildRelease.dependsOn(preReleaseBuild)
166+
configureNdkBuildDebug.dependsOn(preDebugBuild)
167+
project.ext.react.architectures.each { architecture ->
168+
tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure {
169+
dependsOn("preDebugBuild")
170+
}
171+
tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure {
172+
dependsOn("preReleaseBuild")
173+
}
174+
}
175+
}
109176
}
110177

111178
lintOptions {
@@ -154,6 +221,13 @@ android {
154221
main.java.srcDirs += "src/no-fabric/java"
155222
}
156223

224+
// TODO: Remove this block when we drop support for 0.65.
225+
if (project.ext.react.enableNewArchitecture) {
226+
main.java.srcDirs += "src/turbomodule/java"
227+
} else {
228+
main.java.srcDirs += "src/no-turbomodule/java"
229+
}
230+
157231
// TODO: Remove this block when we drop support for 0.67.
158232
// https://github.com/facebook/react-native/commit/ce74aa4ed335d4c36ce722d47937b582045e05c4
159233
if (reactNativeVersion < 6800) {
@@ -162,6 +236,15 @@ android {
162236
main.java.srcDirs += "src/reactinstanceeventlistener-0.68/java"
163237
}
164238
}
239+
240+
splits {
241+
abi {
242+
reset()
243+
enable(project.ext.react.abiSplit)
244+
universalApk(false)
245+
include(*project.ext.react.architectures)
246+
}
247+
}
165248
}
166249

167250
dependencies {
@@ -171,8 +254,8 @@ dependencies {
171254
// TODO: Remove this block when we drop support for 0.68.
172255
if (reactNativeVersion < 6900) {
173256
def hermesEngineDir =
174-
findNodeModulesPath(file(reactNativeDir), "hermes-engine")
175-
?: findNodeModulesPath(file(reactNativeDir), "hermesvm")
257+
findNodeModulesPath("hermes-engine", file(reactNativeDir))
258+
?: findNodeModulesPath("hermesvm", file(reactNativeDir))
176259
if (hermesEngineDir == null) {
177260
throw new GradleException("Could not find 'hermes-engine'. Please make sure you've added it to 'package.json'.")
178261
}
@@ -225,3 +308,22 @@ dependencies {
225308
}
226309
}
227310
}
311+
312+
if (project.ext.react.enableNewArchitecture) {
313+
configurations.all {
314+
resolutionStrategy.dependencySubstitution {
315+
substitute(module("com.facebook.react:react-native"))
316+
.using(project(":ReactAndroid"))
317+
.because("On New Architecture, we are building React Native from source")
318+
substitute(module("com.facebook.react:hermes-engine"))
319+
.using(project(":ReactAndroid:hermes-engine"))
320+
.because("On New Architecture, we are building Hermes from source")
321+
}
322+
}
323+
}
324+
325+
// `@react-native-community/cli` currently requires this function to be defined.
326+
// See https://github.com/react-native-community/cli/blob/a87fb9014635fe84ab19a1a88d6ecbbc530eb4e2/packages/platform-android/native_modules.gradle#L497
327+
def isNewArchitectureEnabled() {
328+
return isFabricEnabled(project)
329+
}

android/app/src/fabric/java/com/microsoft/reacttestapp/fabric/FabricJSIModulePackage.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class FabricJSIModulePackage(reactNativeHost: ReactNativeHost) : JSIModulePackag
3434
val componentFactory = ComponentFactory()
3535
CoreComponentsRegistry.register(componentFactory)
3636

37+
ComponentsRegistry.register(componentFactory)
38+
3739
return FabricJSIModuleProvider(
3840
reactApplicationContext,
3941
componentFactory,

android/app/src/main/java/com/microsoft/reacttestapp/react/TestAppReactNativeHost.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import android.content.Context
66
import android.util.Log
77
import com.facebook.react.PackageList
88
import com.facebook.react.ReactInstanceManager
9-
import com.facebook.react.ReactNativeHost
10-
import com.facebook.react.ReactPackage
119
import com.facebook.react.bridge.JSIModulePackage
1210
import com.facebook.react.bridge.ReactContext
1311
import com.facebook.react.bridge.ReactMarker
@@ -22,6 +20,7 @@ import com.facebook.soloader.SoLoader
2220
import com.microsoft.reacttestapp.BuildConfig
2321
import com.microsoft.reacttestapp.R
2422
import com.microsoft.reacttestapp.compat.ReactInstanceEventListener
23+
import com.microsoft.reacttestapp.compat.ReactNativeHostCompat
2524
import com.microsoft.reacttestapp.fabric.FabricJSIModulePackage
2625
import java.util.concurrent.CountDownLatch
2726

@@ -49,7 +48,7 @@ sealed class BundleSource {
4948
class TestAppReactNativeHost(
5049
application: Application,
5150
private val reactBundleNameProvider: ReactBundleNameProvider
52-
) : ReactNativeHost(application) {
51+
) : ReactNativeHostCompat(application) {
5352
var source: BundleSource =
5453
if (reactBundleNameProvider.bundleName == null || isPackagerRunning(application)) {
5554
BundleSource.Server
@@ -166,7 +165,7 @@ class TestAppReactNativeHost(
166165

167166
override fun getUseDeveloperSupport() = source == BundleSource.Server
168167

169-
override fun getPackages(): List<ReactPackage> = PackageList(application).packages
168+
override fun getPackages() = PackageList(application).packages
170169

171170
private fun addCustomDevOptions(devSupportManager: DevSupportManager) {
172171
val bundleOption = application.resources.getString(
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
THIS_DIR := $(call my-dir)
2+
3+
include $(REACT_ANDROID_DIR)/Android-prebuilt.mk
4+
5+
# If you wish to add a custom TurboModule or Fabric component in your app you
6+
# will have to include the following autogenerated makefile.
7+
# include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk
8+
9+
# Makefile for autolinked libraries
10+
include $(PROJECT_BUILD_DIR)/generated/rncli/src/main/jni/Android-rncli.mk
11+
12+
include $(CLEAR_VARS)
13+
14+
LOCAL_PATH := $(THIS_DIR)
15+
16+
# You can customize the name of your application .so file here.
17+
LOCAL_MODULE := reacttestapp_appmodules
18+
19+
LOCAL_C_INCLUDES := $(LOCAL_PATH)
20+
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
21+
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
22+
23+
# If you wish to add a custom TurboModule or Fabric component in your app you
24+
# will have to uncomment those lines to include the generated source
25+
# files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni)
26+
#
27+
# LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
28+
# LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
29+
# LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
30+
31+
# Autolinked TurboModules and Fabric components
32+
LOCAL_C_INCLUDES += $(PROJECT_BUILD_DIR)/generated/rncli/src/main/jni
33+
LOCAL_SRC_FILES += $(wildcard $(PROJECT_BUILD_DIR)/generated/rncli/src/main/jni/*.cpp)
34+
LOCAL_EXPORT_C_INCLUDES += $(PROJECT_BUILD_DIR)/generated/rncli/src/main/jni
35+
36+
# Here you should add any native library you wish to depend on.
37+
LOCAL_SHARED_LIBRARIES := \
38+
libfabricjni \
39+
libfbjni \
40+
libfolly_runtime \
41+
libglog \
42+
libjsi \
43+
libreact_codegen_rncore \
44+
libreact_debug \
45+
libreact_nativemodule_core \
46+
libreact_render_componentregistry \
47+
libreact_render_core \
48+
libreact_render_debug \
49+
libreact_render_graphics \
50+
librrc_view \
51+
libruntimeexecutor \
52+
libturbomodulejsijni \
53+
libyoga \
54+
$(call import-codegen-modules)
55+
56+
LOCAL_CFLAGS := -std=c++17 -Wall -frtti -fexceptions -DLOG_TAG=\"ReactNative\"
57+
58+
include $(BUILD_SHARED_LIBRARY)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include "ComponentsRegistry.h"
2+
3+
#include <CoreComponentsRegistry.h>
4+
#include <rncli.h>
5+
6+
#include <fbjni/fbjni.h>
7+
8+
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
9+
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
10+
#include <react/renderer/components/rncore/ComponentDescriptors.h>
11+
12+
using facebook::react::ComponentDescriptorParameters;
13+
using facebook::react::ComponentDescriptorProviderRegistry;
14+
using facebook::react::ComponentDescriptorRegistry;
15+
using facebook::react::ComponentFactory;
16+
using facebook::react::ContextContainer;
17+
using facebook::react::CoreComponentsRegistry;
18+
using facebook::react::EventDispatcher;
19+
using facebook::react::UnimplementedNativeViewComponentDescriptor;
20+
using ReactTestApp::ComponentsRegistry;
21+
22+
void ComponentsRegistry::registerNatives()
23+
{
24+
registerHybrid({makeNativeMethod("initHybrid", ComponentsRegistry::initHybrid)});
25+
}
26+
27+
ComponentsRegistry::ComponentsRegistry(ComponentFactory *)
28+
{
29+
}
30+
31+
facebook::jni::local_ref<ComponentsRegistry::jhybriddata>
32+
ComponentsRegistry::initHybrid(facebook::jni::alias_ref<jclass>, ComponentFactory *delegate)
33+
{
34+
delegate->buildRegistryFunction = [](EventDispatcher::Weak const &eventDispatcher,
35+
ContextContainer::Shared const &contextContainer)
36+
-> ComponentDescriptorRegistry::Shared {
37+
auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
38+
39+
// Register providers generated by `@react-native-community/cli`
40+
rncli_registerProviders(providerRegistry);
41+
42+
auto registry = providerRegistry->createComponentDescriptorRegistry(
43+
{eventDispatcher, contextContainer});
44+
45+
auto mutableRegistry = std::const_pointer_cast<ComponentDescriptorRegistry>(registry);
46+
47+
mutableRegistry->setFallbackComponentDescriptor(
48+
std::make_shared<UnimplementedNativeViewComponentDescriptor>(
49+
ComponentDescriptorParameters{eventDispatcher, contextContainer, nullptr}));
50+
51+
return registry;
52+
};
53+
54+
return makeCxxInstance(delegate);
55+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#ifndef REACTTESTAPP_JNI_COMPONENTSREGISTRY_H_
2+
#define REACTTESTAPP_JNI_COMPONENTSREGISTRY_H_
3+
4+
#include <ComponentFactory.h>
5+
6+
#include <fbjni/fbjni.h>
7+
8+
namespace ReactTestApp
9+
{
10+
class ComponentsRegistry : public facebook::jni::HybridClass<ComponentsRegistry>
11+
{
12+
public:
13+
constexpr static auto kJavaDescriptor =
14+
"Lcom/microsoft/reacttestapp/fabric/ComponentsRegistry;";
15+
16+
static void registerNatives();
17+
18+
ComponentsRegistry(facebook::react::ComponentFactory *delegate);
19+
20+
private:
21+
static facebook::jni::local_ref<ComponentsRegistry::jhybriddata>
22+
initHybrid(facebook::jni::alias_ref<jclass>, facebook::react::ComponentFactory *delegate);
23+
};
24+
} // namespace ReactTestApp
25+
26+
#endif // REACTTESTAPP_JNI_COMPONENTSREGISTRY_H_
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <fbjni/fbjni.h>
2+
3+
#include "ComponentsRegistry.h"
4+
#include "TurboModuleManagerDelegate.h"
5+
6+
using ReactTestApp::ComponentsRegistry;
7+
using ReactTestApp::TurboModuleManagerDelegate;
8+
9+
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *)
10+
{
11+
return facebook::jni::initialize(vm, [] {
12+
TurboModuleManagerDelegate::registerNatives();
13+
ComponentsRegistry::registerNatives();
14+
});
15+
}

0 commit comments

Comments
 (0)