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