From af5c8a8fd2fb959cae6a364dd0107f67f28453ae Mon Sep 17 00:00:00 2001 From: Marc Horowitz Date: Wed, 28 Sep 2016 14:00:16 -0700 Subject: [PATCH] Add support for new ios bridge to FBReactBridgeJSExecutor Reviewed By: javache Differential Revision: D3897535 fbshipit-source-id: 35bdaf885b03c0c95017a68b69f1f506e6943f2b --- React/Base/RCTBatchedBridge.m | 42 +++++++++++++++++++++++++++++++++++ React/Base/RCTBridge.h | 16 +++++++++++++ React/Base/RCTBridge.m | 9 ++++++++ 3 files changed, 67 insertions(+) diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index 63e456d0bfbd04..3a87af40df7a29 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -778,6 +778,48 @@ - (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args } queue:RCTJSThread]; } +/** + * JS thread only + */ +- (JSValue *)callFunctionOnModule:(NSString *)module + method:(NSString *)method + arguments:(NSArray *)arguments + error:(NSError **)error +{ + RCTJSCExecutor *jsExecutor = (RCTJSCExecutor *)_javaScriptExecutor; + if (![jsExecutor isKindOfClass:[RCTJSCExecutor class]]) { + RCTLogWarn(@"FBReactBridgeJSExecutor is only supported when running in JSC"); + return nil; + } + + __block JSValue *jsResult = nil; + + RCTAssertJSThread(); + RCT_PROFILE_BEGIN_EVENT(0, @"callFunctionOnModule", (@{ @"module": module, @"method": method })); + [jsExecutor callFunctionOnModule:module + method:method + arguments:arguments + jsValueCallback:^(JSValue *result, NSError *jsError) { + if (error) { + *error = jsError; + } + + JSValue *length = result[@"length"]; + RCTAssert([length isNumber] && [length toUInt32] == 2, + @"Return value of a callFunction must be an array of size 2"); + + jsResult = [result valueAtIndex:0]; + + NSArray *nativeModuleCalls = [[result valueAtIndex:1] toArray]; + [self handleBuffer:nativeModuleCalls batchEnded:YES]; + }]; + + RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"js_call"); + + return jsResult; +} + + /** * Private hack to support `setTimeout(fn, 0)` */ diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h index b87821c9b36a9f..852f3ec63033b2 100644 --- a/React/Base/RCTBridge.h +++ b/React/Base/RCTBridge.h @@ -15,6 +15,7 @@ #import "RCTFrameUpdate.h" #import "RCTInvalidating.h" +@class JSValue; @class RCTBridge; @class RCTEventDispatcher; @class RCTPerformanceLogger; @@ -103,6 +104,21 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass); - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args; - (void)enqueueJSCall:(NSString *)module method:(NSString *)method args:(NSArray *)args completion:(dispatch_block_t)completion; +/** + * This method is used to call functions in the JavaScript application context + * synchronously. This is intended for use by applications which do their own + * thread management and are careful to manage multi-threaded access to the JSVM. + * See also -[RCTBridgeDelgate shouldBridgeLoadJavaScriptSynchronously], which + * may be needed to ensure that any requires JS code is loaded before this method + * is called. If the underlying executor is not JSC, this will return nil. Safe + * to call from any thread. + * + * @experimental + */ +- (JSValue *)callFunctionOnModule:(NSString *)module + method:(NSString *)method + arguments:(NSArray *)arguments + error:(NSError **)error; /** * Retrieve a bridge module instance by name or class. Note that modules are diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index 8720d5d7567f18..4876bd2fd93364 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -351,4 +351,13 @@ - (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args [self.batchedBridge enqueueCallback:cbID args:args]; } +- (JSValue *)callFunctionOnModule:(NSString *)module + method:(NSString *)method + arguments:(NSArray *)arguments + error:(NSError **)error +{ + return [self.batchedBridge callFunctionOnModule:module method:method arguments:arguments error:error]; +} + + @end