1*cde16245SBen Roth// Copyright 2015-present 650 Industries. All rights reserved. 2*cde16245SBen Roth 3*cde16245SBen Roth#import "EXNativeModuleIntrospection.h" 4*cde16245SBen Roth 5*cde16245SBen Roth#import <React/RCTBridge.h> 6*cde16245SBen Roth#import <React/RCTBridgeMethod.h> 7*cde16245SBen Roth#import <React/RCTModuleData.h> 8*cde16245SBen Roth 9*cde16245SBen Roth@implementation EXNativeModuleIntrospection 10*cde16245SBen Roth 11*cde16245SBen Roth@synthesize bridge = _bridge; 12*cde16245SBen Roth 13*cde16245SBen RothRCT_EXPORT_MODULE(ExpoNativeModuleIntrospection) 14*cde16245SBen Roth 15*cde16245SBen RothRCT_REMAP_METHOD(getNativeModuleNamesAsync, 16*cde16245SBen Roth nativeModuleNamesWithResolver:(RCTPromiseResolveBlock)resolve 17*cde16245SBen Roth rejecter:(RCTPromiseRejectBlock)reject) { 18*cde16245SBen Roth NSError *error; 19*cde16245SBen Roth NSDictionary<NSString *, RCTModuleData *> *moduleDataByName = [self _moduleDataFromBridge:&error]; 20*cde16245SBen Roth if (!moduleDataByName) { 21*cde16245SBen Roth reject(error.domain, error.userInfo[NSLocalizedDescriptionKey], error); 22*cde16245SBen Roth return; 23*cde16245SBen Roth } 24*cde16245SBen Roth 25*cde16245SBen Roth NSArray<NSString *> *moduleNames = moduleDataByName.allKeys; 26*cde16245SBen Roth resolve(moduleNames); 27*cde16245SBen Roth} 28*cde16245SBen Roth 29*cde16245SBen RothRCT_REMAP_METHOD(introspectNativeModuleAsync, 30*cde16245SBen Roth introspectNativeModule:(NSString *)name 31*cde16245SBen Roth resolver:(RCTPromiseResolveBlock)resolve 32*cde16245SBen Roth rejecter:(RCTPromiseRejectBlock)reject) { 33*cde16245SBen Roth NSError *error; 34*cde16245SBen Roth NSDictionary<NSString *, RCTModuleData *> *moduleDataByName = [self _moduleDataFromBridge:&error]; 35*cde16245SBen Roth if (!moduleDataByName) { 36*cde16245SBen Roth reject(error.domain, error.userInfo[NSLocalizedDescriptionKey], error); 37*cde16245SBen Roth return; 38*cde16245SBen Roth } 39*cde16245SBen Roth 40*cde16245SBen Roth RCTModuleData *moduleData = moduleDataByName[name]; 41*cde16245SBen Roth if (!moduleData) { 42*cde16245SBen Roth resolve(nil); 43*cde16245SBen Roth return; 44*cde16245SBen Roth } 45*cde16245SBen Roth 46*cde16245SBen Roth NSArray<id<RCTBridgeMethod>> *moduleMethods = moduleData.methods; 47*cde16245SBen Roth NSMutableDictionary<NSString *, NSDictionary<NSString *, id> *> *methodDescriptions = [NSMutableDictionary dictionaryWithCapacity:moduleMethods.count]; 48*cde16245SBen Roth for (id<RCTBridgeMethod> method in moduleMethods) { 49*cde16245SBen Roth NSString *methodName = [NSString stringWithCString:method.JSMethodName encoding:NSASCIIStringEncoding]; 50*cde16245SBen Roth NSString *functionType = [NSString stringWithCString:RCTFunctionDescriptorFromType(method.functionType) 51*cde16245SBen Roth encoding:NSASCIIStringEncoding]; 52*cde16245SBen Roth methodDescriptions[methodName] = @{ @"type": functionType }; 53*cde16245SBen Roth } 54*cde16245SBen Roth 55*cde16245SBen Roth resolve(@{ @"methods": methodDescriptions }); 56*cde16245SBen Roth} 57*cde16245SBen Roth 58*cde16245SBen Roth- (NSDictionary<NSString *, RCTModuleData *> *)_moduleDataFromBridge:(NSError **)error { 59*cde16245SBen Roth RCTBridge *bridge = _bridge; 60*cde16245SBen Roth if (![NSStringFromClass(bridge.class) isEqualToString:@"RCTCxxBridge"]) { 61*cde16245SBen Roth if (error) { 62*cde16245SBen Roth *error = [NSError errorWithDomain:@"E_NATIVEMODULEINTROSPECTION_INCOMPATIBLE_BRIDGE" code:0 userInfo:@{ 63*cde16245SBen Roth NSLocalizedDescriptionKey: @"Native module introspection is compatible only with the C++ bridge", 64*cde16245SBen Roth }]; 65*cde16245SBen Roth } 66*cde16245SBen Roth return nil; 67*cde16245SBen Roth } 68*cde16245SBen Roth 69*cde16245SBen Roth NSDictionary<NSString *, RCTModuleData *> *moduleDataByName; 70*cde16245SBen Roth @try { 71*cde16245SBen Roth moduleDataByName = [bridge valueForKey:@"_moduleDataByName"]; 72*cde16245SBen Roth } 73*cde16245SBen Roth @catch (NSException *e) { 74*cde16245SBen Roth if (![e.name isEqualToString:NSUndefinedKeyException]) { 75*cde16245SBen Roth @throw; 76*cde16245SBen Roth } 77*cde16245SBen Roth 78*cde16245SBen Roth if (error) { 79*cde16245SBen Roth NSString *variableName = e.userInfo[@"NSUnknownUserInfoKey"]; 80*cde16245SBen Roth *error = [NSError errorWithDomain:@"E_NATIVEMODULEINTROSPECTION_INCOMPATIBLE_BRIDGE" code:0 userInfo:@{ 81*cde16245SBen Roth NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Bridge does not define expected variable: %@", variableName], 82*cde16245SBen Roth }]; 83*cde16245SBen Roth } 84*cde16245SBen Roth return nil; 85*cde16245SBen Roth } 86*cde16245SBen Roth 87*cde16245SBen Roth return moduleDataByName; 88*cde16245SBen Roth} 89*cde16245SBen Roth 90*cde16245SBen Roth@end 91*cde16245SBen Roth 92