[0.73] Collection of Android picks for RC4 (#41221)

Co-authored-by: Lulu Wu <luluwu@meta.com>
Co-authored-by: Gabriel Donadel <donadeldev@gmail.com>
fix `java.lang.NoSuchMethodError` for Bridgeless (#41081)
resolved: https://github.com/facebook/react-native/pull/41081
resolved: https://github.com/facebook/react-native/pull/40999
resolved: https://github.com/facebook/react-native/pull/41165
Fix RNTester not showing Redbox when Metro is not connected (#41191)
resolved: https://github.com/facebook/react-native/pull/41191
resolved: https://github.com/facebook/react-native/pull/41190
resolved: https://github.com/facebook/react-native/pull/41085
resolved: https://github.com/facebook/react-native/pull/41206
This commit is contained in:
Nicola Corti
2023-11-02 09:23:15 -07:00
committed by GitHub
parent 2664b8b117
commit c8ad23ae1a
11 changed files with 177 additions and 37 deletions
@@ -15,6 +15,7 @@ import com.facebook.react.tasks.GenerateCodegenSchemaTask
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFieldsForApp
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFieldsForLibraries
import com.facebook.react.utils.AgpConfiguratorUtils.configureDevPorts
import com.facebook.react.utils.AgpConfiguratorUtils.configureNamespaceForLibraries
import com.facebook.react.utils.BackwardCompatUtils.configureBackwardCompatibilityReactMap
import com.facebook.react.utils.DependencyUtils.configureDependencies
import com.facebook.react.utils.DependencyUtils.configureRepositories
@@ -80,6 +81,7 @@ class ReactPlugin : Plugin<Project> {
// Library Only Configuration
configureBuildConfigFieldsForLibraries(project)
configureNamespaceForLibraries(project)
project.pluginManager.withPlugin("com.android.library") {
configureCodegen(project, extension, rootExtension, isLibrary = true)
}
@@ -8,12 +8,17 @@
package com.facebook.react.utils
import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.gradle.LibraryExtension
import com.facebook.react.ReactExtension
import com.facebook.react.utils.ProjectUtils.isHermesEnabled
import com.facebook.react.utils.ProjectUtils.isNewArchEnabled
import java.io.File
import javax.xml.parsers.DocumentBuilder
import javax.xml.parsers.DocumentBuilderFactory
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.plugins.AppliedPlugin
import org.w3c.dom.Element
@Suppress("UnstableApiUsage")
internal object AgpConfiguratorUtils {
@@ -63,6 +68,43 @@ internal object AgpConfiguratorUtils {
project.pluginManager.withPlugin("com.android.application", action)
project.pluginManager.withPlugin("com.android.library", action)
}
fun configureNamespaceForLibraries(appProject: Project) {
appProject.rootProject.allprojects { subproject ->
subproject.pluginManager.withPlugin("com.android.library") {
subproject.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext ->
if (ext.namespace == null) {
val android = subproject.extensions.getByType(LibraryExtension::class.java)
val manifestFile = android.sourceSets.getByName("main").manifest.srcFile
manifestFile
.takeIf { it.exists() }
?.let { file ->
getPackageNameFromManifest(file)?.let { packageName ->
ext.namespace = packageName
}
}
}
}
}
}
}
}
const val DEFAULT_DEV_SERVER_PORT = "8081"
fun getPackageNameFromManifest(manifest: File): String? {
val factory: DocumentBuilderFactory = DocumentBuilderFactory.newInstance()
val builder: DocumentBuilder = factory.newDocumentBuilder()
try {
val xmlDocument = builder.parse(manifest)
val manifestElement = xmlDocument.getElementsByTagName("manifest").item(0) as? Element
val packageName = manifestElement?.getAttribute("package")
return if (packageName.isNullOrEmpty()) null else packageName
} catch (e: Exception) {
return null
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.utils
import java.io.File
import org.junit.Assert.*
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
class AgpConfiguratorUtilsTest {
@get:Rule val tempFolder = TemporaryFolder()
@Test
fun getPackageNameFromManifest_withEmptyFile_returnsNull() {
val mainFolder = tempFolder.newFolder("awesome-module/src/main/")
val manifest = File(mainFolder, "AndroidManifest.xml").apply { writeText("") }
val actual = getPackageNameFromManifest(manifest)
assertNull(actual)
}
@Test
fun getPackageNameFromManifest_withMissingPackage_returnsNull() {
val mainFolder = tempFolder.newFolder("awesome-module/src/main/")
val manifest =
File(mainFolder, "AndroidManifest.xml").apply {
writeText(
// language=xml
"""
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
"""
.trimIndent())
}
val actual = getPackageNameFromManifest(manifest)
assertNull(actual)
}
@Test
fun getPackageNameFromManifest_withPackage_returnsPackage() {
val mainFolder = tempFolder.newFolder("awesome-module/src/main/")
val manifest =
File(mainFolder, "AndroidManifest.xml").apply {
writeText(
// language=xml
"""
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.facebook.react" >
</manifest>
"""
.trimIndent())
}
val actual = getPackageNameFromManifest(manifest)
assertNotNull(actual)
assertEquals("com.facebook.react", actual)
}
}
@@ -86,9 +86,6 @@ public final class BridgeDevSupportManager extends DevSupportManagerBase {
surfaceDelegateFactory,
devLoadingViewManager);
mReactInstanceManagerHelper = reactInstanceManagerHelper;
mDevLoadingViewManager = devLoadingViewManager;
if (getDevSettings().isStartSamplingProfilerOnInit()) {
// Only start the profiler. If its already running, there is an error
if (!mIsSamplingProfilerEnabled) {
@@ -112,14 +109,6 @@ public final class BridgeDevSupportManager extends DevSupportManagerBase {
});
}
public DevLoadingViewManager getDevLoadingViewManager() {
return mDevLoadingViewManager;
}
public ReactInstanceDevHelper getReactInstanceManagerHelper() {
return mReactInstanceManagerHelper;
}
@Override
protected String getUniqueTag() {
return "Bridge";
@@ -695,7 +695,11 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
return mDevServerHelper;
}
protected ReactInstanceDevHelper getReactInstanceDevHelper() {
public DevLoadingViewManager getDevLoadingViewManager() {
return mDevLoadingViewManager;
}
public ReactInstanceDevHelper getReactInstanceDevHelper() {
return mReactInstanceDevHelper;
}
@@ -13,8 +13,7 @@ import com.facebook.react.bridge.JSExceptionHandler;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.devsupport.BridgeDevSupportManager;
import com.facebook.react.devsupport.DefaultDevLoadingViewImplementation;
import com.facebook.react.devsupport.DevSupportManagerBase;
import com.facebook.react.devsupport.interfaces.DevLoadingViewManager;
import com.facebook.react.module.annotations.ReactModule;
@@ -28,14 +27,9 @@ public class DevLoadingModule extends NativeDevLoadingViewSpec {
public DevLoadingModule(ReactApplicationContext reactContext) {
super(reactContext);
mJSExceptionHandler = reactContext.getJSExceptionHandler();
if (mJSExceptionHandler != null && mJSExceptionHandler instanceof BridgeDevSupportManager) {
if (mJSExceptionHandler != null && mJSExceptionHandler instanceof DevSupportManagerBase) {
mDevLoadingViewManager =
((BridgeDevSupportManager) mJSExceptionHandler).getDevLoadingViewManager();
mDevLoadingViewManager =
mDevLoadingViewManager != null
? mDevLoadingViewManager
: new DefaultDevLoadingViewImplementation(
((BridgeDevSupportManager) mJSExceptionHandler).getReactInstanceManagerHelper());
((DevSupportManagerBase) mJSExceptionHandler).getDevLoadingViewManager();
}
}
@@ -9,13 +9,15 @@ package com.facebook.react.runtime;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.jni.HybridData;
import com.facebook.jni.annotations.DoNotStrip;
import com.facebook.jni.annotations.DoNotStripAny;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.modules.core.JavaScriptTimerExecutor;
import com.facebook.soloader.SoLoader;
@Nullsafe(Nullsafe.Mode.LOCAL)
@DoNotStripAny
class JSTimerExecutor implements JavaScriptTimerExecutor {
static {
@@ -24,6 +26,7 @@ class JSTimerExecutor implements JavaScriptTimerExecutor {
@DoNotStrip private final HybridData mHybridData;
@DoNotStrip
public JSTimerExecutor(HybridData hybridData) {
mHybridData = hybridData;
}
@@ -638,6 +638,9 @@ public class ReactHostImpl implements ReactHost {
final String method = "handleHostException(message = \"" + e.getMessage() + "\")";
log(method);
if (DEV) {
mDevSupportManager.handleException(e);
}
destroy(method, e);
mReactHostDelegate.handleInstanceException(e);
}
@@ -922,6 +925,7 @@ public class ReactHostImpl implements ReactHost {
final JSBundleLoader bundleLoader = task.getResult();
final BridgelessReactContext reactContext = getOrCreateReactContext();
final DevSupportManager devSupportManager = getDevSupportManager();
reactContext.setJSExceptionHandler(devSupportManager);
log(method, "Creating ReactInstance");
final ReactInstance instance =
@@ -1036,6 +1040,7 @@ public class ReactHostImpl implements ReactHost {
final BridgelessReactContext reactContext = getOrCreateReactContext();
final DevSupportManager devSupportManager = getDevSupportManager();
reactContext.setJSExceptionHandler(devSupportManager);
return getJsBundleLoader()
.onSuccess(
@@ -71,6 +71,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nullable;
/**
@@ -93,6 +94,7 @@ final class ReactInstance {
private final TurboModuleManager mTurboModuleManager;
private final FabricUIManager mFabricUIManager;
private final JavaTimerManager mJavaTimerManager;
private final Map<String, ViewManager> mViewManagers = new ConcurrentHashMap<>();
@DoNotStrip @Nullable private ComponentNameResolverManager mComponentNameResolverManager;
@DoNotStrip @Nullable private UIConstantsProviderManager mUIConstantsProviderManager;
@@ -489,8 +491,12 @@ final class ReactInstance {
}
private @Nullable ViewManager createViewManager(String viewManagerName) {
// Return cached view manager if available, no matter it's eagerly or lazily loaded
if (mViewManagers.containsKey(viewManagerName)) {
return mViewManagers.get(viewManagerName);
}
List<ReactPackage> packages = mReactPackages;
if (mDelegate != null) {
List<ReactPackage> packages = mReactPackages;
if (packages != null) {
synchronized (packages) {
for (ReactPackage reactPackage : packages) {
@@ -499,6 +505,7 @@ final class ReactInstance {
((ViewManagerOnDemandReactPackage) reactPackage)
.createViewManager(mBridgelessReactContext, viewManagerName);
if (viewManager != null) {
mViewManagers.put(viewManagerName, viewManager);
return viewManager;
}
}
@@ -507,7 +514,17 @@ final class ReactInstance {
}
}
return null;
// Once a view manager is not found in all react packages via lazy loading, fall back to default
// implementation: eagerly initialize all view managers
for (ReactPackage reactPackage : packages) {
List<ViewManager> viewManagersInPackage =
reactPackage.createViewManagers(mBridgelessReactContext);
for (ViewManager viewManager : viewManagersInPackage) {
mViewManagers.put(viewManager.getName(), viewManager);
}
}
return mViewManagers.get(viewManagerName);
}
private @NonNull Collection<String> getViewManagerNames() {
@@ -534,8 +551,28 @@ final class ReactInstance {
private @NonNull NativeMap getUIManagerConstants() {
List<ViewManager> viewManagers = new ArrayList<ViewManager>();
for (String viewManagerName : getViewManagerNames()) {
viewManagers.add(createViewManager(viewManagerName));
boolean canLoadViewManagersLazily = true;
List<ReactPackage> packages = mReactPackages;
for (ReactPackage reactPackage : packages) {
if (!(reactPackage instanceof ViewManagerOnDemandReactPackage)) {
canLoadViewManagersLazily = false;
break;
}
}
// 1, Retrive view managers via on demand loading
if (canLoadViewManagersLazily) {
for (String viewManagerName : getViewManagerNames()) {
viewManagers.add(createViewManager(viewManagerName));
}
} else {
// 2, There are packages that don't implement ViewManagerOnDemandReactPackage so we retrieve
// view managers via eager loading
for (ReactPackage reactPackage : packages) {
List<ViewManager> viewManagersInPackage =
reactPackage.createViewManagers(mBridgelessReactContext);
viewManagers.addAll(viewManagersInPackage);
}
}
Map<String, Object> constants =
UIManagerModule.createConstants(viewManagers, new HashMap<>(), new HashMap<>());
@@ -22,9 +22,9 @@ import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactNoCrashSoftException;
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.bridge.UIManager;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.uimanager.common.UIManagerType;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.react.uimanager.events.EventDispatcherProvider;
/** Helper class for {@link UIManager}. */
public class UIManagerHelper {
@@ -53,13 +53,19 @@ public class UIManagerHelper {
@UIManagerType int uiManagerType,
boolean returnNullIfCatalystIsInactive) {
if (context.isBridgeless()) {
@Nullable UIManager uiManager = (UIManager) context.getJSIModule(JSIModuleType.UIManager);
UIManager uiManager = null;
if (uiManagerType == FABRIC) {
uiManager = (UIManager) context.getJSIModule(JSIModuleType.UIManager);
} else if (ReactFeatureFlags.unstable_useFabricInterop) {
// When Fabric Interop is enabled in Bridgeless mode, enable the legacy UIManager
uiManager = context.getNativeModule(UIManagerModule.class);
}
if (uiManager == null) {
ReactSoftExceptionLogger.logSoftException(
TAG,
new ReactNoCrashSoftException(
"Cannot get UIManager because the instance hasn't been initialized yet."));
return null;
}
return uiManager;
}
@@ -118,13 +124,6 @@ public class UIManagerHelper {
@Nullable
public static EventDispatcher getEventDispatcher(
ReactContext context, @UIManagerType int uiManagerType) {
// TODO T67518514 Clean this up once we migrate everything over to bridgeless mode
if (context.isBridgeless()) {
if (context instanceof ThemedReactContext) {
context = ((ThemedReactContext) context).getReactApplicationContext();
}
return ((EventDispatcherProvider) context).getEventDispatcher();
}
UIManager uiManager = getUIManager(context, uiManagerType, false);
if (uiManager == null) {
ReactSoftExceptionLogger.logSoftException(
@@ -16,7 +16,7 @@ assertj = "3.21.0"
download = "5.4.0"
fbjni = "0.5.1"
flipper = "0.201.0"
fresco = "3.1.0"
fresco = "3.1.3"
infer-annotation = "0.18.0"
javax-inject = "1"
jsr305 = "3.0.2"