Expose new API FabricUIManager.getInspectorDataForInstance

Summary:
This diff exposes a new API in FabricUIManager called getInspectorDataForInstance. The goal of this method is to return React metadata for a Native view.

This data will be used from partner teams to build tools that uses React metadata in RN

Data returned from React: P429701924

changelog: [internal] internal

allow-large-files

Reviewed By: JoshuaGross

Differential Revision: D29747864

fbshipit-source-id: 8cb55573be08cb530f7e3c83eed8b4fcf43e7781
This commit is contained in:
David Vacca authored and Facebook GitHub Bot committed 2021-07-24 09:12:44 -07:00
1 parent ff494eece2
commit 43cdd84a22
8 files changed
+109

No files matched your search

@@ -12,9 +12,11 @@ import androidx.annotation.NonNull;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.NativeMap;
import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.bridge.RuntimeExecutor;
import com.facebook.react.bridge.queue.MessageQueueThread;
import com.facebook.react.fabric.events.EventBeatManager;
import com.facebook.react.fabric.events.EventEmitterWrapper;
import com.facebook.react.uimanager.PixelUtil;
@DoNotStrip
@@ -76,6 +78,9 @@ public class Binding {
public native void driveCxxAnimations();
public native ReadableNativeMap getInspectorDataForInstance(
EventEmitterWrapper eventEmitterWrapper);
public void register(
@NonNull RuntimeExecutor runtimeExecutor,
@NonNull FabricUIManager fabricUIManager,
@@ -223,6 +223,16 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
return rootTag;
}
@UiThread
@ThreadConfined(UI)
public ReadableMap getInspectorDataForInstance(final int surfaceId, final View view) {
UiThreadUtil.assertOnUiThread();
int reactTag = view.getId();
EventEmitterWrapper eventEmitter = mMountingManager.getEventEmitter(surfaceId, reactTag);
return mBinding.getInspectorDataForInstance(eventEmitter);
}
@Override
public void preInitializeViewManagers(List<String> viewManagerNames) {
for (String viewManagerName : viewManagerNames) {
@@ -233,6 +233,32 @@ std::shared_ptr<Scheduler> Binding::getScheduler() {
return scheduler_;
}
jni::local_ref<ReadableNativeMap::jhybridobject>
Binding::getInspectorDataForInstance(
jni::alias_ref<EventEmitterWrapper::javaobject> eventEmitterWrapper) {
std::shared_ptr<Scheduler> scheduler = getScheduler();
if (!scheduler) {
LOG(ERROR) << "Binding::startSurface: scheduler disappeared";
return ReadableNativeMap::newObjectCxxArgs(folly::dynamic::object());
}
EventEmitterWrapper *cEventEmitter = cthis(eventEmitterWrapper);
InspectorData data =
scheduler->getInspectorDataForInstance(cEventEmitter->eventEmitter);
folly::dynamic result = folly::dynamic::object;
result["fileName"] = data.fileName;
result["lineNumber"] = data.lineNumber;
result["columnNumber"] = data.columnNumber;
result["selectedIndex"] = data.selectedIndex;
auto hierarchy = folly::dynamic::array();
for (auto hierarchyItem : data.hierarchy) {
hierarchy.push_back(hierarchyItem);
}
result["hierarchy"] = hierarchy;
return ReadableNativeMap::newObjectCxxArgs(result);
}
void Binding::startSurface(
jint surfaceId,
jni::alias_ref<jstring> moduleName,
@@ -1314,6 +1340,8 @@ void Binding::registerNatives() {
makeNativeMethod(
"installFabricUIManager", Binding::installFabricUIManager),
makeNativeMethod("startSurface", Binding::startSurface),
makeNativeMethod(
"getInspectorDataForInstance", Binding::getInspectorDataForInstance),
makeNativeMethod(
"startSurfaceWithConstraints", Binding::startSurfaceWithConstraints),
makeNativeMethod(
@@ -15,10 +15,12 @@
#include <react/renderer/scheduler/Scheduler.h>
#include <react/renderer/scheduler/SchedulerDelegate.h>
#include <react/renderer/uimanager/LayoutAnimationStatusDelegate.h>
#include <memory>
#include <mutex>
#include "ComponentFactory.h"
#include "EventBeatManager.h"
#include "EventEmitterWrapper.h"
#include "JBackgroundExecutor.h"
#include "SurfaceHandlerBinding.h"
@@ -96,6 +98,9 @@ class Binding : public jni::HybridClass<Binding>,
jboolean isRTL,
jboolean doLeftAndRightSwapInRTL);
jni::local_ref<ReadableNativeMap::jhybridobject> getInspectorDataForInstance(
jni::alias_ref<EventEmitterWrapper::javaobject> eventEmitterWrapper);
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
void installFabricUIManager(
@@ -206,6 +206,31 @@ void Scheduler::registerSurface(
surfaceHandler.setUIManager(uiManager_.get());
}
InspectorData Scheduler::getInspectorDataForInstance(
SharedEventEmitter eventEmitter) const noexcept {
return executeSynchronouslyOnSameThread_CAN_DEADLOCK<InspectorData>(
runtimeExecutor_, [=](jsi::Runtime &runtime) -> InspectorData {
auto uiManagerBinding = UIManagerBinding::getBinding(runtime);
auto value = uiManagerBinding->getInspectorDataForInstance(
runtime, eventEmitter);
// TODO: avoid transforming jsi
auto dynamic = jsi::dynamicFromValue(runtime, value);
auto source = dynamic["source"];
InspectorData result = {};
result.fileName = source["fileName"].c_str();
result.lineNumber = (int)source["lineNumber"].getDouble();
result.columnNumber = (int)source["columnNumber"].getDouble();
result.selectedIndex = (int)dynamic["selectedIndex"].getDouble();
auto hierarchy = dynamic["hierarchy"];
for (size_t i = 0; i < hierarchy.size(); i++) {
result.hierarchy.push_back(hierarchy[i]["name"].c_str());
}
return result;
});
}
void Scheduler::unregisterSurface(
SurfaceHandler const &surfaceHandler) const noexcept {
surfaceHandler.setUIManager(nullptr);
@@ -15,8 +15,10 @@
#include <react/renderer/componentregistry/ComponentDescriptorFactory.h>
#include <react/renderer/components/root/RootComponentDescriptor.h>
#include <react/renderer/core/ComponentDescriptor.h>
#include <react/renderer/core/EventEmitter.h>
#include <react/renderer/core/LayoutConstraints.h>
#include <react/renderer/mounting/MountingOverrideDelegate.h>
#include <react/renderer/scheduler/InspectorData.h>
#include <react/renderer/scheduler/SchedulerDelegate.h>
#include <react/renderer/scheduler/SchedulerToolbox.h>
#include <react/renderer/scheduler/SurfaceHandler.h>
@@ -49,6 +51,9 @@ class Scheduler final : public UIManagerDelegate {
void registerSurface(SurfaceHandler const &surfaceHandler) const noexcept;
void unregisterSurface(SurfaceHandler const &surfaceHandler) const noexcept;
InspectorData getInspectorDataForInstance(
SharedEventEmitter eventEmitter) const noexcept;
void renderTemplateToSurface(
SurfaceId surfaceId,
const std::string &uiTemplate);
@@ -133,6 +133,33 @@ static jsi::Value callMethodOfModule(
return jsi::Value::undefined();
}
jsi::Value UIManagerBinding::getInspectorDataForInstance(
jsi::Runtime &runtime,
SharedEventEmitter eventEmitter) const {
auto eventTarget = eventEmitter->eventTarget_;
EventEmitter::DispatchMutex().lock();
if (!runtime.global().hasProperty(runtime, "__fbBatchedBridge") ||
!eventTarget) {
return jsi::Value::undefined();
}
eventTarget->retain(runtime);
auto instanceHandle = eventTarget->getInstanceHandle(runtime);
eventTarget->release(runtime);
EventEmitter::DispatchMutex().unlock();
if (instanceHandle.isUndefined()) {
return jsi::Value::undefined();
}
return callMethodOfModule(
runtime,
"ReactFabric",
"getInspectorDataForInstance",
{std::move(instanceHandle)});
}
void UIManagerBinding::startSurface(
jsi::Runtime &runtime,
SurfaceId surfaceId,
@@ -74,6 +74,10 @@ class UIManagerBinding : public jsi::HostObject {
folly::dynamic const &props,
DisplayMode displayMode) const;
jsi::Value getInspectorDataForInstance(
jsi::Runtime &runtime,
SharedEventEmitter eventEmitter) const;
/*
* Stops React Native Surface with given id.
* Thread synchronization must be enforced externally.