mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
[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:
@@ -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)
|
||||
}
|
||||
|
||||
+42
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+65
@@ -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)
|
||||
}
|
||||
}
|
||||
-11
@@ -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";
|
||||
|
||||
+5
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+3
-9
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -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;
|
||||
}
|
||||
|
||||
+5
@@ -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(
|
||||
|
||||
+41
-4
@@ -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<>());
|
||||
|
||||
+9
-10
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user