react-native-macos/React/Base/RCTBridge.h

343 строки
12 KiB
C
Исходник Обычный вид История

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
2015-04-02 17:33:21 +03:00
#import <UIKit/UIKit.h>
#import <React/RCTBridgeDelegate.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTDefines.h>
#import <React/RCTFrameUpdate.h>
#import <React/RCTInvalidating.h>
@class JSValue;
@class RCTBridge;
@class RCTPerformanceLogger;
/**
* This notification fires when the bridge initializes.
*/
RCT_EXTERN NSString *const RCTJavaScriptWillStartLoadingNotification;
/**
* This notification fires when the bridge starts executing the JS bundle.
*/
RCT_EXTERN NSString *const RCTJavaScriptWillStartExecutingNotification;
2015-04-12 01:08:00 +03:00
/**
* This notification fires when the bridge has finished loading the JS bundle.
2015-04-12 01:08:00 +03:00
*/
RCT_EXTERN NSString *const RCTJavaScriptDidLoadNotification;
2015-04-12 01:08:00 +03:00
/**
* This notification fires when the bridge failed to load the JS bundle. The
* `error` key can be used to determine the error that occurred.
*/
RCT_EXTERN NSString *const RCTJavaScriptDidFailToLoadNotification;
/**
* This notification fires each time a native module is instantiated. The
* `module` key will contain a reference to the newly-created module instance.
* Note that this notification may be fired before the module is available via
* the `[bridge moduleForClass:]` method.
*/
RCT_EXTERN NSString *const RCTDidInitializeModuleNotification;
2019-03-22 20:39:38 +03:00
/**
* This notification fires each time a module is setup after it is initialized. The
2019-03-22 20:39:38 +03:00
* `RCTDidSetupModuleNotificationModuleNameKey` key will contain a reference to the module name and
* `RCTDidSetupModuleNotificationSetupTimeKey` will contain the setup time in ms.
*/
RCT_EXTERN NSString *const RCTDidSetupModuleNotification;
/**
* Key for the module name (NSString) in the
* RCTDidSetupModuleNotification userInfo dictionary.
*/
RCT_EXTERN NSString *const RCTDidSetupModuleNotificationModuleNameKey;
/**
* Key for the setup time (NSNumber) in the
* RCTDidSetupModuleNotification userInfo dictionary.
*/
RCT_EXTERN NSString *const RCTDidSetupModuleNotificationSetupTimeKey;
/**
* DEPRECATED - Use RCTReloadCommand instead. This notification fires just before the bridge starts
* processing a request to reload.
*/
RCT_EXTERN NSString *const RCTBridgeWillReloadNotification;
/**
* This notification fires whenever a fast refresh happens.
*/
RCT_EXTERN NSString *const RCTBridgeFastRefreshNotification;
/**
* This notification fires just before the bridge begins downloading a script
* from the packager.
*/
RCT_EXTERN NSString *const RCTBridgeWillDownloadScriptNotification;
/**
* This notification fires just after the bridge finishes downloading a script
* from the packager.
*/
RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotification;
/**
* This notification fires right after the bridge is about to invalidate NativeModule
* instances during teardown. Handle this notification to perform additional invalidation.
*/
RCT_EXTERN NSString *const RCTBridgeWillInvalidateModulesNotification;
/**
* This notification fires right after the bridge finishes invalidating NativeModule
* instances during teardown. Handle this notification to perform additional invalidation.
*/
RCT_EXTERN NSString *const RCTBridgeDidInvalidateModulesNotification;
/**
* This notification fires right before the bridge starting invalidation process.
* Handle this notification to perform additional invalidation.
* The notification can be issued on any thread.
*/
RCT_EXTERN NSString *const RCTBridgeWillBeInvalidatedNotification;
/**
* Key for the RCTSource object in the RCTBridgeDidDownloadScriptNotification
* userInfo dictionary.
*/
RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotificationSourceKey;
/**
* Key for the reload reason in the RCTBridgeWillReloadNotification userInfo dictionary.
*/
RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotificationReasonKey;
/**
* Key for the bridge description (NSString_ in the
* RCTBridgeDidDownloadScriptNotification userInfo dictionary.
*/
RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotificationBridgeDescriptionKey;
/**
* This block can be used to instantiate modules that require additional
* init parameters, or additional configuration prior to being used.
* The bridge will call this block to instantiate the modules, and will
* be responsible for invalidating/releasing them when the bridge is destroyed.
* For this reason, the block should always return new module instances, and
* module instances should not be shared between bridges.
*/
typedef NSArray<id<RCTBridgeModule>> * (^RCTBridgeModuleListProvider)(void);
/**
* These blocks are used to report whether an additional bundle
* fails or succeeds loading.
*/
typedef void (^RCTLoadAndExecuteErrorBlock)(NSError *error);
/**
* This function returns the module name for a given class.
*/
2015-04-21 15:26:51 +03:00
RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
/**
* Experimental.
* Check/set if JSI-bound NativeModule is enabled. By default it's off.
*/
RCT_EXTERN BOOL RCTTurboModuleEnabled(void);
RCT_EXTERN void RCTEnableTurboModule(BOOL enabled);
// Turn on TurboModule eager initialization
RCT_EXTERN BOOL RCTTurboModuleEagerInitEnabled(void);
RCT_EXTERN void RCTEnableTurboModuleEagerInit(BOOL enabled);
// Turn on TurboModule shared mutex initialization
RCT_EXTERN BOOL RCTTurboModuleSharedMutexInitEnabled(void);
RCT_EXTERN void RCTEnableTurboModuleSharedMutexInit(BOOL enabled);
Conditionally disable TurboModuleManager delegate locking Summary: ## Context Whenever the TurboModuleManager calls into its delegate, it [acquires a lock](https://www.internalfb.com/code/fbsource/[f14548634e72009989c844a2ef025915ef74159e]/xplat/js/react-native-github/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm?lines=429%2C513). We initially introduced this mutex (in D21170099 (https://github.com/facebook/react-native/commit/2c473e1a38c35957fe80b6c334a1983c034c2bbc)). It serializes access to the TurboModuleManager delegate during TurboModule create. ## Problems - When we call into the delegate, we acquire a lock, and call into arbitrary product code: getModuleClassFromName, getModuleInstanceFromClass. If any of these two product methods create another TurboModule, the application will deadlock, because we'll acquire the same std::mutex twice. ## Fix The delegate methods of TurboModuleManager are usually implemented as [switch cases over the NativeModule names or NativeModule classes](https://www.internalfb.com/code/fbsource/[f015e461de4e7a18d0d52a697a53086fe6a3b91c]/fbobjc/Apps/Wilde/FBReactModule2/FBReactModuleAPI/FBReactModuleAPI/Exported/FBReactModule.mm?lines=1481-1488%2C1490-1537%2C1539-1577). So, it should be safe to call into them concurrently for two different modules. So, while we could fix the problem by migrating the TurboModuleManager to an std::recursive_mutex, one could make an argument that this locking shouldn't even be necessary in the first place. We don't have this locking in the Android TurboModule system. ## Changes This diff introduces a flag in React Native that allows to to safely remove this TurboModuleManager delegate locking in production. Changelog: [Internal] Reviewed By: sammy-SC Differential Revision: D30754875 fbshipit-source-id: d04a831c18a2a8b46e9bc07ddf690d8e4d0be8e0
2021-09-08 22:49:15 +03:00
// Turn off TurboModule delegate locking
RCT_EXTERN BOOL RCTTurboModuleManagerDelegateLockingDisabled(void);
RCT_EXTERN void RCTDisableTurboModuleManagerDelegateLocking(BOOL enabled);
// Turn off validAttribute: entries inside ViewConfigs for events
// TODO(109509380): Remove this gating
RCT_EXTERN BOOL RCTViewConfigEventValidAttributesDisabled(void);
RCT_EXTERN void RCTDisableViewConfigEventValidAttributes(BOOL disabled);
Stop sharing LongLivedObjectCollection with the bridge Summary: ## Context Previously, when you'd call TurboModule methods with JavaScript callbacks, we'd [store the callbacks](https://www.internalfb.com/code/fbsource/[c503ff1b38621aebca87b2bbebeae088b01886c4]/xplat/js/react-native-github/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModule.mm?lines=173%2C248-249) into [this global LongLivedObjectCollection collection](https://www.internalfb.com/code/fbsource/[c503ff1b38621aebca87b2bbebeae088b01886c4]/xplat/js/react-native-github/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleUtils.h?lines=65). Then, when React Native's JavaScript VM got torn down, we'd [clear the global collection](https://www.internalfb.com/code/fbsource/[e26f476ce208c578f05b1edb7639d1dad5612c7d]/xplat/js/react-native-github/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp?lines=49), which would ensure that we deleted all held jsi::Functions, before deleting the jsi::Runtime. ## Problem With bridgeless mode enabled, there can be two TurboModule systems. Further, it is possible to tear down bridgeless mode, or the bridge, without tearing down the other initialization infra. In this scenario, the jsi::Function for the other initialization infra would also get deleted, which could lead to mysterious problems. ## Fix In this diff, I refactored the jsi::Function cleanup in the TurboModule system. Now, there are 3 modes: - kGlobalScope: Everything works as it did before - kRCTGlobalScopeUsingRetainJSCallback: We still use the global LongLivedObjectCollection, but we do it through invoking a block passed to every ObjCTurboModule by the TurboModuleManager. This group exists to assess the impact of having each TurboModule retain/use the block. I suspect this will be negligible, but it'd be good to have actual data to back this claim. - kRCTTurboModuleManagerScope: Every TurboModule uses a LongLivedObjectCollection that is owned by its TurboModuleManager. This should effectively fix the problem I outlined above. Changelog: [Internal] Reviewed By: p-sun Differential Revision: D30019833 fbshipit-source-id: da50d884c7e37190107f570d8ed70eeda7d9ae83
2021-08-02 21:19:47 +03:00
typedef enum {
kRCTGlobalScope,
kRCTGlobalScopeUsingRetainJSCallback,
kRCTTurboModuleManagerScope,
} RCTTurboModuleCleanupMode;
RCT_EXTERN RCTTurboModuleCleanupMode RCTGetTurboModuleCleanupMode(void);
RCT_EXTERN void RCTSetTurboModuleCleanupMode(RCTTurboModuleCleanupMode mode);
/**
* Async batched bridge used to communicate with the JavaScript application.
*/
@interface RCTBridge : NSObject <RCTInvalidating>
/**
* Creates a new bridge with a custom RCTBridgeDelegate.
*
* All the interaction with the JavaScript context should be done using the bridge
* instance of the RCTBridgeModules. Modules will be automatically instantiated
* using the default contructor, but you can optionally pass in an array of
* pre-initialized module instances if they require additional init parameters
* or configuration.
*/
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions;
/**
* DEPRECATED: Use initWithDelegate:launchOptions: instead
*
* The designated initializer. This creates a new bridge on top of the specified
* executor. The bridge should then be used for all subsequent communication
* with the JavaScript code running in the executor. Modules will be automatically
* instantiated using the default contructor, but you can optionally pass in an
* array of pre-initialized module instances if they require additional init
* parameters or configuration.
*/
2015-04-12 01:08:00 +03:00
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
moduleProvider:(RCTBridgeModuleListProvider)block
launchOptions:(NSDictionary *)launchOptions;
/**
* This method is used to call functions in the JavaScript application context.
* It is primarily intended for use by modules that require two-way communication
* with the JavaScript code. Safe to call from any thread.
*/
- (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args;
- (void)enqueueJSCall:(NSString *)module
method:(NSString *)method
args:(NSArray *)args
completion:(dispatch_block_t)completion;
/**
* This method registers the file path of an additional JS segment by its ID.
*
* @experimental
*/
- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path;
/**
Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 14:09:00 +03:00
* Retrieve a bridge module instance by name or class. Note that modules are
* lazily instantiated, so calling these methods for the first time with a given
* module name/class may cause the class to be synchronously instantiated,
* potentially blocking both the calling thread and main thread for a short time.
*
* Note: This method does NOT lazily load the particular module if it's not yet loaded.
Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 14:09:00 +03:00
*/
- (id)moduleForName:(NSString *)moduleName;
- (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad;
// Note: This method lazily load the module as necessary.
Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 14:09:00 +03:00
- (id)moduleForClass:(Class)moduleClass;
Enable module lookup in TurboModules Summary: NativeModules are instantiated by the bridge. If they choose, they can capture the bridge instance that instantiated them. From within the NativeModule, the bridge can then be used to lookup other NativeModules. TurboModules have no way to do such a lookup. Both NativeModules and TurboModules need to be able to query for one another. Therefore, we have four cases: 1. NativeModule accesses NativeModule. 2. NativeModule accesses TurboModule. 3. TurboModule accesses NativeModule. 4. TurboModule accesses TurboModule. In summary, this solution extends the bridge to support querying TurboModules. It also introduces a `RCTTurboModuleLookupDelegate` protocol, which, implemented by `RCTTurboModuleManager`, supports querying TurboModules: ``` protocol RCTTurboModuleLookupDelegate <NSObject> - (id)moduleForName:(NSString *)moduleName; - (id)moduleForName:(NSString *)moduleName warnOnLookupFailure:(BOOL)warnOnLookupFailure; - (BOOL)moduleIsInitialized:(NSString *)moduleName end ``` If TurboModules want to query other TurboModules, then they need to implement this protocol and synthesize `turboModuleLookupDelegate`: ``` protocol RCTTurboModuleWithLookupCapabilities property (nonatomic, weak) id<RCTTurboModuleLookupDelegate> turboModuleLookupDelegate; end ``` NativeModules will continue to use `RCTBridge` to access other NativeModules. Nothing needs to change. When we attach the bridge to `RCTTurboModuleManager`, we also attach `RCTTurboModuleManager` to the bridge as a `RCTTurboModuleLookupDelegate`. This allows the bridge to query TurboModules, which enables our NativeModules to transparently (i.e: without any NativeModule code modification) query TurboModules. In an ideal world, all modules would be TurboModules. Until then, we're going to require that TurboModules use the bridge to query for NativeModules or TurboModules. `RCTTurboModuleManager` keeps a map of all TurboModules that we instantiated. We simply search in this map and return the TurboModule. This setup allows us to switch NativeModules to TurboModules without compromising their ability to use the bridge to search for other NativeModules (and TurboModules). When we write new TurboModules, we can have them use `RCTTurboModuleLookupDelegate` to do access other TurboModules. Eventually, after we migrate all NativeModules to TurboModules, we can migrate all old callsites to use `RCTTurboModuleLookupDelegate`. Reviewed By: fkgozali Differential Revision: D13553186 fbshipit-source-id: 4d0488eef081332c8b70782e1337eccf10717dae
2019-01-31 22:04:45 +03:00
/**
* When a NativeModule performs a lookup for a TurboModule, we need to query
* the TurboModuleRegistry.
Enable module lookup in TurboModules Summary: NativeModules are instantiated by the bridge. If they choose, they can capture the bridge instance that instantiated them. From within the NativeModule, the bridge can then be used to lookup other NativeModules. TurboModules have no way to do such a lookup. Both NativeModules and TurboModules need to be able to query for one another. Therefore, we have four cases: 1. NativeModule accesses NativeModule. 2. NativeModule accesses TurboModule. 3. TurboModule accesses NativeModule. 4. TurboModule accesses TurboModule. In summary, this solution extends the bridge to support querying TurboModules. It also introduces a `RCTTurboModuleLookupDelegate` protocol, which, implemented by `RCTTurboModuleManager`, supports querying TurboModules: ``` protocol RCTTurboModuleLookupDelegate <NSObject> - (id)moduleForName:(NSString *)moduleName; - (id)moduleForName:(NSString *)moduleName warnOnLookupFailure:(BOOL)warnOnLookupFailure; - (BOOL)moduleIsInitialized:(NSString *)moduleName end ``` If TurboModules want to query other TurboModules, then they need to implement this protocol and synthesize `turboModuleLookupDelegate`: ``` protocol RCTTurboModuleWithLookupCapabilities property (nonatomic, weak) id<RCTTurboModuleLookupDelegate> turboModuleLookupDelegate; end ``` NativeModules will continue to use `RCTBridge` to access other NativeModules. Nothing needs to change. When we attach the bridge to `RCTTurboModuleManager`, we also attach `RCTTurboModuleManager` to the bridge as a `RCTTurboModuleLookupDelegate`. This allows the bridge to query TurboModules, which enables our NativeModules to transparently (i.e: without any NativeModule code modification) query TurboModules. In an ideal world, all modules would be TurboModules. Until then, we're going to require that TurboModules use the bridge to query for NativeModules or TurboModules. `RCTTurboModuleManager` keeps a map of all TurboModules that we instantiated. We simply search in this map and return the TurboModule. This setup allows us to switch NativeModules to TurboModules without compromising their ability to use the bridge to search for other NativeModules (and TurboModules). When we write new TurboModules, we can have them use `RCTTurboModuleLookupDelegate` to do access other TurboModules. Eventually, after we migrate all NativeModules to TurboModules, we can migrate all old callsites to use `RCTTurboModuleLookupDelegate`. Reviewed By: fkgozali Differential Revision: D13553186 fbshipit-source-id: 4d0488eef081332c8b70782e1337eccf10717dae
2019-01-31 22:04:45 +03:00
*/
- (void)setRCTTurboModuleRegistry:(id<RCTTurboModuleRegistry>)turboModuleRegistry;
Enable module lookup in TurboModules Summary: NativeModules are instantiated by the bridge. If they choose, they can capture the bridge instance that instantiated them. From within the NativeModule, the bridge can then be used to lookup other NativeModules. TurboModules have no way to do such a lookup. Both NativeModules and TurboModules need to be able to query for one another. Therefore, we have four cases: 1. NativeModule accesses NativeModule. 2. NativeModule accesses TurboModule. 3. TurboModule accesses NativeModule. 4. TurboModule accesses TurboModule. In summary, this solution extends the bridge to support querying TurboModules. It also introduces a `RCTTurboModuleLookupDelegate` protocol, which, implemented by `RCTTurboModuleManager`, supports querying TurboModules: ``` protocol RCTTurboModuleLookupDelegate <NSObject> - (id)moduleForName:(NSString *)moduleName; - (id)moduleForName:(NSString *)moduleName warnOnLookupFailure:(BOOL)warnOnLookupFailure; - (BOOL)moduleIsInitialized:(NSString *)moduleName end ``` If TurboModules want to query other TurboModules, then they need to implement this protocol and synthesize `turboModuleLookupDelegate`: ``` protocol RCTTurboModuleWithLookupCapabilities property (nonatomic, weak) id<RCTTurboModuleLookupDelegate> turboModuleLookupDelegate; end ``` NativeModules will continue to use `RCTBridge` to access other NativeModules. Nothing needs to change. When we attach the bridge to `RCTTurboModuleManager`, we also attach `RCTTurboModuleManager` to the bridge as a `RCTTurboModuleLookupDelegate`. This allows the bridge to query TurboModules, which enables our NativeModules to transparently (i.e: without any NativeModule code modification) query TurboModules. In an ideal world, all modules would be TurboModules. Until then, we're going to require that TurboModules use the bridge to query for NativeModules or TurboModules. `RCTTurboModuleManager` keeps a map of all TurboModules that we instantiated. We simply search in this map and return the TurboModule. This setup allows us to switch NativeModules to TurboModules without compromising their ability to use the bridge to search for other NativeModules (and TurboModules). When we write new TurboModules, we can have them use `RCTTurboModuleLookupDelegate` to do access other TurboModules. Eventually, after we migrate all NativeModules to TurboModules, we can migrate all old callsites to use `RCTTurboModuleLookupDelegate`. Reviewed By: fkgozali Differential Revision: D13553186 fbshipit-source-id: 4d0488eef081332c8b70782e1337eccf10717dae
2019-01-31 22:04:45 +03:00
/**
* This hook is called by the TurboModule infra with every TurboModule that's created.
* It allows the bridge to attach properties to TurboModules that give TurboModules
* access to Bridge APIs.
*/
- (void)attachBridgeAPIsToTurboModule:(id<RCTTurboModule>)module;
/**
* Convenience method for retrieving all modules conforming to a given protocol.
* Modules will be synchronously instantiated if they haven't already been,
* potentially blocking both the calling thread and main thread for a short time.
*/
- (NSArray *)modulesConformingToProtocol:(Protocol *)protocol;
/**
* Test if a module has been initialized. Use this prior to calling
* `moduleForClass:` or `moduleForName:` if you do not want to cause the module
* to be instantiated if it hasn't been already.
*/
- (BOOL)moduleIsInitialized:(Class)moduleClass;
Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 14:09:00 +03:00
/**
* All registered bridge module classes.
*/
Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 14:09:00 +03:00
@property (nonatomic, copy, readonly) NSArray<Class> *moduleClasses;
2015-04-21 00:04:53 +03:00
/**
* URL of the script that was loaded into the bridge.
*/
@property (nonatomic, strong, readonly) NSURL *bundleURL;
2015-04-21 00:04:53 +03:00
/**
* The class of the executor currently being used. Changes to this value will
* take effect after the bridge is reloaded.
*/
2015-04-02 17:33:21 +03:00
@property (nonatomic, strong) Class executorClass;
/**
* The delegate provided during the bridge initialization
*/
@property (nonatomic, weak, readonly) id<RCTBridgeDelegate> delegate;
/**
* The launch options that were used to initialize the bridge.
*/
2015-03-26 04:59:42 +03:00
@property (nonatomic, copy, readonly) NSDictionary *launchOptions;
/**
* Use this to check if the bridge is currently loading.
*/
2015-04-12 01:08:00 +03:00
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
/**
* Use this to check if the bridge has been invalidated.
*/
@property (nonatomic, readonly, getter=isValid) BOOL valid;
/**
* Link to the Performance Logger that logs React Native perf events.
*/
@property (nonatomic, readonly, strong) RCTPerformanceLogger *performanceLogger;
/**
Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 14:09:00 +03:00
* Reload the bundle and reset executor & modules. Safe to call from any thread.
*/
Deprecate bridge reload API [1/n] Summary: Testing the waters with an idea for unifying RN lifecycle with/without bridge. ### Motivation/Background RN bridge is being reloaded from [several different places](https://fburl.com/codesearch/ae3zeatt). When this happens, the bridge does a bunch of things: 1. Post `RCTBridgeWillReloadNotification` (RCTSurfacePresenter listens to this and reloads) 2. Invalidate batched bridge, which does: a. invalidate display link b. post `RCTBridgeWillInvalidateModules/RCTBridgeDidInvalidateModules` (TurboModuleManager listens to this and reloads modules) c. clear js thread state d. clear some local caches 3. Set up (reload bundle and batched bridge) In a bridgeless world, there isn't one thing which owns all these peices of infra, and can reload them. ### Plan Use `RCTReloadCommand` to handle reloads. This light class previously only handled CMD+R. The new workflow looks like this: 1. Anything which cares about reloads can register itself as a listener. (RCTBridge, RCTSurfacePresenter, TurboModuleManager...) 2. Anything that previously called `bridge reload` now calls `RCTTriggerReloadCommandListeners`. 3. Delete old notifications ### Alternate Plan Use yet another NSNotification. I like `RCTReloadCommand` better. ### Unknowns Looks like we log the reason for bridge reloading [here](https://fburl.com/diffusion/lc9jj8la), do we want to save this behaviour? Does anyone look at why bridge is being reloaded cc/Rick? If so, I can add back that functionality to `RCTReloadCommand`. It should be possible to customize the order/priority of what gets reloaded first. There may be some racy behaviour that I haven't thought about yet. Changelog: [iOS][Deprecated] Deprecate [bridge reload] API - prefer RCTReloadCommand Reviewed By: shergin Differential Revision: D17869635 fbshipit-source-id: 81f39eaa2c3ce08ea1bc6f2193684c2630d81a2d
2019-10-30 22:20:29 +03:00
- (void)reload __deprecated_msg("Use RCTReloadCommand instead");
/**
* Reload the bundle and reset executor & modules. Safe to call from any thread.
*/
Deprecate bridge reload API [1/n] Summary: Testing the waters with an idea for unifying RN lifecycle with/without bridge. ### Motivation/Background RN bridge is being reloaded from [several different places](https://fburl.com/codesearch/ae3zeatt). When this happens, the bridge does a bunch of things: 1. Post `RCTBridgeWillReloadNotification` (RCTSurfacePresenter listens to this and reloads) 2. Invalidate batched bridge, which does: a. invalidate display link b. post `RCTBridgeWillInvalidateModules/RCTBridgeDidInvalidateModules` (TurboModuleManager listens to this and reloads modules) c. clear js thread state d. clear some local caches 3. Set up (reload bundle and batched bridge) In a bridgeless world, there isn't one thing which owns all these peices of infra, and can reload them. ### Plan Use `RCTReloadCommand` to handle reloads. This light class previously only handled CMD+R. The new workflow looks like this: 1. Anything which cares about reloads can register itself as a listener. (RCTBridge, RCTSurfacePresenter, TurboModuleManager...) 2. Anything that previously called `bridge reload` now calls `RCTTriggerReloadCommandListeners`. 3. Delete old notifications ### Alternate Plan Use yet another NSNotification. I like `RCTReloadCommand` better. ### Unknowns Looks like we log the reason for bridge reloading [here](https://fburl.com/diffusion/lc9jj8la), do we want to save this behaviour? Does anyone look at why bridge is being reloaded cc/Rick? If so, I can add back that functionality to `RCTReloadCommand`. It should be possible to customize the order/priority of what gets reloaded first. There may be some racy behaviour that I haven't thought about yet. Changelog: [iOS][Deprecated] Deprecate [bridge reload] API - prefer RCTReloadCommand Reviewed By: shergin Differential Revision: D17869635 fbshipit-source-id: 81f39eaa2c3ce08ea1bc6f2193684c2630d81a2d
2019-10-30 22:20:29 +03:00
- (void)reloadWithReason:(NSString *)reason __deprecated_msg("Use RCTReloadCommand instead");
Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 14:09:00 +03:00
/**
* Handle notifications for a fast refresh. Safe to call from any thread.
*/
- (void)onFastRefresh;
/**
* Inform the bridge, and anything subscribing to it, that it should reload.
*/
Deprecate bridge reload API [1/n] Summary: Testing the waters with an idea for unifying RN lifecycle with/without bridge. ### Motivation/Background RN bridge is being reloaded from [several different places](https://fburl.com/codesearch/ae3zeatt). When this happens, the bridge does a bunch of things: 1. Post `RCTBridgeWillReloadNotification` (RCTSurfacePresenter listens to this and reloads) 2. Invalidate batched bridge, which does: a. invalidate display link b. post `RCTBridgeWillInvalidateModules/RCTBridgeDidInvalidateModules` (TurboModuleManager listens to this and reloads modules) c. clear js thread state d. clear some local caches 3. Set up (reload bundle and batched bridge) In a bridgeless world, there isn't one thing which owns all these peices of infra, and can reload them. ### Plan Use `RCTReloadCommand` to handle reloads. This light class previously only handled CMD+R. The new workflow looks like this: 1. Anything which cares about reloads can register itself as a listener. (RCTBridge, RCTSurfacePresenter, TurboModuleManager...) 2. Anything that previously called `bridge reload` now calls `RCTTriggerReloadCommandListeners`. 3. Delete old notifications ### Alternate Plan Use yet another NSNotification. I like `RCTReloadCommand` better. ### Unknowns Looks like we log the reason for bridge reloading [here](https://fburl.com/diffusion/lc9jj8la), do we want to save this behaviour? Does anyone look at why bridge is being reloaded cc/Rick? If so, I can add back that functionality to `RCTReloadCommand`. It should be possible to customize the order/priority of what gets reloaded first. There may be some racy behaviour that I haven't thought about yet. Changelog: [iOS][Deprecated] Deprecate [bridge reload] API - prefer RCTReloadCommand Reviewed By: shergin Differential Revision: D17869635 fbshipit-source-id: 81f39eaa2c3ce08ea1bc6f2193684c2630d81a2d
2019-10-30 22:20:29 +03:00
- (void)requestReload __deprecated_msg("Use RCTReloadCommand instead");
/**
* Says whether bridge has started receiving calls from JavaScript.
*/
- (BOOL)isBatchActive;
/**
* Loads and executes additional bundles in the VM for development.
*/
- (void)loadAndExecuteSplitBundleURL:(NSURL *)bundleURL
onError:(RCTLoadAndExecuteErrorBlock)onError
onComplete:(dispatch_block_t)onComplete;
Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 14:09:00 +03:00
@end