Prepare the bridge for C++

Reviewed By: @nicklockwood

Differential Revision: D2432291
This commit is contained in:
Marc Horowitz 2015-09-18 15:01:21 -07:00 committed by facebook-github-bot-8
parent 18a7e363b5
commit a87ba4ab4c
6 changed files with 74 additions and 23 deletions

View File

@ -18,7 +18,7 @@
#import "RCTLog.h" #import "RCTLog.h"
#import "RCTModuleData.h" #import "RCTModuleData.h"
#import "RCTModuleMap.h" #import "RCTModuleMap.h"
#import "RCTModuleMethod.h" #import "RCTBridgeMethod.h"
#import "RCTPerformanceLogger.h" #import "RCTPerformanceLogger.h"
#import "RCTPerfStats.h" #import "RCTPerfStats.h"
#import "RCTProfile.h" #import "RCTProfile.h"
@ -767,7 +767,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
return NO; return NO;
} }
RCTModuleMethod *method = moduleData.methods[methodID]; id<RCTBridgeMethod> method = moduleData.methods[methodID];
if (RCT_DEBUG && !method) { if (RCT_DEBUG && !method) {
RCTLogError(@"Unknown methodID: %zd for module: %zd (%@)", methodID, moduleID, moduleData.name); RCTLogError(@"Unknown methodID: %zd for module: %zd (%@)", methodID, moduleID, moduleData.name);
return NO; return NO;
@ -783,12 +783,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
} }
} }
RCTProfileEndEvent(0, @"objc_call", @{ NSMutableDictionary *args = [method.profileArgs mutableCopy];
@"module": NSStringFromClass(method.moduleClass), [args setValue:method.JSMethodName forKey:@"method"];
@"method": method.JSMethodName, [args setValue:RCTJSONStringify(RCTNullIfNil(params), NULL) forKey:@"args"];
@"selector": NSStringFromSelector(method.selector),
@"args": RCTJSONStringify(RCTNullIfNil(params), NULL), RCTProfileEndEvent(0, @"objc_call", args);
});
return YES; return YES;
} }

View File

@ -0,0 +1,29 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
@class RCTBridge;
typedef NS_ENUM(NSUInteger, RCTFunctionType) {
RCTFunctionTypeNormal,
RCTFunctionTypePromise,
};
@protocol RCTBridgeMethod <NSObject>
@property (nonatomic, copy, readonly) NSString *JSMethodName;
@property (nonatomic, copy, readonly) NSDictionary *profileArgs;
@property (nonatomic, readonly) RCTFunctionType functionType;
- (void)invokeWithBridge:(RCTBridge *)bridge
module:(id)module
arguments:(NSArray *)arguments;
@end

View File

