Skip to content

Commit 8d652fb

Browse files
cortinicofacebook-github-bot
authored andcommitted
Setup a newArchEnabled property to Opt-in the New Architecture in the template (#32790)
Summary: Pull Request resolved: #32790 As the name says, I've added a `newArchEnabled` property that can be used to toggle the New Architecture in the new app template. Users can use this to try the New Architecture in their project by either: * Set `newArchEnabled` to true inside the `gradle.properties` file * Invoke gradle with `-PnewArchEnabled=true` * Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` The Project property will also control if: * ReactNative dependency should be built from source or not. * The NDK should be enabled or not. Please note that this requires RN 0.68.x to run properly (it won't work with 0.67 RCs) or a Nightly version of React Native. Changelog: [Android] [Added] - Setup a `newArchEnabled` property to Opt-in the New Architecture in the template Reviewed By: ShikaSD Differential Revision: D33065373 fbshipit-source-id: 32085f5b071d6243936bafd91425b5b43e5b5101
1 parent f142bfe commit 8d652fb

19 files changed

+599
-9
lines changed

settings.gradle.kts

-6
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,3 @@ include(
2121
// Include this to enable codegen Gradle plugin.
2222
includeBuild("packages/react-native-gradle-plugin/")
2323

24-
// Include this to build the Android template as well and make sure is not broken.
25-
if (File("template/node_modules/").exists()) {
26-
includeBuild("template/android/") {
27-
name = "template-android"
28-
}
29-
}

template/android/app/build.gradle

+66-2
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,56 @@ android {
139139
targetSdkVersion rootProject.ext.targetSdkVersion
140140
versionCode 1
141141
versionName "1.0"
142+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
143+
144+
if (isNewArchitectureEnabled()) {
145+
// We configure the NDK build only if you decide to opt-in for the New Architecture.
146+
externalNativeBuild {
147+
ndkBuild {
148+
arguments "APP_PLATFORM=android-21",
149+
"APP_STL=c++_shared",
150+
"NDK_TOOLCHAIN_VERSION=clang",
151+
"GENERATED_SRC_DIR=$buildDir/generated/source",
152+
"PROJECT_BUILD_DIR=$buildDir",
153+
"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
154+
"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build"
155+
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
156+
cppFlags "-std=c++17"
157+
// Make sure this target name is the same you specify inside the
158+
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
159+
targets "helloworld_appmodules"
160+
}
161+
}
162+
}
163+
}
164+
165+
if (isNewArchitectureEnabled()) {
166+
// We configure the NDK build only if you decide to opt-in for the New Architecture.
167+
externalNativeBuild {
168+
ndkBuild {
169+
path "$projectDir/src/main/jni/Android.mk"
170+
}
171+
}
172+
def reactAndroidProjectDir = project(':ReactAndroid').projectDir
173+
def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
174+
dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
175+
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
176+
into("$buildDir/react-ndk/exported")
177+
}
178+
def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
179+
dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
180+
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
181+
into("$buildDir/react-ndk/exported")
182+
}
183+
afterEvaluate {
184+
// If you wish to add a custom TurboModule or component locally,
185+
// you should uncomment this line.
186+
// preBuild.dependsOn("generateCodegenArtifactsFromSchema")
187+
preDebugBuild.dependsOn(packageReactNdkDebugLibs)
188+
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
189+
}
142190
}
191+
143192
splits {
144193
abi {
145194
reset()
@@ -193,8 +242,15 @@ android {
193242

194243
dependencies {
195244
implementation fileTree(dir: "libs", include: ["*.jar"])
196-
//noinspection GradleDynamicVersion
197-
implementation "com.facebook.react:react-native:+" // From node_modules
245+
246+
// If new architecture is enabled, we let you build RN from source
247+
// Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
248+
if (isNewArchitectureEnabled()) {
249+
implementation project(":ReactAndroid")
250+
} else {
251+
//noinspection GradleDynamicVersion
252+
implementation "com.facebook.react:react-native:+" // From node_modules
253+
}
198254

199255
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
200256

@@ -228,3 +284,11 @@ task copyDownloadableDepsToLibs(type: Copy) {
228284
}
229285

230286
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
287+
288+
def isNewArchitectureEnabled() {
289+
// To opt-in for the New Architecture, you can either:
290+
// - Set `newArchEnabled` to true inside the `gradle.properties` file
291+
// - Invoke gradle with `-newArchEnabled=true`
292+
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
293+
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
294+
}

template/android/app/src/main/java/com/helloworld/MainActivity.java

+25
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.helloworld;
22

33
import com.facebook.react.ReactActivity;
4+
import com.facebook.react.ReactActivityDelegate;
5+
import com.facebook.react.ReactRootView;
46

57
public class MainActivity extends ReactActivity {
68

@@ -12,4 +14,27 @@ public class MainActivity extends ReactActivity {
1214
protected String getMainComponentName() {
1315
return "HelloWorld";
1416
}
17+
18+
/**
19+
* Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
20+
* you can specify the rendered you wish to use (Fabric or the older renderer).
21+
*/
22+
@Override
23+
protected ReactActivityDelegate createReactActivityDelegate() {
24+
return new MainActivityDelegate(this, getMainComponentName());
25+
}
26+
27+
public static class MainActivityDelegate extends ReactActivityDelegate {
28+
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
29+
super(activity, mainComponentName);
30+
}
31+
32+
@Override
33+
protected ReactRootView createRootView() {
34+
ReactRootView reactRootView = new ReactRootView(getContext());
35+
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
36+
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
37+
return reactRootView;
38+
}
39+
}
1540
}

template/android/app/src/main/java/com/helloworld/MainApplication.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
import com.facebook.react.ReactInstanceManager;
88
import com.facebook.react.ReactNativeHost;
99
import com.facebook.react.ReactPackage;
10+
import com.facebook.react.config.ReactFeatureFlags;
1011
import com.facebook.soloader.SoLoader;
12+
import com.helloworld.newarchitecture.MainApplicationReactNativeHost;
1113
import java.lang.reflect.InvocationTargetException;
1214
import java.util.List;
1315

@@ -35,14 +37,23 @@ protected String getJSMainModuleName() {
3537
}
3638
};
3739

40+
private final ReactNativeHost mNewArchitectureNativeHost =
41+
new MainApplicationReactNativeHost(this);
42+
3843
@Override
3944
public ReactNativeHost getReactNativeHost() {
40-
return mReactNativeHost;
45+
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
46+
return mNewArchitectureNativeHost;
47+
} else {
48+
return mReactNativeHost;
49+
}
4150
}
4251

4352
@Override
4453
public void onCreate() {
4554
super.onCreate();
55+
// If you opted-in for the New Architecture, we enable the TurboModule system
56+
ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
4657
SoLoader.init(this, /* native exopackage */ false);
4758
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
4859
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package com.helloworld.newarchitecture;
2+
3+
import android.app.Application;
4+
import androidx.annotation.NonNull;
5+
import com.facebook.react.PackageList;
6+
import com.facebook.react.ReactInstanceManager;
7+
import com.facebook.react.ReactNativeHost;
8+
import com.facebook.react.ReactPackage;
9+
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
10+
import com.facebook.react.bridge.JSIModulePackage;
11+
import com.facebook.react.bridge.JSIModuleProvider;
12+
import com.facebook.react.bridge.JSIModuleSpec;
13+
import com.facebook.react.bridge.JSIModuleType;
14+
import com.facebook.react.bridge.JavaScriptContextHolder;
15+
import com.facebook.react.bridge.ReactApplicationContext;
16+
import com.facebook.react.bridge.UIManager;
17+
import com.facebook.react.fabric.ComponentFactory;
18+
import com.facebook.react.fabric.CoreComponentsRegistry;
19+
import com.facebook.react.fabric.EmptyReactNativeConfig;
20+
import com.facebook.react.fabric.FabricJSIModuleProvider;
21+
import com.facebook.react.uimanager.ViewManagerRegistry;
22+
import com.helloworld.BuildConfig;
23+
import com.helloworld.newarchitecture.components.MainComponentsRegistry;
24+
import com.helloworld.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
28+
/**
29+
* A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
30+
* TurboModule delegates and the Fabric Renderer.
31+
*
32+
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
33+
* `newArchEnabled` property). Is ignored otherwise.
34+
*/
35+
public class MainApplicationReactNativeHost extends ReactNativeHost {
36+
public MainApplicationReactNativeHost(Application application) {
37+
super(application);
38+
}
39+
40+
@Override
41+
public boolean getUseDeveloperSupport() {
42+
return BuildConfig.DEBUG;
43+
}
44+
45+
@Override
46+
protected List<ReactPackage> getPackages() {
47+
List<ReactPackage> packages = new PackageList(this).getPackages();
48+
// Packages that cannot be autolinked yet can be added manually here, for example:
49+
// packages.add(new MyReactNativePackage());
50+
// TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
51+
// packages.add(new TurboReactPackage() { ... });
52+
// If you have custom Fabric Components, their ViewManagers should also be loaded here
53+
// inside a ReactPackage.
54+
return packages;
55+
}
56+
57+
@Override
58+
protected String getJSMainModuleName() {
59+
return "index";
60+
}
61+
62+
@NonNull
63+
@Override
64+
protected ReactPackageTurboModuleManagerDelegate.Builder
65+
getReactPackageTurboModuleManagerDelegateBuilder() {
66+
// Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
67+
// for the new architecture and to use TurboModules correctly.
68+
return new MainApplicationTurboModuleManagerDelegate.Builder();
69+
}
70+
71+
@Override
72+
protected JSIModulePackage getJSIModulePackage() {
73+
return new JSIModulePackage() {
74+
@Override
75+
public List<JSIModuleSpec> getJSIModules(
76+
final ReactApplicationContext reactApplicationContext,
77+
final JavaScriptContextHolder jsContext) {
78+
final List<JSIModuleSpec> specs = new ArrayList<>();
79+
80+
// Here we provide a new JSIModuleSpec that will be responsible of providing the
81+
// custom Fabric Components.
82+
specs.add(
83+
new JSIModuleSpec() {
84+
@Override
85+
public JSIModuleType getJSIModuleType() {
86+
return JSIModuleType.UIManager;
87+
}
88+
89+
@Override
90+
public JSIModuleProvider<UIManager> getJSIModuleProvider() {
91+
final ComponentFactory componentFactory = new ComponentFactory();
92+
CoreComponentsRegistry.register(componentFactory);
93+
94+
// Here we register a Components Registry.
95+
// The one that is generated with the template contains no components
96+
// and just provides you the one from React Native core.
97+
MainComponentsRegistry.register(componentFactory);
98+
99+
final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
100+
101+
ViewManagerRegistry viewManagerRegistry =
102+
new ViewManagerRegistry(
103+
reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
104+
105+
return new FabricJSIModuleProvider(
106+
reactApplicationContext,
107+
componentFactory,
108+
new EmptyReactNativeConfig(),
109+
viewManagerRegistry);
110+
}
111+
});
112+
return specs;
113+
}
114+
};
115+
}
116+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.helloworld.newarchitecture.components;
2+
3+
import com.facebook.jni.HybridData;
4+
import com.facebook.proguard.annotations.DoNotStrip;
5+
import com.facebook.react.fabric.ComponentFactory;
6+
import com.facebook.soloader.SoLoader;
7+
8+
/**
9+
* Class responsible to load the custom Fabric Components. This class has native methods and needs a
10+
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
11+
* folder for you).
12+
*
13+
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
14+
* `newArchEnabled` property). Is ignored otherwise.
15+
*/
16+
@DoNotStrip
17+
public class MainComponentsRegistry {
18+
static {
19+
SoLoader.loadLibrary("fabricjni");
20+
}
21+
22+
@DoNotStrip private final HybridData mHybridData;
23+
24+
@DoNotStrip
25+
private native HybridData initHybrid(ComponentFactory componentFactory);
26+
27+
@DoNotStrip
28+
private MainComponentsRegistry(ComponentFactory componentFactory) {
29+
mHybridData = initHybrid(componentFactory);
30+
}
31+
32+
@DoNotStrip
33+
public static MainComponentsRegistry register(ComponentFactory componentFactory) {
34+
return new MainComponentsRegistry(componentFactory);
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.helloworld.newarchitecture.modules;
2+
3+
import com.facebook.jni.HybridData;
4+
import com.facebook.react.ReactPackage;
5+
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
6+
import com.facebook.react.bridge.ReactApplicationContext;
7+
import com.facebook.soloader.SoLoader;
8+
import java.util.List;
9+
10+
/**
11+
* Class responsible to load the TurboModules. This class has native methods and needs a
12+
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
13+
* folder for you).
14+
*
15+
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
16+
* `newArchEnabled` property). Is ignored otherwise.
17+
*/
18+
public class MainApplicationTurboModuleManagerDelegate
19+
extends ReactPackageTurboModuleManagerDelegate {
20+
21+
private static volatile boolean sIsSoLibraryLoaded;
22+
23+
protected MainApplicationTurboModuleManagerDelegate(
24+
ReactApplicationContext reactApplicationContext, List<ReactPackage> packages) {
25+
super(reactApplicationContext, packages);
26+
}
27+
28+
protected native HybridData initHybrid();
29+
30+
native boolean canCreateTurboModule(String moduleName);
31+
32+
public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
33+
protected MainApplicationTurboModuleManagerDelegate build(
34+
ReactApplicationContext context, List<ReactPackage> packages) {
35+
return new MainApplicationTurboModuleManagerDelegate(context, packages);
36+
}
37+
}
38+
39+
@Override
40+
protected synchronized void maybeLoadOtherSoLibraries() {
41+
if (!sIsSoLibraryLoaded) {
42+
// If you change the name of your application .so file in the Android.mk file,
43+
// make sure you update the name here as well.
44+
SoLoader.loadLibrary("helloworld_appmodules");
45+
sIsSoLibraryLoaded = true;
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)