Skip to content

Commit 43cdd84

Browse files
mdvaccafacebook-github-bot
authored andcommitted
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
1 parent ff494ee commit 43cdd84

File tree

8 files changed

+109
-0
lines changed

8 files changed

+109
-0
lines changed

ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
import com.facebook.jni.HybridData;
1313
import com.facebook.proguard.annotations.DoNotStrip;
1414
import com.facebook.react.bridge.NativeMap;
15+
import com.facebook.react.bridge.ReadableNativeMap;
1516
import com.facebook.react.bridge.RuntimeExecutor;
1617
import com.facebook.react.bridge.queue.MessageQueueThread;
1718
import com.facebook.react.fabric.events.EventBeatManager;
19+
import com.facebook.react.fabric.events.EventEmitterWrapper;
1820
import com.facebook.react.uimanager.PixelUtil;
1921

2022
@DoNotStrip
@@ -76,6 +78,9 @@ public native void setConstraints(
7678

7779
public native void driveCxxAnimations();
7880

81+
public native ReadableNativeMap getInspectorDataForInstance(
82+
EventEmitterWrapper eventEmitterWrapper);
83+
7984
public void register(
8085
@NonNull RuntimeExecutor runtimeExecutor,
8186
@NonNull FabricUIManager fabricUIManager,

ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,16 @@ public <T extends View> int addRootView(
223223
return rootTag;
224224
}
225225

226+
@UiThread
227+
@ThreadConfined(UI)
228+
public ReadableMap getInspectorDataForInstance(final int surfaceId, final View view) {
229+
UiThreadUtil.assertOnUiThread();
230+
int reactTag = view.getId();
231+
232+
EventEmitterWrapper eventEmitter = mMountingManager.getEventEmitter(surfaceId, reactTag);
233+
return mBinding.getInspectorDataForInstance(eventEmitter);
234+
}
235+
226236
@Override
227237
public void preInitializeViewManagers(List<String> viewManagerNames) {
228238
for (String viewManagerName : viewManagerNames) {

ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,32 @@ std::shared_ptr<Scheduler> Binding::getScheduler() {
233233
return scheduler_;
234234
}
235235

236+
jni::local_ref<ReadableNativeMap::jhybridobject>
237+
Binding::getInspectorDataForInstance(
238+
jni::alias_ref<EventEmitterWrapper::javaobject> eventEmitterWrapper) {
239+
std::shared_ptr<Scheduler> scheduler = getScheduler();
240+
if (!scheduler) {
241+
LOG(ERROR) << "Binding::startSurface: scheduler disappeared";
242+
return ReadableNativeMap::newObjectCxxArgs(folly::dynamic::object());
243+
}
244+
245+
EventEmitterWrapper *cEventEmitter = cthis(eventEmitterWrapper);
246+
InspectorData data =
247+
scheduler->getInspectorDataForInstance(cEventEmitter->eventEmitter);
248+
249+
folly::dynamic result = folly::dynamic::object;
250+
result["fileName"] = data.fileName;
251+
result["lineNumber"] = data.lineNumber;
252+
result["columnNumber"] = data.columnNumber;
253+
result["selectedIndex"] = data.selectedIndex;
254+
auto hierarchy = folly::dynamic::array();
255+
for (auto hierarchyItem : data.hierarchy) {
256+
hierarchy.push_back(hierarchyItem);
257+
}
258+
result["hierarchy"] = hierarchy;
259+
return ReadableNativeMap::newObjectCxxArgs(result);
260+
}
261+
236262
void Binding::startSurface(
237263
jint surfaceId,
238264
jni::alias_ref<jstring> moduleName,
@@ -1314,6 +1340,8 @@ void Binding::registerNatives() {
13141340
makeNativeMethod(
13151341
"installFabricUIManager", Binding::installFabricUIManager),
13161342
makeNativeMethod("startSurface", Binding::startSurface),
1343+
makeNativeMethod(
1344+
"getInspectorDataForInstance", Binding::getInspectorDataForInstance),
13171345
makeNativeMethod(
13181346
"startSurfaceWithConstraints", Binding::startSurfaceWithConstraints),
13191347
makeNativeMethod(

ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
#include <react/renderer/scheduler/Scheduler.h>
1616
#include <react/renderer/scheduler/SchedulerDelegate.h>
1717
#include <react/renderer/uimanager/LayoutAnimationStatusDelegate.h>
18+
1819
#include <memory>
1920
#include <mutex>
2021
#include "ComponentFactory.h"
2122
#include "EventBeatManager.h"
23+
#include "EventEmitterWrapper.h"
2224
#include "JBackgroundExecutor.h"
2325
#include "SurfaceHandlerBinding.h"
2426

@@ -96,6 +98,9 @@ class Binding : public jni::HybridClass<Binding>,
9698
jboolean isRTL,
9799
jboolean doLeftAndRightSwapInRTL);
98100

101+
jni::local_ref<ReadableNativeMap::jhybridobject> getInspectorDataForInstance(
102+
jni::alias_ref<EventEmitterWrapper::javaobject> eventEmitterWrapper);
103+
99104
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
100105

101106
void installFabricUIManager(

ReactCommon/react/renderer/scheduler/Scheduler.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,31 @@ void Scheduler::registerSurface(
206206
surfaceHandler.setUIManager(uiManager_.get());
207207
}
208208

209+
InspectorData Scheduler::getInspectorDataForInstance(
210+
SharedEventEmitter eventEmitter) const noexcept {
211+
return executeSynchronouslyOnSameThread_CAN_DEADLOCK<InspectorData>(
212+
runtimeExecutor_, [=](jsi::Runtime &runtime) -> InspectorData {
213+
auto uiManagerBinding = UIManagerBinding::getBinding(runtime);
214+
auto value = uiManagerBinding->getInspectorDataForInstance(
215+
runtime, eventEmitter);
216+
217+
// TODO: avoid transforming jsi
218+
auto dynamic = jsi::dynamicFromValue(runtime, value);
219+
auto source = dynamic["source"];
220+
221+
InspectorData result = {};
222+
result.fileName = source["fileName"].c_str();
223+
result.lineNumber = (int)source["lineNumber"].getDouble();
224+
result.columnNumber = (int)source["columnNumber"].getDouble();
225+
result.selectedIndex = (int)dynamic["selectedIndex"].getDouble();
226+
auto hierarchy = dynamic["hierarchy"];
227+
for (size_t i = 0; i < hierarchy.size(); i++) {
228+
result.hierarchy.push_back(hierarchy[i]["name"].c_str());
229+
}
230+
return result;
231+
});
232+
}
233+
209234
void Scheduler::unregisterSurface(
210235
SurfaceHandler const &surfaceHandler) const noexcept {
211236
surfaceHandler.setUIManager(nullptr);

ReactCommon/react/renderer/scheduler/Scheduler.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
#include <react/renderer/componentregistry/ComponentDescriptorFactory.h>
1616
#include <react/renderer/components/root/RootComponentDescriptor.h>
1717
#include <react/renderer/core/ComponentDescriptor.h>
18+
#include <react/renderer/core/EventEmitter.h>
1819
#include <react/renderer/core/LayoutConstraints.h>
1920
#include <react/renderer/mounting/MountingOverrideDelegate.h>
21+
#include <react/renderer/scheduler/InspectorData.h>
2022
#include <react/renderer/scheduler/SchedulerDelegate.h>
2123
#include <react/renderer/scheduler/SchedulerToolbox.h>
2224
#include <react/renderer/scheduler/SurfaceHandler.h>
@@ -49,6 +51,9 @@ class Scheduler final : public UIManagerDelegate {
4951
void registerSurface(SurfaceHandler const &surfaceHandler) const noexcept;
5052
void unregisterSurface(SurfaceHandler const &surfaceHandler) const noexcept;
5153

54+
InspectorData getInspectorDataForInstance(
55+
SharedEventEmitter eventEmitter) const noexcept;
56+
5257
void renderTemplateToSurface(
5358
SurfaceId surfaceId,
5459
const std::string &uiTemplate);

ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,33 @@ static jsi::Value callMethodOfModule(
133133
return jsi::Value::undefined();
134134
}
135135

136+
jsi::Value UIManagerBinding::getInspectorDataForInstance(
137+
jsi::Runtime &runtime,
138+
SharedEventEmitter eventEmitter) const {
139+
auto eventTarget = eventEmitter->eventTarget_;
140+
EventEmitter::DispatchMutex().lock();
141+
142+
if (!runtime.global().hasProperty(runtime, "__fbBatchedBridge") ||
143+
!eventTarget) {
144+
return jsi::Value::undefined();
145+
}
146+
147+
eventTarget->retain(runtime);
148+
auto instanceHandle = eventTarget->getInstanceHandle(runtime);
149+
eventTarget->release(runtime);
150+
EventEmitter::DispatchMutex().unlock();
151+
152+
if (instanceHandle.isUndefined()) {
153+
return jsi::Value::undefined();
154+
}
155+
156+
return callMethodOfModule(
157+
runtime,
158+
"ReactFabric",
159+
"getInspectorDataForInstance",
160+
{std::move(instanceHandle)});
161+
}
162+
136163
void UIManagerBinding::startSurface(
137164
jsi::Runtime &runtime,
138165
SurfaceId surfaceId,

ReactCommon/react/renderer/uimanager/UIManagerBinding.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ class UIManagerBinding : public jsi::HostObject {
7474
folly::dynamic const &props,
7575
DisplayMode displayMode) const;
7676

77+
jsi::Value getInspectorDataForInstance(
78+
jsi::Runtime &runtime,
79+
SharedEventEmitter eventEmitter) const;
80+
7781
/*
7882
* Stops React Native Surface with given id.
7983
* Thread synchronization must be enforced externally.

0 commit comments

Comments
 (0)