RCTBridge.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import "RCTBridge.h"
  8. #import "RCTBridge+Private.h"
  9. #import <objc/runtime.h>
  10. #import "RCTConvert.h"
  11. #import "RCTEventDispatcher.h"
  12. #if RCT_ENABLE_INSPECTOR
  13. #import "RCTInspectorDevServerHelper.h"
  14. #endif
  15. #import "RCTLog.h"
  16. #import "RCTModuleData.h"
  17. #import "RCTPerformanceLogger.h"
  18. #import "RCTProfile.h"
  19. #import "RCTReloadCommand.h"
  20. #import "RCTUtils.h"
  21. NSString *const RCTJavaScriptWillStartLoadingNotification = @"RCTJavaScriptWillStartLoadingNotification";
  22. NSString *const RCTJavaScriptWillStartExecutingNotification = @"RCTJavaScriptWillStartExecutingNotification";
  23. NSString *const RCTJavaScriptDidLoadNotification = @"RCTJavaScriptDidLoadNotification";
  24. NSString *const RCTJavaScriptDidFailToLoadNotification = @"RCTJavaScriptDidFailToLoadNotification";
  25. NSString *const RCTDidInitializeModuleNotification = @"RCTDidInitializeModuleNotification";
  26. NSString *const RCTDidSetupModuleNotification = @"RCTDidSetupModuleNotification";
  27. NSString *const RCTDidSetupModuleNotificationModuleNameKey = @"moduleName";
  28. NSString *const RCTDidSetupModuleNotificationSetupTimeKey = @"setupTime";
  29. NSString *const RCTBridgeWillReloadNotification = @"RCTBridgeWillReloadNotification";
  30. NSString *const RCTBridgeFastRefreshNotification = @"RCTBridgeFastRefreshNotification";
  31. NSString *const RCTBridgeWillDownloadScriptNotification = @"RCTBridgeWillDownloadScriptNotification";
  32. NSString *const RCTBridgeDidDownloadScriptNotification = @"RCTBridgeDidDownloadScriptNotification";
  33. NSString *const RCTBridgeWillInvalidateModulesNotification = @"RCTBridgeWillInvalidateModulesNotification";
  34. NSString *const RCTBridgeDidInvalidateModulesNotification = @"RCTBridgeDidInvalidateModulesNotification";
  35. NSString *const RCTBridgeWillBeInvalidatedNotification = @"RCTBridgeWillBeInvalidatedNotification";
  36. NSString *const RCTBridgeDidDownloadScriptNotificationSourceKey = @"source";
  37. NSString *const RCTBridgeDidDownloadScriptNotificationBridgeDescriptionKey = @"bridgeDescription";
  38. static NSMutableArray<Class> *RCTModuleClasses;
  39. static dispatch_queue_t RCTModuleClassesSyncQueue;
  40. NSArray<Class> *RCTGetModuleClasses(void)
  41. {
  42. __block NSArray<Class> *result;
  43. dispatch_sync(RCTModuleClassesSyncQueue, ^{
  44. result = [RCTModuleClasses copy];
  45. });
  46. return result;
  47. }
  48. /**
  49. * Register the given class as a bridge module. All modules must be registered
  50. * prior to the first bridge initialization.
  51. */
  52. void RCTRegisterModule(Class);
  53. void RCTRegisterModule(Class moduleClass)
  54. {
  55. static dispatch_once_t onceToken;
  56. dispatch_once(&onceToken, ^{
  57. RCTModuleClasses = [NSMutableArray new];
  58. RCTModuleClassesSyncQueue =
  59. dispatch_queue_create("com.facebook.react.ModuleClassesSyncQueue", DISPATCH_QUEUE_CONCURRENT);
  60. });
  61. RCTAssert(
  62. [moduleClass conformsToProtocol:@protocol(RCTBridgeModule)],
  63. @"%@ does not conform to the RCTBridgeModule protocol",
  64. moduleClass);
  65. // Register module
  66. dispatch_barrier_async(RCTModuleClassesSyncQueue, ^{
  67. [RCTModuleClasses addObject:moduleClass];
  68. });
  69. }
  70. /**
  71. * This function returns the module name for a given class.
  72. */
  73. NSString *RCTBridgeModuleNameForClass(Class cls)
  74. {
  75. #if RCT_DEBUG
  76. RCTAssert(
  77. [cls conformsToProtocol:@protocol(RCTBridgeModule)],
  78. @"Bridge module `%@` does not conform to RCTBridgeModule",
  79. cls);
  80. #endif
  81. NSString *name = [cls moduleName];
  82. if (name.length == 0) {
  83. name = NSStringFromClass(cls);
  84. }
  85. return RCTDropReactPrefixes(name);
  86. }
  87. static BOOL turboModuleEnabled = NO;
  88. BOOL RCTTurboModuleEnabled(void)
  89. {
  90. #if RCT_DEBUG
  91. // TODO(T53341772): Allow TurboModule for test environment. Right now this breaks RNTester tests if enabled.
  92. if (RCTRunningInTestEnvironment()) {
  93. return NO;
  94. }
  95. #endif
  96. return turboModuleEnabled;
  97. }
  98. void RCTEnableTurboModule(BOOL enabled)
  99. {
  100. turboModuleEnabled = enabled;
  101. }
  102. @interface RCTBridge () <RCTReloadListener>
  103. @end
  104. @implementation RCTBridge {
  105. NSURL *_delegateBundleURL;
  106. }
  107. dispatch_queue_t RCTJSThread;
  108. + (void)initialize
  109. {
  110. static dispatch_once_t onceToken;
  111. dispatch_once(&onceToken, ^{
  112. // Set up JS thread
  113. RCTJSThread = (id)kCFNull;
  114. });
  115. }
  116. static RCTBridge *RCTCurrentBridgeInstance = nil;
  117. /**
  118. * The last current active bridge instance. This is set automatically whenever
  119. * the bridge is accessed. It can be useful for static functions or singletons
  120. * that need to access the bridge for purposes such as logging, but should not
  121. * be relied upon to return any particular instance, due to race conditions.
  122. */
  123. + (instancetype)currentBridge
  124. {
  125. return RCTCurrentBridgeInstance;
  126. }
  127. + (void)setCurrentBridge:(RCTBridge *)currentBridge
  128. {
  129. RCTCurrentBridgeInstance = currentBridge;
  130. }
  131. - (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions
  132. {
  133. return [self initWithDelegate:delegate bundleURL:nil moduleProvider:nil launchOptions:launchOptions];
  134. }
  135. - (instancetype)initWithBundleURL:(NSURL *)bundleURL
  136. moduleProvider:(RCTBridgeModuleListProvider)block
  137. launchOptions:(NSDictionary *)launchOptions
  138. {
  139. return [self initWithDelegate:nil bundleURL:bundleURL moduleProvider:block launchOptions:launchOptions];
  140. }
  141. - (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate
  142. bundleURL:(NSURL *)bundleURL
  143. moduleProvider:(RCTBridgeModuleListProvider)block
  144. launchOptions:(NSDictionary *)launchOptions
  145. {
  146. if (self = [super init]) {
  147. _delegate = delegate;
  148. _bundleURL = bundleURL;
  149. _moduleProvider = block;
  150. _launchOptions = [launchOptions copy];
  151. [self setUp];
  152. }
  153. return self;
  154. }
  155. RCT_NOT_IMPLEMENTED(-(instancetype)init)
  156. - (void)dealloc
  157. {
  158. /**
  159. * This runs only on the main thread, but crashes the subclass
  160. * RCTAssertMainQueue();
  161. */
  162. [self invalidate];
  163. }
  164. - (void)setRCTTurboModuleLookupDelegate:(id<RCTTurboModuleLookupDelegate>)turboModuleLookupDelegate
  165. {
  166. [self.batchedBridge setRCTTurboModuleLookupDelegate:turboModuleLookupDelegate];
  167. }
  168. - (void)didReceiveReloadCommand
  169. {
  170. [self reloadWithReason:@"Command"];
  171. }
  172. - (NSArray<Class> *)moduleClasses
  173. {
  174. return self.batchedBridge.moduleClasses;
  175. }
  176. - (id)moduleForName:(NSString *)moduleName
  177. {
  178. return [self.batchedBridge moduleForName:moduleName];
  179. }
  180. - (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad
  181. {
  182. return [self.batchedBridge moduleForName:moduleName lazilyLoadIfNecessary:lazilyLoad];
  183. }
  184. - (id)moduleForClass:(Class)moduleClass
  185. {
  186. id module = [self.batchedBridge moduleForClass:moduleClass];
  187. if (!module) {
  188. module = [self moduleForName:RCTBridgeModuleNameForClass(moduleClass)];
  189. }
  190. return module;
  191. }
  192. - (NSArray *)modulesConformingToProtocol:(Protocol *)protocol
  193. {
  194. NSMutableArray *modules = [NSMutableArray new];
  195. for (Class moduleClass in [self.moduleClasses copy]) {
  196. if ([moduleClass conformsToProtocol:protocol]) {
  197. id module = [self moduleForClass:moduleClass];
  198. if (module) {
  199. [modules addObject:module];
  200. }
  201. }
  202. }
  203. return [modules copy];
  204. }
  205. - (BOOL)moduleIsInitialized:(Class)moduleClass
  206. {
  207. return [self.batchedBridge moduleIsInitialized:moduleClass];
  208. }
  209. /**
  210. * DEPRECATED - please use RCTReloadCommand.
  211. */
  212. - (void)reload
  213. {
  214. [self reloadWithReason:@"Unknown from bridge"];
  215. }
  216. /**
  217. * DEPRECATED - please use RCTReloadCommand.
  218. */
  219. - (void)reloadWithReason:(NSString *)reason
  220. {
  221. #if RCT_ENABLE_INSPECTOR
  222. // Disable debugger to resume the JsVM & avoid thread locks while reloading
  223. [RCTInspectorDevServerHelper disableDebugger];
  224. #endif
  225. [[NSNotificationCenter defaultCenter] postNotificationName:RCTBridgeWillReloadNotification object:self userInfo:nil];
  226. /**
  227. * Any thread
  228. */
  229. dispatch_async(dispatch_get_main_queue(), ^{
  230. // WARNING: Invalidation is async, so it may not finish before re-setting up the bridge,
  231. // causing some issues. TODO: revisit this post-Fabric/TurboModule.
  232. [self invalidate];
  233. // Reload is a special case, do not preserve launchOptions and treat reload as a fresh start
  234. self->_launchOptions = nil;
  235. [self setUp];
  236. });
  237. }
  238. - (void)onFastRefresh
  239. {
  240. [[NSNotificationCenter defaultCenter] postNotificationName:RCTBridgeFastRefreshNotification object:self];
  241. }
  242. /**
  243. * DEPRECATED - please use RCTReloadCommand.
  244. */
  245. - (void)requestReload
  246. {
  247. [self reloadWithReason:@"Requested from bridge"];
  248. }
  249. - (Class)bridgeClass
  250. {
  251. return [RCTCxxBridge class];
  252. }
  253. - (void)setUp
  254. {
  255. RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBridge setUp]", nil);
  256. _performanceLogger = [RCTPerformanceLogger new];
  257. [_performanceLogger markStartForTag:RCTPLBridgeStartup];
  258. [_performanceLogger markStartForTag:RCTPLTTI];
  259. Class bridgeClass = self.bridgeClass;
  260. // Only update bundleURL from delegate if delegate bundleURL has changed
  261. NSURL *previousDelegateURL = _delegateBundleURL;
  262. _delegateBundleURL = [self.delegate sourceURLForBridge:self];
  263. if (_delegateBundleURL && ![_delegateBundleURL isEqual:previousDelegateURL]) {
  264. _bundleURL = _delegateBundleURL;
  265. }
  266. // Sanitize the bundle URL
  267. _bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString];
  268. RCTExecuteOnMainQueue(^{
  269. RCTRegisterReloadCommandListener(self);
  270. RCTReloadCommandSetBundleURL(self->_bundleURL);
  271. });
  272. self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self];
  273. [self.batchedBridge start];
  274. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  275. }
  276. - (BOOL)isLoading
  277. {
  278. return self.batchedBridge.loading;
  279. }
  280. - (BOOL)isValid
  281. {
  282. return self.batchedBridge.valid;
  283. }
  284. - (BOOL)isBatchActive
  285. {
  286. return [_batchedBridge isBatchActive];
  287. }
  288. - (void)invalidate
  289. {
  290. [[NSNotificationCenter defaultCenter] postNotificationName:RCTBridgeWillBeInvalidatedNotification object:self];
  291. RCTBridge *batchedBridge = self.batchedBridge;
  292. self.batchedBridge = nil;
  293. if (batchedBridge) {
  294. RCTExecuteOnMainQueue(^{
  295. [batchedBridge invalidate];
  296. });
  297. }
  298. }
  299. - (void)updateModuleWithInstance:(id<RCTBridgeModule>)instance
  300. {
  301. [self.batchedBridge updateModuleWithInstance:instance];
  302. }
  303. - (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules
  304. {
  305. [self.batchedBridge registerAdditionalModuleClasses:modules];
  306. }
  307. - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args
  308. {
  309. NSArray<NSString *> *ids = [moduleDotMethod componentsSeparatedByString:@"."];
  310. NSString *module = ids[0];
  311. NSString *method = ids[1];
  312. [self enqueueJSCall:module method:method args:args completion:NULL];
  313. }
  314. - (void)enqueueJSCall:(NSString *)module
  315. method:(NSString *)method
  316. args:(NSArray *)args
  317. completion:(dispatch_block_t)completion
  318. {
  319. [self.batchedBridge enqueueJSCall:module method:method args:args completion:completion];
  320. }
  321. - (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args
  322. {
  323. [self.batchedBridge enqueueCallback:cbID args:args];
  324. }
  325. - (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
  326. {
  327. [self.batchedBridge registerSegmentWithId:segmentId path:path];
  328. }
  329. @end