diff --git a/React/Base/RCTBatchedBridge.mm b/React/Base/RCTBatchedBridge.mm index 5c90acca5..2f5a6da2c 100644 --- a/React/Base/RCTBatchedBridge.mm +++ b/React/Base/RCTBatchedBridge.mm @@ -63,6 +63,7 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) { @synthesize loading = _loading; @synthesize valid = _valid; @synthesize performanceLogger = _performanceLogger; +@synthesize bridgeDescription = _bridgeDescription; - (instancetype)initWithParentBridge:(RCTBridge *)bridge { diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h index a917ef124..ec7dde92f 100644 --- a/React/Base/RCTBridge+Private.h +++ b/React/Base/RCTBridge+Private.h @@ -35,6 +35,9 @@ RCT_EXTERN void RCTVerifyAllModulesExported(NSArray *extraModules); @property (nonatomic, assign) CFMutableDictionaryRef flowIDMap; @property (nonatomic, strong) NSLock *flowIDMapLock; +// Used by RCTDevMenu +@property (nonatomic, copy) NSString *bridgeDescription; + + (instancetype)currentBridge; + (void)setCurrentBridge:(RCTBridge *)bridge; diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index be29341e3..cd6844bdb 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -72,6 +72,30 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) { RCTBridgeFieldCallID, }; +namespace { + +class GetDescAdapter : public JSExecutorFactory { +public: + GetDescAdapter(RCTCxxBridge *bridge, std::shared_ptr factory) + : bridge_(bridge) + , factory_(factory) {} + std::unique_ptr createJSExecutor( + std::shared_ptr delegate, + std::shared_ptr jsQueue) override { + auto ret = factory_->createJSExecutor(delegate, jsQueue); + bridge_.bridgeDescription = + [NSString stringWithFormat:@"RCTCxxBridge %s", + ret->getDescription().c_str()]; + return std::move(ret); + } + +private: + RCTCxxBridge *bridge_; + std::shared_ptr factory_; +}; + +} + static bool isRAMBundle(NSData *script) { BundleHeader header; [script getBytes:&header length:sizeof(header)]; @@ -154,6 +178,7 @@ struct RCTInstanceCallback : public InstanceCallback { @synthesize loading = _loading; @synthesize valid = _valid; @synthesize performanceLogger = _performanceLogger; +@synthesize bridgeDescription = _bridgeDescription; + (void)initialize { @@ -491,6 +516,10 @@ struct RCTInstanceCallback : public InstanceCallback { RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge initializeBridge:]", nil); // This can only be false if the bridge was invalidated before startup completed if (_reactInstance) { +#if RCT_DEV + executorFactory = std::make_shared(self, executorFactory); +#endif + // This is async, but any calls into JS are blocked by the m_syncReady CV in Instance _reactInstance->initializeBridge( std::unique_ptr(new RCTInstanceCallback(self)), diff --git a/React/CxxBridge/RCTObjcExecutor.mm b/React/CxxBridge/RCTObjcExecutor.mm index e2468d78c..a8428dd72 100644 --- a/React/CxxBridge/RCTObjcExecutor.mm +++ b/React/CxxBridge/RCTObjcExecutor.mm @@ -117,6 +117,10 @@ public: callback:m_errorBlock]; } + virtual std::string getDescription() override { + return [NSStringFromClass([m_jse class]) UTF8String]; + } + private: id m_jse; RCTJavaScriptCompleteBlock m_errorBlock; diff --git a/React/DevSupport/RCTDevMenu.m b/React/DevSupport/RCTDevMenu.m index 644fd9bfc..782396f82 100644 --- a/React/DevSupport/RCTDevMenu.m +++ b/React/DevSupport/RCTDevMenu.m @@ -9,6 +9,7 @@ #import "RCTDevMenu.h" +#import "RCTBridge+Private.h" #import "RCTDevSettings.h" #import "RCTKeyCommands.h" #import "RCTLog.h" @@ -259,7 +260,11 @@ RCT_EXPORT_METHOD(show) return; } - NSString *title = [NSString stringWithFormat:@"React Native: Development (%@)", [_bridge class]]; + NSString *desc = _bridge.bridgeDescription; + if (desc.length == 0) { + desc = NSStringFromClass([_bridge class]); + } + NSString *title = [NSString stringWithFormat:@"React Native: Development (%@)", desc]; // On larger devices we don't have an anchor point for the action sheet UIAlertControllerStyle style = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? UIAlertControllerStyleActionSheet : UIAlertControllerStyleAlert; _actionSheet = [UIAlertController alertControllerWithTitle:title diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp index b0780f6d3..5e495ec7a 100644 --- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp +++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp @@ -114,4 +114,8 @@ void ProxyExecutor::setGlobalVariable(std::string propName, jni::make_jstring(jsonValue->c_str()).get()); } +std::string ProxyExecutor::getDescription() { + return "Chrome"; +} + } } diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h index 8603f8fec..e4d88a2b3 100644 --- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h +++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h @@ -47,6 +47,7 @@ public: virtual void setGlobalVariable( std::string propName, std::unique_ptr jsonValue) override; + virtual std::string getDescription() override; private: jni::global_ref m_executor; diff --git a/ReactCommon/cxxreact/JSCExecutor.cpp b/ReactCommon/cxxreact/JSCExecutor.cpp index 5bc837696..70fd599f5 100644 --- a/ReactCommon/cxxreact/JSCExecutor.cpp +++ b/ReactCommon/cxxreact/JSCExecutor.cpp @@ -509,6 +509,18 @@ void JSCExecutor::setGlobalVariable(std::string propName, std::unique_ptr script) { #if defined(WITH_FBJSCEXTENSIONS) const JSBigString* string = script.release(); diff --git a/ReactCommon/cxxreact/JSCExecutor.h b/ReactCommon/cxxreact/JSCExecutor.h index 0f823c3b6..9fbd52337 100644 --- a/ReactCommon/cxxreact/JSCExecutor.h +++ b/ReactCommon/cxxreact/JSCExecutor.h @@ -88,6 +88,8 @@ public: std::string propName, std::unique_ptr jsonValue) override; + virtual std::string getDescription() override; + virtual void* getJavaScriptContext() override; #ifdef WITH_JSC_MEMORY_PRESSURE diff --git a/ReactCommon/cxxreact/JSExecutor.h b/ReactCommon/cxxreact/JSExecutor.h index 8299d5d39..7d9deb716 100644 --- a/ReactCommon/cxxreact/JSExecutor.h +++ b/ReactCommon/cxxreact/JSExecutor.h @@ -73,6 +73,13 @@ public: return nullptr; } + /** + * The description is displayed in the dev menu, if there is one in + * this build. There is a default, but if this method returns a + * non-empty string, it will be used instead. + */ + virtual std::string getDescription() = 0; + virtual void handleMemoryPressure(int pressureLevel) {} virtual void destroy() {}