@ -210,15 +210,21 @@ RCT_EXTERN void RCTRegisterModule(Class); \
#define RCT_EXTERN_REMAP_METHOD(js_name, method) \ #define RCT_EXTERN_REMAP_METHOD(js_name, method) \
+ (NSArray *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \ + (NSArray *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \
return @[@#js_name, @#method]; \ return @[@#js_name, @#method]; \
} \ }
/**
* Injects methods into JS. Entries in this array are used in addition to any
* methods defined using the macros above. This method is called only once,
* before registration.
*/
- (NSArray *)methodsToExport;
/** /**
* Injects constants into JS. These constants are made accessible via * Injects constants into JS. These constants are made accessible via
* NativeModules.ModuleName.X. This method is called when the module is * NativeModules.ModuleName.X. It is only called once for the lifetime of the
* registered by the bridge. It is only called once for the lifetime of the * bridge, so it is not suitable for returning dynamic values, but may be used
* bridge, so it is not suitable for returning dynamic values, but may be * for long-lived values such as session keys, that are regenerated only as
* used for long-lived values such as session keys, that are regenerated only * part of a reload of the entire React application.
* as part of a reload of the entire React application.
*/ */
- (NSDictionary *)constantsToExport; - (NSDictionary *)constantsToExport;

View File

@ -49,6 +49,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
{ {
if (!_methods) { if (!_methods) {
NSMutableArray *moduleMethods = [NSMutableArray new]; NSMutableArray *moduleMethods = [NSMutableArray new];
if ([_instance respondsToSelector:@selector(methodsToExport)]) {
[moduleMethods addObjectsFromArray:[_instance methodsToExport]];
}
unsigned int methodCount; unsigned int methodCount;
Method *methods = class_copyMethodList(object_getClass(_moduleClass), &methodCount); Method *methods = class_copyMethodList(object_getClass(_moduleClass), &methodCount);
@ -58,7 +63,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) { if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) {
IMP imp = method_getImplementation(method); IMP imp = method_getImplementation(method);
NSArray *entries = ((NSArray *(*)(id, SEL))imp)(_moduleClass, selector); NSArray *entries = ((NSArray *(*)(id, SEL))imp)(_moduleClass, selector);
RCTModuleMethod *moduleMethod = id<RCTBridgeMethod> moduleMethod =
[[RCTModuleMethod alloc] initWithObjCMethodName:entries[1] [[RCTModuleMethod alloc] initWithObjCMethodName:entries[1]
JSMethodName:entries[0] JSMethodName:entries[0]
moduleClass:_moduleClass]; moduleClass:_moduleClass];
@ -84,7 +89,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
} }
NSMutableDictionary *methodconfig = [NSMutableDictionary new]; NSMutableDictionary *methodconfig = [NSMutableDictionary new];
[self.methods enumerateObjectsUsingBlock:^(RCTModuleMethod *method, NSUInteger idx, __unused BOOL *stop) { [self.methods enumerateObjectsUsingBlock:^(id<RCTBridgeMethod> method, NSUInteger idx, __unused BOOL *stop) {
methodconfig[method.JSMethodName] = @{ methodconfig[method.JSMethodName] = @{
@"methodID": @(idx), @"methodID": @(idx),
@"type": method.functionType == RCTFunctionTypePromise ? @"remoteAsync" : @"remote", @"type": method.functionType == RCTFunctionTypePromise ? @"remoteAsync" : @"remote",

View File

@ -9,12 +9,9 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@class RCTBridge; #import "RCTBridgeMethod.h"
typedef NS_ENUM(NSUInteger, RCTFunctionType) { @class RCTBridge;
RCTFunctionTypeNormal,
RCTFunctionTypePromise,
};
typedef NS_ENUM(NSUInteger, RCTNullability) { typedef NS_ENUM(NSUInteger, RCTNullability) {
RCTNullabilityUnspecified, RCTNullabilityUnspecified,
@ -30,9 +27,8 @@ typedef NS_ENUM(NSUInteger, RCTNullability) {
@end @end
@interface RCTModuleMethod : NSObject @interface RCTModuleMethod : NSObject <RCTBridgeMethod>
@property (nonatomic, copy, readonly) NSString *JSMethodName;
@property (nonatomic, readonly) Class moduleClass; @property (nonatomic, readonly) Class moduleClass;
@property (nonatomic, readonly) SEL selector; @property (nonatomic, readonly) SEL selector;
@property (nonatomic, readonly) RCTFunctionType functionType; @property (nonatomic, readonly) RCTFunctionType functionType;

View File

@ -50,8 +50,11 @@ typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id);
NSArray *_argumentBlocks; NSArray *_argumentBlocks;
NSString *_objCMethodName; NSString *_objCMethodName;
SEL _selector; SEL _selector;
NSDictionary *_profileArgs;
} }
@synthesize JSMethodName = _JSMethodName;
static void RCTLogArgumentError(RCTModuleMethod *method, NSUInteger index, static void RCTLogArgumentError(RCTModuleMethod *method, NSUInteger index,
id valueOrType, const char *issue) id valueOrType, const char *issue)
{ {
@ -370,6 +373,19 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments)
return _selector; return _selector;
} }
- (NSDictionary *)profileArgs
{
if (_profileArgs) {
// This sets _selector
[self processMethodSignature];
_profileArgs = @{
@"module": NSStringFromClass(_moduleClass),
@"selector": NSStringFromSelector(_selector),
};
}
return _profileArgs;
}
- (void)invokeWithBridge:(RCTBridge *)bridge - (void)invokeWithBridge:(RCTBridge *)bridge
module:(id)module module:(id)module
arguments:(NSArray *)arguments arguments:(NSArray *)arguments