Skip to content

Commit d7b64b8

Browse files
cortinicofacebook-github-bot
authored andcommitted
Expose an API to enable Concurrent Root on Android (#33645)
Summary: Pull Request resolved: #33645 With React 18, we now need to allow users on Fabric to opt-in for Concurrent Root. This commit adds a new method that can be called on the ReactActivityDelegate that can be used to set the `concurrentRoot` flag on the `initialProps` on the Render. Changelog: [Android] [Added] - Expose an API to enable Concurrent Root on Android Reviewed By: mdvacca Differential Revision: D35614879 fbshipit-source-id: 2de83e8115d3748c0346cdec6f31b2ab1f899478
1 parent a129595 commit d7b64b8

File tree

4 files changed

+107
-1
lines changed

4 files changed

+107
-1
lines changed

ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java

+33-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import android.os.Build;
1616
import android.os.Bundle;
1717
import android.view.KeyEvent;
18+
import androidx.annotation.NonNull;
1819
import androidx.annotation.Nullable;
1920
import com.facebook.infer.annotation.Assertions;
2021
import com.facebook.react.bridge.Callback;
@@ -33,6 +34,7 @@ public class ReactActivityDelegate {
3334
private @Nullable PermissionListener mPermissionListener;
3435
private @Nullable Callback mPermissionsCallback;
3536
private ReactDelegate mReactDelegate;
37+
private boolean mConcurrentRootEnabled;
3638

3739
@Deprecated
3840
public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) {
@@ -45,10 +47,27 @@ public ReactActivityDelegate(ReactActivity activity, @Nullable String mainCompon
4547
mMainComponentName = mainComponentName;
4648
}
4749

50+
/**
51+
* Public API to populate the launch options that will be passed to React. Here you can customize
52+
* the values that will be passed as `initialProperties` to the Renderer.
53+
*
54+
* @return Either null or a key-value map as a Bundle
55+
*/
4856
protected @Nullable Bundle getLaunchOptions() {
4957
return null;
5058
}
5159

60+
private @NonNull Bundle composeLaunchOptions() {
61+
Bundle composedLaunchOptions = getLaunchOptions();
62+
if (isConcurrentRootEnabled()) {
63+
if (composedLaunchOptions == null) {
64+
composedLaunchOptions = new Bundle();
65+
}
66+
composedLaunchOptions.putBoolean("concurrentRoot", true);
67+
}
68+
return composedLaunchOptions;
69+
}
70+
5271
protected ReactRootView createRootView() {
5372
return new ReactRootView(getContext());
5473
}
@@ -74,9 +93,10 @@ public String getMainComponentName() {
7493

7594
protected void onCreate(Bundle savedInstanceState) {
7695
String mainComponentName = getMainComponentName();
96+
Bundle launchOptions = composeLaunchOptions();
7797
mReactDelegate =
7898
new ReactDelegate(
79-
getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions()) {
99+
getPlainActivity(), getReactNativeHost(), mainComponentName, launchOptions) {
80100
@Override
81101
protected ReactRootView createRootView() {
82102
return ReactActivityDelegate.this.createRootView();
@@ -190,4 +210,16 @@ protected Context getContext() {
190210
protected Activity getPlainActivity() {
191211
return ((Activity) getContext());
192212
}
213+
214+
/**
215+
* Override this method to enable Concurrent Root on the surface for this Activity. See:
216+
* https://reactjs.org/blog/2022/03/29/react-v18.html
217+
*
218+
* <p>This requires to be rendering on Fabric (i.e. on the New Architecture).
219+
*
220+
* @return Wether you want to enable Concurrent Root for this surface or not.
221+
*/
222+
protected boolean isConcurrentRootEnabled() {
223+
return false;
224+
}
193225
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react
9+
10+
import android.os.Bundle
11+
import org.junit.Assert.*
12+
import org.junit.Test
13+
import org.junit.runner.RunWith
14+
import org.robolectric.RobolectricTestRunner
15+
16+
@RunWith(RobolectricTestRunner::class)
17+
class ReactActivityDelegateTest {
18+
19+
@Test
20+
fun delegateWithConcurrentRoot_populatesInitialPropsCorrectly() {
21+
val delegate =
22+
object : ReactActivityDelegate(null, "test-delegate") {
23+
override fun isConcurrentRootEnabled() = true
24+
public val inspectLaunchOptions: Bundle?
25+
get() = getLaunchOptions()
26+
}
27+
28+
assertNotNull(delegate.inspectLaunchOptions)
29+
assertTrue(delegate.inspectLaunchOptions!!.containsKey("concurrentRoot"))
30+
assertTrue(delegate.inspectLaunchOptions!!.getBoolean("concurrentRoot"))
31+
}
32+
33+
@Test
34+
fun delegateWithoutConcurrentRoot_hasNullInitialProperties() {
35+
val delegate =
36+
object : ReactActivityDelegate(null, "test-delegate") {
37+
override fun isConcurrentRootEnabled() = false
38+
public val inspectLaunchOptions: Bundle?
39+
get() = getLaunchOptions()
40+
}
41+
42+
assertNull(delegate.inspectLaunchOptions)
43+
}
44+
45+
@Test
46+
fun delegateWithConcurrentRoot_composesInitialPropertiesCorrectly() {
47+
val delegate =
48+
object : ReactActivityDelegate(null, "test-delegate") {
49+
override fun isConcurrentRootEnabled() = true
50+
override fun getLaunchOptions(): Bundle =
51+
Bundle().apply { putString("test-property", "test-value") }
52+
public val inspectLaunchOptions: Bundle?
53+
get() = getLaunchOptions()
54+
}
55+
56+
assertNotNull(delegate.inspectLaunchOptions)
57+
assertTrue(delegate.inspectLaunchOptions!!.containsKey("concurrentRoot"))
58+
assertTrue(delegate.inspectLaunchOptions!!.getBoolean("concurrentRoot"))
59+
assertTrue(delegate.inspectLaunchOptions!!.containsKey("test-property"))
60+
assertEquals("test-value", delegate.inspectLaunchOptions!!.getString("test-property"))
61+
}
62+
}

packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterActivity.java

+5
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ protected void onCreate(Bundle savedInstanceState) {
5151
protected Bundle getLaunchOptions() {
5252
return mInitialProps;
5353
}
54+
55+
@Override
56+
protected boolean isConcurrentRootEnabled() {
57+
return true;
58+
}
5459
}
5560

5661
@Override

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

+7
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,12 @@ protected ReactRootView createRootView() {
3737
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
3838
return reactRootView;
3939
}
40+
41+
@Override
42+
protected boolean isConcurrentRootEnabled() {
43+
// If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
44+
// More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
45+
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
46+
}
4047
}
4148
}

0 commit comments

Comments
 (0)