Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class JSI_EXPORT TurboModule : public facebook::jsi::HostObject {
public:
TurboModule(std::string name, std::shared_ptr<CallInvoker> jsInvoker);

using BindingsInstaller = std::function<void(jsi::Runtime& runtime)>;

// Note: keep this method declared inline to avoid conflicts
// between RTTI and non-RTTI compilation units
facebook::jsi::Value get(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,20 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule {

} // namespace facebook::react

@class RCTTurboModuleBindingsInstaller;

@protocol RCTTurboModule <NSObject>

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params;

@optional

/**
* Implements this function if a TurboModule needs to install its own JSI bindings.
*/
- (nonnull RCTTurboModuleBindingsInstaller *)createBindingsInstaller;

@end

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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.
*/

#import <Foundation/Foundation.h>

#ifdef __cplusplus
#import <ReactCommon/TurboModule.h>
#endif

NS_ASSUME_NONNULL_BEGIN

/**
* This class is a holder for a RCTTurboModule to get the facebook::react::TurboModule::BindingsInstaller.
*/
@interface RCTTurboModuleBindingsInstaller : NSObject

- (instancetype)init NS_UNAVAILABLE;

#ifdef __cplusplus
- (instancetype)initWithBindingsInstaller:(facebook::react::TurboModule::BindingsInstaller)bindingsInstaller
NS_DESIGNATED_INITIALIZER;

- (facebook::react::TurboModule::BindingsInstaller)get;
#endif

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.
*/

#import "RCTTurboModuleBindingsInstaller.h"

@implementation RCTTurboModuleBindingsInstaller {
facebook::react::TurboModule::BindingsInstaller _bindingsInstaller;
}

- (instancetype)initWithBindingsInstaller:(facebook::react::TurboModule::BindingsInstaller)bindingsInstaller
{
if (self = [super init]) {
_bindingsInstaller = bindingsInstaller;
}

return self;
}

- (facebook::react::TurboModule::BindingsInstaller)get
{
return _bindingsInstaller;
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#import <React/RCTRuntimeExecutorModule.h>
#import <React/RCTUtils.h>
#import <ReactCommon/CxxTurboModuleUtils.h>
#import <ReactCommon/RCTTurboModuleBindingsInstaller.h>
#import <ReactCommon/TurboCxxModule.h>
#import <ReactCommon/TurboModulePerfLogger.h>
#import <ReactCommon/TurboModuleUtils.h>
Expand Down Expand Up @@ -305,7 +306,7 @@ - (instancetype)initWithBridgeProxy:(RCTBridgeProxy *)bridgeProxy
* (for now).
*/

- (std::shared_ptr<TurboModule>)provideTurboModule:(const char *)moduleName
- (std::shared_ptr<TurboModule>)provideTurboModule:(const char *)moduleName runtime:(facebook::jsi::Runtime *)runtime
{
auto turboModuleLookup = _turboModuleCache.find(moduleName);
if (turboModuleLookup != _turboModuleCache.end()) {
Expand Down Expand Up @@ -409,6 +410,12 @@ - (instancetype)initWithBridgeProxy:(RCTBridgeProxy *)bridgeProxy
RCTLogError(@"TurboModule \"%@\"'s getTurboModule: method returned nil.", moduleClass);
}
_turboModuleCache.insert({moduleName, turboModule});

if ([module respondsToSelector:@selector(createBindingsInstaller)]) {
RCTTurboModuleBindingsInstaller *installer =
(RCTTurboModuleBindingsInstaller *)[module performSelector:@selector(createBindingsInstaller)];
[installer get](*runtime);
}
return turboModule;
}

Expand Down Expand Up @@ -771,7 +778,7 @@ - (BOOL)_shouldCreateObjCModule:(Class)moduleClass
* Attach method queue to id<RCTBridgeModule> object.
* This is necessary because the id<RCTBridgeModule> object can be eagerly created/initialized before the method
* queue is required. The method queue is required for an id<RCTBridgeModule> for JS -> Native calls. So, we need it
* before we create the id<RCTBridgeModule>'s TurboModule jsi::HostObject in provideTurboModule:.
* before we create the id<RCTBridgeModule>'s TurboModule jsi::HostObject in provideTurboModule:runtime:.
*/
objc_setAssociatedObject(module, &kAssociatedMethodQueueKey, methodQueue, OBJC_ASSOCIATION_RETAIN);

Expand Down Expand Up @@ -921,7 +928,8 @@ - (void)installJSBindings:(facebook::jsi::Runtime &)runtime
* aren't any strong references to it in ObjC. Hence, we give
* __turboModuleProxy a strong reference to TurboModuleManager.
*/
auto turboModuleProvider = [self](const std::string &name) -> std::shared_ptr<react::TurboModule> {
auto turboModuleProvider = [self,
runtime = &runtime](const std::string &name) -> std::shared_ptr<react::TurboModule> {
auto moduleName = name.c_str();

TurboModulePerfLogger::moduleJSRequireBeginningStart(moduleName);
Expand All @@ -935,7 +943,7 @@ - (void)installJSBindings:(facebook::jsi::Runtime &)runtime
* Additionally, if a TurboModule with the name `name` isn't found, then we
* trigger an assertion failure.
*/
auto turboModule = [self provideTurboModule:moduleName];
auto turboModule = [self provideTurboModule:moduleName runtime:runtime];

if (moduleWasNotInitialized && [self moduleIsInitialized:moduleName]) {
[self->_bridge.performanceLogger markStopForTag:RCTPLTurboModuleSetup];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#import <Foundation/Foundation.h>
#import <ReactCommon/RCTTurboModuleBindingsInstaller.h>

#import "RCTNativeSampleTurboModuleSpec.h"

Expand All @@ -15,4 +16,6 @@
*/
@interface RCTSampleTurboModule : NSObject <NativeSampleTurboModuleSpec>

- (nonnull RCTTurboModuleBindingsInstaller *)createBindingsInstaller;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ - (dispatch_queue_t)methodQueue
return std::make_shared<NativeSampleTurboModuleSpecJSI>(params);
}

- (RCTTurboModuleBindingsInstaller *)createBindingsInstaller;
{
return [[RCTTurboModuleBindingsInstaller alloc] initWithBindingsInstaller:[](facebook::jsi::Runtime &runtime) {
runtime.global().setProperty(runtime, "__SampleTurboModuleJSIBindings", "Hello JSI!");
}];
}

// Backward compatible invalidation
- (void)invalidate
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ class SampleTurboModuleExample extends React.Component<{||}, State> {
this._setResult('promiseAssert', e.message);
});
},
installJSIBindings: () => {
return global.__SampleTurboModuleJSIBindings;
},
};

_setResult(
Expand Down Expand Up @@ -194,6 +197,11 @@ class SampleTurboModuleExample extends React.Component<{||}, State> {
'Cannot load this example because TurboModule is not configured.',
);
}
if (global.__SampleTurboModuleJSIBindings == null) {
throw new Error(
'The JSI bindings for SampleTurboModule are not installed.',
);
}
}

render(): React.Node {
Expand Down