From 8a4c85316dbc6c88f230eaa4a35e4eb2837aaac3 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Mon, 22 Jan 2024 05:00:01 -0800 Subject: [PATCH] Register RCTHost with modern CDP backend (#42393) Summary: Changelog: [Internal][iOS] - Enable stub modern CDP backend in Bridgeless behind a feature flag Minimally integrates the stub native CDP backend implementation (D50936932) into iOS Bridgeless. This integration registers itself as a "Modern" target (D50967794, D50967795) to instruct `inspector-proxy` to disable its CDP hacks related to source map fetching, reloads, etc. This gives us a mostly-clean slate on which to develop and test native CDP functionality. Pull Request resolved: https://github.com/facebook/react-native/pull/42393 Test Plan: 1. `js1 run` 2. Enable the modern CDP backend by grafting D52844391 3. Enable Bridgeless in RNTester by grafting D52910646 4. `buck2 install rntester-ios` 5. Dev Menu -> Open Debugger 6. Observe console message self-identifying the backend + iOS Bridgeless 7. Observe that the debugger stays connected when the app is reloaded (albeit without doing anything very interesting just yet) {F1329876835} Reviewed By: huntie Differential Revision: D50936931 Pulled By: motiz88 fbshipit-source-id: ff8f919d0370266aea2916da349520bc76d690ab --- .../jsinspector-modern/PageTarget.h | 14 +++++++- .../ReactCommon/react/runtime/CMakeLists.txt | 1 + .../react/runtime/React-RuntimeCore.podspec | 1 + .../platform/ios/React-RuntimeApple.podspec | 1 + .../platform/ios/ReactCommon/RCTHost.mm | 34 +++++++++++++++++++ 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/react-native/ReactCommon/jsinspector-modern/PageTarget.h b/packages/react-native/ReactCommon/jsinspector-modern/PageTarget.h index 7e622e79502..9682383755b 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/PageTarget.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/PageTarget.h @@ -12,6 +12,18 @@ #include #include +#ifndef JSINSPECTOR_EXPORT +#ifdef _MSC_VER +#ifdef CREATE_SHARED_LIBRARY +#define JSINSPECTOR_EXPORT __declspec(dllexport) +#else +#define JSINSPECTOR_EXPORT +#endif // CREATE_SHARED_LIBRARY +#else // _MSC_VER +#define JSINSPECTOR_EXPORT __attribute__((visibility("default"))) +#endif // _MSC_VER +#endif // !defined(JSINSPECTOR_EXPORT) + namespace facebook::react::jsinspector_modern { /** @@ -19,7 +31,7 @@ namespace facebook::react::jsinspector_modern { * "Host" in React Native's architecture - the entity that manages the * lifecycle of a React Instance. */ -class PageTarget { +class JSINSPECTOR_EXPORT PageTarget { public: struct SessionMetadata { std::optional integrationName; diff --git a/packages/react-native/ReactCommon/react/runtime/CMakeLists.txt b/packages/react-native/ReactCommon/react/runtime/CMakeLists.txt index 3a6bb1a64f1..3ab02524543 100644 --- a/packages/react-native/ReactCommon/react/runtime/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/runtime/CMakeLists.txt @@ -35,4 +35,5 @@ target_link_libraries( jsi jsireact react_utils + jsinspector ) diff --git a/packages/react-native/ReactCommon/react/runtime/React-RuntimeCore.podspec b/packages/react-native/ReactCommon/react/runtime/React-RuntimeCore.podspec index 8ac8cc92605..d75f5ea1cd8 100644 --- a/packages/react-native/ReactCommon/react/runtime/React-RuntimeCore.podspec +++ b/packages/react-native/ReactCommon/react/runtime/React-RuntimeCore.podspec @@ -62,4 +62,5 @@ Pod::Spec.new do |s| s.dependency "React-jsc" end + s.dependency "React-jsinspector" end diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/React-RuntimeApple.podspec b/packages/react-native/ReactCommon/react/runtime/platform/ios/React-RuntimeApple.podspec index 68520ff807e..589d097f890 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/React-RuntimeApple.podspec +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/React-RuntimeApple.podspec @@ -65,6 +65,7 @@ Pod::Spec.new do |s| s.dependency "React-RuntimeCore" s.dependency "React-Mapbuffer" s.dependency "React-jserrorhandler" + s.dependency "React-jsinspector" if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1" s.dependency "hermes-engine" diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm index 64daf56c38d..a6ac478f3db 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm @@ -17,6 +17,10 @@ #import #import #import +#import +#import +#import +#import RCT_MOCK_DEF(RCTHost, _RCTLogNativeInternal); #define _RCTLogNativeInternal RCT_MOCK_USE(RCTHost, _RCTLogNativeInternal) @@ -47,6 +51,9 @@ using namespace facebook::react; std::vector<__weak RCTFabricSurface *> _attachedSurfaces; RCTModuleRegistry *_moduleRegistry; + + std::unique_ptr _inspectorTarget; + std::optional _inspectorPageId; } + (void)initialize @@ -141,6 +148,28 @@ using namespace facebook::react; - (void)start { + auto &inspectorFlags = jsinspector_modern::InspectorFlags::getInstance(); + if (inspectorFlags.getEnableModernCDPRegistry() && !_inspectorPageId.has_value()) { + _inspectorTarget = std::make_unique(); + __weak RCTHost *weakSelf = self; + _inspectorPageId = facebook::react::jsinspector_modern::getInspectorInstance().addPage( + "React Native Bridgeless (Experimental)", + /* vm */ "", + [weakSelf](std::unique_ptr remote) + -> std::unique_ptr { + RCTHost *strongSelf = weakSelf; + if (!strongSelf) { + // This can happen if we're about to be dealloc'd. Reject the connection. + return nullptr; + } + return strongSelf->_inspectorTarget->connect( + std::move(remote), + { + .integrationName = "iOS Bridgeless (RCTHost)", + }); + }, + facebook::react::jsinspector_modern::InspectorPageType::Modern); + } if (_instance) { RCTLogWarn( @"RCTHost should not be creating a new instance if one already exists. This implies there is a bug with how/when this method is being called."); @@ -228,6 +257,11 @@ using namespace facebook::react; - (void)dealloc { + if (_inspectorPageId.has_value()) { + facebook::react::jsinspector_modern::getInspectorInstance().removePage(*_inspectorPageId); + _inspectorPageId.reset(); + _inspectorTarget.reset(); + } [_instance invalidate]; }