Skip to content
Merged
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
25 changes: 22 additions & 3 deletions React/CxxBridge/RCTCxxBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,28 @@ - (void)start
// Prepare executor factory (shared_ptr for copy into block)
std::shared_ptr<JSExecutorFactory> executorFactory;
if (!self.executorClass) {
if ([self.delegate respondsToSelector:@selector(jsExecutorFactoryForBridge:)]) {
id<RCTCxxBridgeDelegate> cxxDelegate = (id<RCTCxxBridgeDelegate>)self.delegate;
executorFactory = std::make_shared<JSCExecutorFactory>(*reinterpret_cast<JSCExecutorFactory *>([cxxDelegate jsExecutorFactoryForBridge:self]));
SEL jsExecutorFactoryForBridgeSEL = @selector(jsExecutorFactoryForBridge:);
if ([self.delegate respondsToSelector:jsExecutorFactoryForBridgeSEL]) {
// Normally, `RCTCxxBridgeDelegate` protocol uses `std::unique_ptr` to return the js executor object.
// However, we needed to change the signature of `jsExecutorFactoryForBridge` to return `void *` instead. See https://github.com/expo/expo/pull/9862.
// This change works great in Expo Go because we have full control over modules initialization,
// but if someone is using our fork in the bare app, crashes may occur (`EXC_BAD_ACCESS`).
// To fix it, we need to get the return type of `jsExecutorFactoryForBridge` and handle two cases:
// - method returns `void *`
// - method returns `std::unique_ptr<JSExecutorFactory>`
Method m = class_getInstanceMethod([self.delegate class], jsExecutorFactoryForBridgeSEL);
char returnType[128];
method_getReturnType(m, returnType, sizeof(returnType));

if(strcmp(returnType, @encode(void *)) == 0) {
// `jsExecutorFactoryForBridge` returns `void *`
id<RCTCxxBridgeDelegate> cxxDelegate = (id<RCTCxxBridgeDelegate>)self.delegate;
executorFactory = std::make_shared<JSCExecutorFactory>(*reinterpret_cast<JSCExecutorFactory *>([cxxDelegate jsExecutorFactoryForBridge:self]));
} else {
// `jsExecutorFactoryForBridge` returns `std::unique_ptr<JSExecutorFactory>`
id<RCTCxxBridgeTurboModuleDelegate> cxxDelegate = (id<RCTCxxBridgeTurboModuleDelegate>)self.delegate;
executorFactory = [cxxDelegate jsExecutorFactoryForBridge:self];
}
}
if (!executorFactory) {
executorFactory = std::make_shared<JSCExecutorFactory>(nullptr);
Expand Down
9 changes: 9 additions & 0 deletions React/CxxBridge/RCTCxxBridgeDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,12 @@ class JSExecutorFactory;
- (void *)jsExecutorFactoryForBridge:(RCTBridge *)bridge;

@end

@protocol RCTCxxBridgeTurboModuleDelegate <RCTBridgeDelegate>

/**
* The RCTCxxBridgeDelegate used outside of the Expo Go.
*/
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge;

@end