Android: Introduce RN$LegacyInterop_UIManager_getConstants (#38153)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/38153

This diff adds Android specific implementation of `RN$LegacyInterop_UIManager_getConstants` and binds it to JS runtime. It is supposed to be used as a substitute to UIManager.getConstants in bridgeless mode.

Changelog:
[Internal] - Introduce RN$LegacyInterop_UIManager_getConstants in Android.

Reviewed By: RSNara

Differential Revision: D45773342

fbshipit-source-id: 194aa5e940743b4d2c242798764a4207e8b1334f
This commit is contained in:
Dmitry Rykun
2023-07-19 10:09:03 -07:00
committed by Facebook GitHub Bot
parent 6eeb81a86e
commit f7f5b4913a
11 changed files with 238 additions and 1 deletions
@@ -19,10 +19,12 @@ import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.BridgelessReactPackage;
import com.facebook.react.ReactPackage;
import com.facebook.react.ViewManagerOnDemandReactPackage;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.JSBundleLoader;
import com.facebook.react.bridge.JSBundleLoaderDelegate;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.NativeArray;
import com.facebook.react.bridge.NativeMap;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.bridge.RuntimeExecutor;
@@ -33,6 +35,7 @@ import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
import com.facebook.react.bridge.queue.ReactQueueConfiguration;
import com.facebook.react.bridge.queue.ReactQueueConfigurationImpl;
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
import com.facebook.react.fabric.Binding;
import com.facebook.react.fabric.BindingImpl;
@@ -52,6 +55,9 @@ import com.facebook.react.uimanager.ComponentNameResolver;
import com.facebook.react.uimanager.ComponentNameResolverManager;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.facebook.react.uimanager.UIConstantsProvider;
import com.facebook.react.uimanager.UIConstantsProviderManager;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.uimanager.ViewManagerRegistry;
import com.facebook.react.uimanager.ViewManagerResolver;
@@ -60,8 +66,10 @@ import com.facebook.soloader.SoLoader;
import com.facebook.systrace.Systrace;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
@@ -87,6 +95,7 @@ final class ReactInstance {
private final JavaTimerManager mJavaTimerManager;
@DoNotStrip @Nullable private ComponentNameResolverManager mComponentNameResolverManager;
@DoNotStrip @Nullable private UIConstantsProviderManager mUIConstantsProviderManager;
static {
loadLibraryIfNeeded();
@@ -220,6 +229,27 @@ final class ReactInstance {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
// Initialize function for JS's UIManager.getViewManagerConfig()
// It should come after getTurboModuleManagerDelegate as it relies on react packages being
// initialized.
// This happens inside getTurboModuleManagerDelegate getter.
if (ReactFeatureFlags.useNativeViewConfigsInBridgelessMode) {
mUIConstantsProviderManager =
new UIConstantsProviderManager(
// Use unbuffered RuntimeExecutor to install binding
unbufferedRuntimeExecutor,
// Here we are construncting the return value for UIManager.getConstants call.
// The old architectre relied on the constatnts struct to contain:
// 1. Eagerly loaded view configs for all native components.
// 2. genericBubblingEventTypes.
// 3. genericDirectEventTypes.
// We want to match this beahavior.
(UIConstantsProvider)
() -> {
return getUIManagerConstants();
});
}
// Set up Fabric
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstance.initialize#initFabric");
@@ -388,6 +418,7 @@ final class ReactInstance {
mFabricUIManager.onCatalystInstanceDestroy();
mHybridData.resetNative();
mComponentNameResolverManager = null;
mUIConstantsProviderManager = null;
}
/* --- Native methods --- */
@@ -500,4 +531,14 @@ final class ReactInstance {
}
return uniqueNames;
}
private @NonNull NativeMap getUIManagerConstants() {
List<ViewManager> viewManagers = new ArrayList<ViewManager>();
for (String viewManagerName : getViewManagerNames()) {
viewManagers.add(createViewManager(viewManagerName));
}
Map<String, Object> constants =
UIManagerModule.createConstants(viewManagers, new HashMap<>(), new HashMap<>());
return Arguments.makeNativeMap(constants);
}
}
@@ -154,4 +154,7 @@ public class ReactFeatureFlags {
/** Disable the background executor for layout in Fabric */
public static boolean enableBackgroundExecutor = false;
/** Use native view configs in bridgeless mode. */
public static boolean useNativeViewConfigsInBridgelessMode = false;
}
@@ -0,0 +1,18 @@
/*
* 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.uimanager;
import com.facebook.proguard.annotations.DoNotStripAny;
import com.facebook.react.bridge.NativeMap;
@DoNotStripAny
public interface UIConstantsProvider {
/* Returns UIManager's constants. */
NativeMap getConstants();
}
@@ -0,0 +1,41 @@
/*
* 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.uimanager;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.proguard.annotations.DoNotStripAny;
import com.facebook.react.bridge.RuntimeExecutor;
import com.facebook.soloader.SoLoader;
@DoNotStripAny
public class UIConstantsProviderManager {
static {
staticInit();
}
@DoNotStrip
@SuppressWarnings("unused")
private final HybridData mHybridData;
public UIConstantsProviderManager(
RuntimeExecutor runtimeExecutor, Object uiConstantsProviderManager) {
mHybridData = initHybrid(runtimeExecutor, uiConstantsProviderManager);
installJSIBindings();
}
private native HybridData initHybrid(
RuntimeExecutor runtimeExecutor, Object uiConstantsProviderManager);
private native void installJSIBindings();
private static void staticInit() {
SoLoader.loadLibrary("uimanagerjni");
}
}
@@ -229,7 +229,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule
}
}
private static Map<String, Object> createConstants(
public static Map<String, Object> createConstants(
List<ViewManager> viewManagers,
@Nullable Map<String, Object> customBubblingEvents,
@Nullable Map<String, Object> customDirectEvents) {
@@ -101,6 +101,7 @@ add_react_common_subdir(react/nativemodule/core)
add_react_common_subdir(jserrorhandler)
add_react_common_subdir(react/bridgeless)
add_react_common_subdir(react/bridgeless/hermes)
add_react_common_subdir(react/bridgeless/nativeviewconfig)
# ReactAndroid JNI targets
add_react_build_subdir(generated/source/codegen/jni)
@@ -19,6 +19,7 @@ target_link_libraries(uimanagerjni
folly_runtime
glog
glog_init
bridgelessnativeviewconfig
rrc_native
yoga
callinvokerholder
@@ -8,9 +8,11 @@
#include <fbjni/fbjni.h>
#include "ComponentNameResolverManager.h"
#include "UIConstantsProviderManager.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::jni::initialize(vm, [] {
facebook::react::ComponentNameResolverManager::registerNatives();
facebook::react::UIConstantsProviderManager::registerNatives();
});
}
@@ -0,0 +1,64 @@
/*
* 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.
*/
#include <string>
#include <fbjni/fbjni.h>
#include <jsi/JSIDynamic.h>
#include <jsi/jsi.h>
#include <react/jni/NativeMap.h>
#include <react/bridgeless/nativeviewconfig/LegacyUIManagerConstantsProviderBinding.h>
#include "UIConstantsProviderManager.h"
namespace facebook::react {
using namespace facebook::jni;
UIConstantsProviderManager::UIConstantsProviderManager(
jni::alias_ref<UIConstantsProviderManager::javaobject> jThis,
RuntimeExecutor runtimeExecutor,
jni::alias_ref<jobject> uiConstantsProvider)
: javaPart_(jni::make_global(jThis)),
runtimeExecutor_(runtimeExecutor),
uiConstantsProvider_(jni::make_global(uiConstantsProvider)) {}
jni::local_ref<UIConstantsProviderManager::jhybriddata>
UIConstantsProviderManager::initHybrid(
jni::alias_ref<jhybridobject> jThis,
jni::alias_ref<JRuntimeExecutor::javaobject> runtimeExecutor,
jni::alias_ref<jobject> uiConstantsProvider) {
return makeCxxInstance(
jThis, runtimeExecutor->cthis()->get(), uiConstantsProvider);
}
void UIConstantsProviderManager::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", UIConstantsProviderManager::initHybrid),
makeNativeMethod(
"installJSIBindings", UIConstantsProviderManager::installJSIBindings),
});
}
void UIConstantsProviderManager::installJSIBindings() {
runtimeExecutor_([thizz = this](jsi::Runtime &runtime) {
auto uiConstantsProvider = [thizz, &runtime]() -> jsi::Value {
static auto getConstants =
jni::findClassStatic(
UIConstantsProviderManager::UIConstantsProviderJavaDescriptor)
->getMethod<jni::alias_ref<NativeMap::jhybridobject>()>(
"getConstants");
auto constants = getConstants(thizz->uiConstantsProvider_.get());
return jsi::valueFromDynamic(runtime, constants->cthis()->consume());
};
LegacyUIManagerConstantsProviderBinding::install(
runtime, std::move(uiConstantsProvider));
});
}
} // namespace facebook::react
@@ -0,0 +1,47 @@
/*
* 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.
*/
#pragma once
#include <ReactCommon/RuntimeExecutor.h>
#include <fbjni/fbjni.h>
#include <react/jni/JRuntimeExecutor.h>
namespace facebook::react {
class UIConstantsProviderManager
: public facebook::jni::HybridClass<UIConstantsProviderManager> {
public:
static auto constexpr kJavaDescriptor =
"Lcom/facebook/react/uimanager/UIConstantsProviderManager;";
constexpr static auto UIConstantsProviderJavaDescriptor =
"com/facebook/react/uimanager/UIConstantsProvider";
static facebook::jni::local_ref<jhybriddata> initHybrid(
facebook::jni::alias_ref<jhybridobject> jThis,
facebook::jni::alias_ref<JRuntimeExecutor::javaobject> runtimeExecutor,
facebook::jni::alias_ref<jobject> uiConstantsProviderManager);
static void registerNatives();
private:
friend HybridBase;
facebook::jni::global_ref<UIConstantsProviderManager::javaobject> javaPart_;
RuntimeExecutor runtimeExecutor_;
facebook::jni::global_ref<jobject> uiConstantsProvider_;
void installJSIBindings();
explicit UIConstantsProviderManager(
facebook::jni::alias_ref<UIConstantsProviderManager::jhybridobject> jThis,
RuntimeExecutor runtimeExecutor,
facebook::jni::alias_ref<jobject> uiConstantsProviderManager);
};
} // namespace facebook::react
@@ -0,0 +1,19 @@
# 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.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
add_compile_options(-std=c++17)
file(GLOB_RECURSE bridgeless_nativeviewconfig_SRC CONFIGURE_DEPENDS *.cpp)
add_library(
bridgelessnativeviewconfig
STATIC
${bridgeless_nativeviewconfig_SRC}
)
target_include_directories(bridgelessnativeviewconfig PUBLIC .)
target_link_libraries(bridgelessnativeviewconfig jsi)