Skip to content

Commit

Permalink
Android: Introduce RN$LegacyInterop_UIManager_getConstants (#38153)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #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
  • Loading branch information
dmytrorykun authored and facebook-github-bot committed Jul 19, 2023
1 parent 6eeb81a commit f7f5b49
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
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;
Expand All @@ -33,6 +35,7 @@
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;
Expand All @@ -52,6 +55,9 @@
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;
Expand All @@ -60,8 +66,10 @@
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;

Expand All @@ -87,6 +95,7 @@ final class ReactInstance {
private final JavaTimerManager mJavaTimerManager;

@DoNotStrip @Nullable private ComponentNameResolverManager mComponentNameResolverManager;
@DoNotStrip @Nullable private UIConstantsProviderManager mUIConstantsProviderManager;

static {
loadLibraryIfNeeded();
Expand Down Expand Up @@ -220,6 +229,27 @@ public void onHostDestroy() {

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");
Expand Down Expand Up @@ -388,6 +418,7 @@ public Collection<NativeModule> getNativeModules() {
mFabricUIManager.onCatalystInstanceDestroy();
mHybridData.resetNative();
mComponentNameResolverManager = null;
mUIConstantsProviderManager = null;
}

/* --- Native methods --- */
Expand Down Expand Up @@ -500,4 +531,14 @@ public void registerSegment(int segmentId, String path) {
}
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
@@ -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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ private static Map<String, Object> createConstants(ViewManagerResolver viewManag
}
}

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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ target_link_libraries(uimanagerjni
folly_runtime
glog
glog_init
bridgelessnativeviewconfig
rrc_native
yoga
callinvokerholder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit f7f5b49

Please sign in to comment.