Skip to content

Commit 1ee3eac

Browse files
committed
feat: add support for TurboModule
1 parent a3c9c55 commit 1ee3eac

File tree

18 files changed

+354
-68
lines changed

18 files changed

+354
-68
lines changed

android/app/build.gradle

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ 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}"
11+
12+
// TODO: This is only available on react-native 0.68+
13+
//id("com.facebook.react")
1114
}
1215

1316
// `react-native run-android` is hard-coded to look for the output APK at a very
@@ -50,11 +53,12 @@ apply(from: "${projectDir}/../../test-app.gradle")
5053
applyTestAppModule(project)
5154

5255
project.ext.react = [
53-
appName : getAppName(),
54-
applicationId: getApplicationId(),
55-
enableFabric : isFabricEnabled(rootDir),
56-
enableFlipper: getFlipperVersion(rootDir),
57-
enableHermes : true,
56+
appName : getAppName(),
57+
applicationId : getApplicationId(),
58+
enableFabric : isFabricEnabled(rootDir),
59+
enableFlipper : getFlipperVersion(rootDir),
60+
enableHermes : true,
61+
enableTurboModule: isTurboModuleEnabled(rootDir),
5862
]
5963

6064
project.ext.signingConfigs = getSigningConfigs()
@@ -69,14 +73,20 @@ android {
6973

7074
// TODO: Remove this block when minSdkVersion >= 24. See
7175
// https://stackoverflow.com/q/53402639 for details.
72-
compileOptions {
73-
sourceCompatibility JavaVersion.VERSION_1_8
74-
targetCompatibility JavaVersion.VERSION_1_8
76+
if (getReactNativeVersionNumber(rootDir) < 6900) {
77+
compileOptions {
78+
sourceCompatibility(JavaVersion.VERSION_1_8)
79+
targetCompatibility(JavaVersion.VERSION_1_8)
80+
}
7581
}
7682

7783
kotlinOptions {
7884
allWarningsAsErrors = true
79-
jvmTarget = JavaVersion.VERSION_1_8
85+
if (getReactNativeVersionNumber(rootDir) < 6900) {
86+
jvmTarget = JavaVersion.VERSION_1_8
87+
} else {
88+
jvmTarget = JavaVersion.VERSION_11
89+
}
8090
}
8191

8292
defaultConfig {
@@ -99,6 +109,57 @@ android {
99109
resValue "string", "app_name", project.ext.react.appName
100110

101111
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
112+
113+
if (project.ext.react.enableTurboModule) {
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+
}
130+
}
131+
132+
if (project.ext.react.enableTurboModule) {
133+
externalNativeBuild {
134+
ndkBuild {
135+
path "${projectDir}/src/main/jni/Android.mk"
136+
}
137+
}
138+
139+
def reactAndroidProjectDir = project(":ReactAndroid").projectDir
140+
def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
141+
dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
142+
from("${reactAndroidProjectDir}/src/main/jni/prebuilt/lib")
143+
into("${buildDir}/react-ndk/exported")
144+
}
145+
def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
146+
dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
147+
from("${reactAndroidProjectDir}/src/main/jni/prebuilt/lib")
148+
into("${buildDir}/react-ndk/exported")
149+
}
150+
151+
afterEvaluate {
152+
preBuild.dependsOn("generateCodegenArtifactsFromSchema")
153+
preDebugBuild.dependsOn(packageReactNdkDebugLibs)
154+
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
155+
156+
// Due to a bug in AGP, we have to explicitly set a dependency
157+
// between configureNdkBuild* tasks and the preBuild tasks. This can
158+
// be removed once this issue is resolved:
159+
// https://issuetracker.google.com/issues/207403732
160+
configureNdkBuildRelease.dependsOn(preReleaseBuild)
161+
configureNdkBuildDebug.dependsOn(preDebugBuild)
162+
}
102163
}
103164

104165
lintOptions {
@@ -211,3 +272,16 @@ dependencies {
211272
}
212273
}
213274
}
275+
276+
if (project.ext.react.enableTurboModule) {
277+
configurations.all {
278+
resolutionStrategy.dependencySubstitution {
279+
substitute(module("com.facebook.react:react-native"))
280+
.using(project(":ReactAndroid"))
281+
.because("On New Architecture we are building React Native from source")
282+
substitute(module("com.facebook.react:hermes-engine"))
283+
.using(project(":ReactAndroid:hermes-engine"))
284+
.because("On New Architecture we are building Hermes from source")
285+
}
286+
}
287+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
include $(CLEAR_VARS)
9+
10+
LOCAL_PATH := $(THIS_DIR)
11+
12+
# You can customize the name of your application .so file here.
13+
LOCAL_MODULE := reacttestapp_appmodules
14+
15+
LOCAL_C_INCLUDES := $(LOCAL_PATH)
16+
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
17+
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
18+
19+
# If you wish to add a custom TurboModule or Fabric component in your app you
20+
# will have to uncomment those lines to include the generated source
21+
# files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni)
22+
#
23+
# LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
24+
# LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
25+
# LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
26+
27+
# Here you should add any native library you wish to depend on.
28+
LOCAL_SHARED_LIBRARIES := \
29+
libfabricjni \
30+
libfbjni \
31+
libfolly_runtime \
32+
libglog \
33+
libjsi \
34+
libreact_codegen_rncore \
35+
libreact_debug \
36+
libreact_nativemodule_core \
37+
libreact_render_componentregistry \
38+
libreact_render_core \
39+
libreact_render_debug \
40+
libreact_render_graphics \
41+
librrc_view \
42+
libruntimeexecutor \
43+
libturbomodulejsijni \
44+
libyoga
45+
46+
LOCAL_CFLAGS := -std=c++17 -Wall -frtti -fexceptions -DLOG_TAG=\"ReactNative\"
47+
48+
include $(BUILD_SHARED_LIBRARY)

android/test-app-util.gradle

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,16 @@ ext.getManifest = {
132132
return manifest
133133
}
134134

135+
def reactNativeVersion = 0
135136
ext.getReactNativeVersionNumber = { baseDir ->
136-
def reactNativePath = findNodeModulesPath(baseDir, "react-native")
137-
def packageJson = file("${reactNativePath}/package.json")
138-
def manifest = new JsonSlurper().parseText(packageJson.text)
139-
def (major, minor, patch) = manifest["version"].findAll(/\d+/)
140-
return (major as int) * 10000 + (minor as int) * 100 + (patch as int)
137+
if (reactNativeVersion == 0) {
138+
def reactNativePath = findNodeModulesPath(baseDir, "react-native")
139+
def packageJson = file("${reactNativePath}/package.json")
140+
def manifest = new JsonSlurper().parseText(packageJson.text)
141+
def (major, minor, patch) = manifest["version"].findAll(/\d+/)
142+
reactNativeVersion = (major as int) * 10000 + (minor as int) * 100 + (patch as int)
143+
}
144+
return reactNativeVersion
141145
}
142146

143147
ext.getSigningConfigs = {
@@ -192,7 +196,14 @@ ext.getSingleAppMode = {
192196
}
193197

194198
ext.isFabricEnabled = { baseDir ->
195-
return project.hasProperty("USE_FABRIC") &&
196-
project.getProperty("USE_FABRIC") == "1" &&
199+
return isTurboModuleEnabled(baseDir) ||
200+
(project.hasProperty("USE_FABRIC") &&
201+
project.getProperty("USE_FABRIC") == "1" &&
202+
getReactNativeVersionNumber(baseDir) >= 6800)
203+
}
204+
205+
ext.isTurboModuleEnabled = { baseDir ->
206+
return project.hasProperty("USE_TURBOMODULE") &&
207+
project.getProperty("USE_TURBOMODULE") == "1" &&
197208
getReactNativeVersionNumber(baseDir) >= 6800
198209
}

example/android/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ buildscript {
88
}
99

1010
dependencies {
11-
classpath "com.android.tools.build:gradle:$androidPluginVersion"
12-
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
11+
classpath("com.android.tools.build:gradle:${androidPluginVersion}")
12+
classpath("de.undercouch:gradle-download-task:5.1.0")
1313
}
1414
}
1515

example/android/gradle.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,9 @@ android.enableJetifier=true
3434
# Enable Fabric at runtime.
3535
#USE_FABRIC=1
3636

37+
# Enable TurboModule - implies USE_FABRIC=1
38+
# Note that this is incompatible with web debugging.
39+
#USE_TURBOMODULE=1
40+
3741
# Uncomment the line below if building react-native from source
3842
#ANDROID_NDK_VERSION=21.4.7075529

example/android/settings.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pluginManagement {
22
repositories {
33
gradlePluginPortal()
4-
mavenLocal()
4+
mavenCentral()
55
google()
66
}
77
}

example/ios/Podfile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ workspace 'Example.xcworkspace'
44

55
use_flipper! false if ENV['DISABLE_FLIPPER']
66

7-
use_test_app! :fabric_enabled => false, :hermes_enabled => false do |target|
7+
options = {
8+
:fabric_enabled => false,
9+
:hermes_enabled => false,
10+
:turbomodule_enabled => false,
11+
}
12+
13+
use_test_app! options do |target|
814
target.tests do
915
pod 'Example-Tests', :path => '..'
1016
end

ios/ReactTestApp.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
1914199A234B2DD800D856AE /* RCTDevSupport+UIScene.m in Sources */ = {isa = PBXBuildFile; fileRef = 19141999234B2DD800D856AE /* RCTDevSupport+UIScene.m */; };
1111
192DD201240FCAF5004E9CEB /* Manifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192DD200240FCAF5004E9CEB /* Manifest.swift */; };
12+
193B614D27F5CD7D00080064 /* React+TurboModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 193B614B27F5CD7D00080064 /* React+TurboModule.mm */; };
1213
1963A06227C82E730013D276 /* React+Fabric.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1963A06127C82E730013D276 /* React+Fabric.mm */; };
1314
196C22622490CB7600449D3C /* React+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 196C22602490CB7600449D3C /* React+Compatibility.m */; };
1415
196C7215232F1788006556ED /* ReactInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196C7214232F1788006556ED /* ReactInstance.swift */; };
@@ -48,6 +49,8 @@
4849
192F052624AD3CC500A48456 /* ReactTestApp.release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReactTestApp.release.xcconfig; sourceTree = "<group>"; };
4950
192F052724AD3CC500A48456 /* ReactTestApp.common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReactTestApp.common.xcconfig; sourceTree = "<group>"; };
5051
192F052824AD3CC500A48456 /* ReactTestApp.debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReactTestApp.debug.xcconfig; sourceTree = "<group>"; };
52+
193B614B27F5CD7D00080064 /* React+TurboModule.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "React+TurboModule.mm"; sourceTree = "<group>"; };
53+
193B614C27F5CD7D00080064 /* React+TurboModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "React+TurboModule.h"; sourceTree = "<group>"; };
5154
1963A06027C82E730013D276 /* React+Fabric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "React+Fabric.h"; sourceTree = "<group>"; };
5255
1963A06127C82E730013D276 /* React+Fabric.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "React+Fabric.mm"; sourceTree = "<group>"; };
5356
196C22602490CB7600449D3C /* React+Compatibility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "React+Compatibility.m"; sourceTree = "<group>"; };
@@ -137,6 +140,8 @@
137140
196C22602490CB7600449D3C /* React+Compatibility.m */,
138141
1963A06027C82E730013D276 /* React+Fabric.h */,
139142
1963A06127C82E730013D276 /* React+Fabric.mm */,
143+
193B614C27F5CD7D00080064 /* React+TurboModule.h */,
144+
193B614B27F5CD7D00080064 /* React+TurboModule.mm */,
140145
1988282224105BCC005057FF /* UIViewController+ReactTestApp.h */,
141146
1988284424105BEC005057FF /* UIViewController+ReactTestApp.m */,
142147
19ECD0DB232ED427003D8557 /* Assets.xcassets */,
@@ -349,6 +354,7 @@
349354
1914199A234B2DD800D856AE /* RCTDevSupport+UIScene.m in Sources */,
350355
196C22622490CB7600449D3C /* React+Compatibility.m in Sources */,
351356
1963A06227C82E730013D276 /* React+Fabric.mm in Sources */,
357+
193B614D27F5CD7D00080064 /* React+TurboModule.mm in Sources */,
352358
196C7215232F1788006556ED /* ReactInstance.swift in Sources */,
353359
19ECD0D8232ED425003D8557 /* SceneDelegate.swift in Sources */,
354360
19A624A4258C95F000032776 /* Session.swift in Sources */,
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#if USE_TURBOMODULE
2+
3+
#import <React/RCTBridgeDelegate.h>
4+
5+
NS_ASSUME_NONNULL_BEGIN
6+
7+
@interface RTATurboModuleManagerDelegate : NSObject <RCTBridgeDelegate>
8+
- (instancetype)initWithBridgeDelegate:(id<RCTBridgeDelegate>)bridgeDelegate;
9+
@end
10+
11+
NS_ASSUME_NONNULL_END
12+
13+
#endif // USE_TURBOMODULE
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#import "React+TurboModule.h"
2+
3+
#if USE_TURBOMODULE
4+
5+
#import <React/CoreModulesPlugins.h>
6+
#import <React/RCTAppSetupUtils.h>
7+
#import <React/RCTCxxBridgeDelegate.h>
8+
#import <React/RCTDataRequestHandler.h>
9+
#import <React/RCTFileRequestHandler.h>
10+
#import <React/RCTGIFImageDecoder.h>
11+
#import <React/RCTHTTPRequestHandler.h>
12+
#import <React/RCTImageLoader.h>
13+
#import <React/RCTJSIExecutorRuntimeInstaller.h>
14+
#import <React/RCTLocalAssetImageLoader.h>
15+
#import <React/RCTNetworking.h>
16+
#import <ReactCommon/RCTTurboModuleManager.h>
17+
18+
@interface RTATurboModuleManagerDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate>
19+
@end
20+
21+
@implementation RTATurboModuleManagerDelegate {
22+
__weak id<RCTBridgeDelegate> _bridgeDelegate;
23+
RCTTurboModuleManager *_turboModuleManager;
24+
}
25+
26+
- (instancetype)initWithBridgeDelegate:(id<RCTBridgeDelegate>)bridgeDelegate
27+
{
28+
if (self = [super init]) {
29+
_bridgeDelegate = bridgeDelegate;
30+
}
31+
return self;
32+
}
33+
34+
// MARK: - RCTBridgeDelegate details
35+
36+
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
37+
{
38+
return [_bridgeDelegate sourceURLForBridge:bridge];
39+
}
40+
41+
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
42+
{
43+
return [_bridgeDelegate extraModulesForBridge:bridge];
44+
}
45+
46+
// MARK: - RCTCxxBridgeDelegate details
47+
48+
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:
49+
(RCTBridge *)bridge
50+
{
51+
if (_turboModuleManager == nil) {
52+
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
53+
delegate:self
54+
jsInvoker:bridge.jsCallInvoker];
55+
}
56+
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
57+
}
58+
59+
// MARK: - RCTTurboModuleManagerDelegate details
60+
61+
- (Class)getModuleClassFromName:(const char *)name
62+
{
63+
return RCTCoreModulesClassProvider(name);
64+
}
65+
66+
- (std::shared_ptr<facebook::react::TurboModule>)
67+
getTurboModule:(const std::string &)name
68+
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
69+
{
70+
return nullptr;
71+
}
72+
73+
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
74+
{
75+
return RCTAppSetupDefaultModuleFromClass(moduleClass);
76+
}
77+
78+
@end
79+
80+
#endif // USE_TURBOMODULE

0 commit comments

Comments
 (0)