Skip to content

Commit 76eddc0

Browse files
authored
feat: add support for TurboModule (#843)
Note that this change 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") + } } } ``` If you're seeing build issues with `newArchEnabled=true`, please see https://github.com/microsoft/react-native-test-app/wiki/Troubleshooting.
1 parent e0b5eae commit 76eddc0

38 files changed

+874
-129
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,4 @@ DEPENDENCIES
5353
xcodeproj!
5454

5555
BUNDLED WITH
56-
2.2.22
56+
2.3.11

android/app/build.gradle

Lines changed: 114 additions & 14 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,21 +51,23 @@ 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()
6265

6366
android {
6467
compileSdkVersion project.ext.compileSdkVersion
6568

66-
// We need only set `ndkVersion` when building react-native from source.
67-
if (hasProperty("ANDROID_NDK_VERSION")) {
68-
ndkVersion ANDROID_NDK_VERSION
69+
if (project.hasProperty("ndkVersion")) {
70+
ndkVersion project.ext.ndkVersion
6971
}
7072

7173
// TODO: Remove this block when minSdkVersion >= 24. See
@@ -110,6 +112,69 @@ android {
110112
resValue "string", "app_name", project.ext.react.appName
111113

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

115180
lintOptions {
@@ -158,6 +223,13 @@ android {
158223
main.java.srcDirs += "src/no-fabric/java"
159224
}
160225

226+
// TODO: Remove this block when we drop support for 0.65.
227+
if (project.ext.react.enableNewArchitecture) {
228+
main.java.srcDirs += "src/turbomodule/java"
229+
} else {
230+
main.java.srcDirs += "src/no-turbomodule/java"
231+
}
232+
161233
// TODO: Remove this block when we drop support for 0.67.
162234
// https://github.com/facebook/react-native/commit/ce74aa4ed335d4c36ce722d47937b582045e05c4
163235
if (reactNativeVersion < 6800) {
@@ -166,6 +238,15 @@ android {
166238
main.java.srcDirs += "src/reactinstanceeventlistener-0.68/java"
167239
}
168240
}
241+
242+
splits {
243+
abi {
244+
reset()
245+
enable(project.ext.react.abiSplit)
246+
universalApk(false)
247+
include(*project.ext.react.architectures)
248+
}
249+
}
169250
}
170251

171252
dependencies {
@@ -175,8 +256,8 @@ dependencies {
175256
// TODO: Remove this block when we drop support for 0.68.
176257
if (reactNativeVersion < 6900) {
177258
def hermesEngineDir =
178-
findNodeModulesPath(file(reactNativeDir), "hermes-engine")
179-
?: findNodeModulesPath(file(reactNativeDir), "hermesvm")
259+
findNodeModulesPath("hermes-engine", file(reactNativeDir))
260+
?: findNodeModulesPath("hermesvm", file(reactNativeDir))
180261
if (hermesEngineDir == null) {
181262
throw new GradleException("Could not find 'hermes-engine'. Please make sure you've added it to 'package.json'.")
182263
}
@@ -236,3 +317,22 @@ dependencies {
236317
}
237318
}
238319
}
320+
321+
if (project.ext.react.enableNewArchitecture) {
322+
configurations.all {
323+
resolutionStrategy.dependencySubstitution {
324+
substitute(module("com.facebook.react:react-native"))
325+
.using(project(":ReactAndroid"))
326+
.because("On New Architecture, we are building React Native from source")
327+
substitute(module("com.facebook.react:hermes-engine"))
328+
.using(project(":ReactAndroid:hermes-engine"))
329+
.because("On New Architecture, we are building Hermes from source")
330+
}
331+
}
332+
}
333+
334+
// `@react-native-community/cli` currently requires this function to be defined.
335+
// See https://github.com/react-native-community/cli/blob/a87fb9014635fe84ab19a1a88d6ecbbc530eb4e2/packages/platform-android/native_modules.gradle#L497
336+
def isNewArchitectureEnabled() {
337+
return isFabricEnabled(project)
338+
}

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)