Skip to content

Commit

Permalink
fix(ios): add support for react-native-reanimated (#1197)
Browse files Browse the repository at this point in the history
  • Loading branch information
tido64 committed Nov 29, 2022
1 parent 252afb5 commit b5c0844
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 47 deletions.
14 changes: 7 additions & 7 deletions ios/ReactTestApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
192DD201240FCAF5004E9CEB /* Manifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192DD200240FCAF5004E9CEB /* Manifest.swift */; };
193B614D27F5CD7D00080064 /* React+TurboModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 193B614B27F5CD7D00080064 /* React+TurboModule.mm */; };
193B614D27F5CD7D00080064 /* BridgeDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 193B614B27F5CD7D00080064 /* BridgeDelegate.mm */; };
1963A06227C82E730013D276 /* React+Fabric.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1963A06127C82E730013D276 /* React+Fabric.mm */; };
196C22622490CB7600449D3C /* React+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 196C22602490CB7600449D3C /* React+Compatibility.m */; };
196C7215232F1788006556ED /* ReactInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196C7214232F1788006556ED /* ReactInstance.swift */; };
Expand Down Expand Up @@ -47,8 +47,8 @@
192F052624AD3CC500A48456 /* ReactTestApp.release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReactTestApp.release.xcconfig; sourceTree = "<group>"; };
192F052724AD3CC500A48456 /* ReactTestApp.common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReactTestApp.common.xcconfig; sourceTree = "<group>"; };
192F052824AD3CC500A48456 /* ReactTestApp.debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReactTestApp.debug.xcconfig; sourceTree = "<group>"; };
193B614B27F5CD7D00080064 /* React+TurboModule.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "React+TurboModule.mm"; sourceTree = "<group>"; };
193B614C27F5CD7D00080064 /* React+TurboModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "React+TurboModule.h"; sourceTree = "<group>"; };
193B614B27F5CD7D00080064 /* BridgeDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BridgeDelegate.mm; sourceTree = "<group>"; };
193B614C27F5CD7D00080064 /* BridgeDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BridgeDelegate.h; sourceTree = "<group>"; };
1963A06027C82E730013D276 /* React+Fabric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "React+Fabric.h"; sourceTree = "<group>"; };
1963A06127C82E730013D276 /* React+Fabric.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "React+Fabric.mm"; sourceTree = "<group>"; };
196C22602490CB7600449D3C /* React+Compatibility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "React+Compatibility.m"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -133,12 +133,12 @@
196C7214232F1788006556ED /* ReactInstance.swift */,
19A624A3258C95F000032776 /* Session.swift */,
196C7207232EF5DC006556ED /* ReactTestApp-Bridging-Header.h */,
193B614C27F5CD7D00080064 /* BridgeDelegate.h */,
193B614B27F5CD7D00080064 /* BridgeDelegate.mm */,
196C22612490CB7600449D3C /* React+Compatibility.h */,
196C22602490CB7600449D3C /* React+Compatibility.m */,
1963A06027C82E730013D276 /* React+Fabric.h */,
1963A06127C82E730013D276 /* React+Fabric.mm */,
193B614C27F5CD7D00080064 /* React+TurboModule.h */,
193B614B27F5CD7D00080064 /* React+TurboModule.mm */,
1988282224105BCC005057FF /* UIViewController+ReactTestApp.h */,
1988284424105BEC005057FF /* UIViewController+ReactTestApp.m */,
19ECD0DB232ED427003D8557 /* Assets.xcassets */,
Expand Down Expand Up @@ -325,13 +325,13 @@
buildActionMask = 2147483647;
files = (
19ECD0D6232ED425003D8557 /* AppDelegate.swift in Sources */,
193B614D27F5CD7D00080064 /* BridgeDelegate.mm in Sources */,
19ECD0DA232ED425003D8557 /* ContentView.swift in Sources */,
192DD201240FCAF5004E9CEB /* Manifest.swift in Sources */,
197827FA27710D3400AEC655 /* Manifest+Decoder.swift in Sources */,
196C724123319A85006556ED /* QRCodeScannerViewController.swift in Sources */,
196C22622490CB7600449D3C /* React+Compatibility.m in Sources */,
1963A06227C82E730013D276 /* React+Fabric.mm in Sources */,
193B614D27F5CD7D00080064 /* React+TurboModule.mm in Sources */,
196C7215232F1788006556ED /* ReactInstance.swift in Sources */,
19ECD0D8232ED425003D8557 /* SceneDelegate.swift in Sources */,
19A624A4258C95F000032776 /* Session.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
#if USE_TURBOMODULE

#import <React/RCTBridgeDelegate.h>

NS_ASSUME_NONNULL_BEGIN

@interface RTATurboModuleManagerDelegate : NSObject <RCTBridgeDelegate>
@interface RTABridgeDelegate : NSObject <RCTBridgeDelegate>
- (instancetype)initWithBridgeDelegate:(id<RCTBridgeDelegate>)bridgeDelegate;
@end

NS_ASSUME_NONNULL_END

#endif // USE_TURBOMODULE
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
#import "React+TurboModule.h"
#import "BridgeDelegate.h"

#if USE_TURBOMODULE
#import <React/RCTCxxBridgeDelegate.h>

#if USE_TURBOMODULE
#import <React/CoreModulesPlugins.h>
#import <React/RCTAppSetupUtils.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTDataRequestHandler.h>
#import <React/RCTFileRequestHandler.h>
#import <React/RCTGIFImageDecoder.h>
#import <React/RCTHTTPRequestHandler.h>
#import <React/RCTImageLoader.h>
#import <React/RCTJSIExecutorRuntimeInstaller.h>
#import <React/RCTLocalAssetImageLoader.h>
#import <React/RCTNetworking.h>
#import <ReactCommon/RCTTurboModuleManager.h>

@interface RTATurboModuleManagerDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate>
@interface RTABridgeDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate>
@end
#else
@interface RTABridgeDelegate () <RCTCxxBridgeDelegate>
@end
#endif // USE_TURBOMODULE

@implementation RTATurboModuleManagerDelegate {
@implementation RTABridgeDelegate {
__weak id<RCTBridgeDelegate> _bridgeDelegate;
#if USE_TURBOMODULE
RCTTurboModuleManager *_turboModuleManager;
#endif // USE_TURBOMODULE
}

- (instancetype)initWithBridgeDelegate:(id<RCTBridgeDelegate>)bridgeDelegate
Expand Down Expand Up @@ -48,15 +46,20 @@ - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:
(RCTBridge *)bridge
{
if (_turboModuleManager == nil) {
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
}
#if USE_TURBOMODULE
// jsExecutorFactoryForBridge: (USE_TURBOMODULE=1)
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
#else
// jsExecutorFactoryForBridge: (USE_TURBOMODULE=0)
return nullptr;
#endif // USE_TURBOMODULE
}

// MARK: - RCTTurboModuleManagerDelegate details
#if USE_TURBOMODULE

- (Class)getModuleClassFromName:(const char *)name
{
Expand All @@ -75,6 +78,6 @@ - (Class)getModuleClassFromName:(const char *)name
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}

@end

#endif // USE_TURBOMODULE

@end
14 changes: 2 additions & 12 deletions ios/ReactTestApp/ReactInstance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,9 @@ final class ReactInstance: NSObject, RCTBridgeDelegate {

private var surfacePresenterBridgeAdapter: NSObject?
private(set) var bridge: RCTBridge?
private lazy var bridgeDelegate = RTABridgeDelegate(bridgeDelegate: self)
private var bundleRoot: String?

#if USE_TURBOMODULE
private lazy var turboModuleManagerDelegate = RTATurboModuleManagerDelegate(bridgeDelegate: self)
#endif

override init() {
#if DEBUG
remoteBundleURL = ReactInstance.jsBundleURL()
Expand Down Expand Up @@ -112,17 +109,10 @@ final class ReactInstance: NSObject, RCTBridgeDelegate {
object: nil
)

#if USE_TURBOMODULE
guard let bridge = RCTBridge(delegate: turboModuleManagerDelegate, launchOptions: nil) else {
assertionFailure("Failed to instantiate RCTBridge with TurboModule")
return
}
#else
guard let bridge = RCTBridge(delegate: self, launchOptions: nil) else {
guard let bridge = RCTBridge(delegate: bridgeDelegate, launchOptions: nil) else {
assertionFailure("Failed to instantiate RCTBridge")
return
}
#endif // USE_TURBOMODULE

surfacePresenterBridgeAdapter = RTACreateSurfacePresenterBridgeAdapter(bridge)
self.bridge = bridge
Expand Down
2 changes: 1 addition & 1 deletion ios/ReactTestApp/ReactTestApp-Bridging-Header.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#endif // USE_FLIPPER

#import "BridgeDelegate.h"
#import "React+Compatibility.h"
#import "React+Fabric.h"
#import "React+TurboModule.h"
#import "UIViewController+ReactTestApp.h"

// Generated by `validate-manifest.js`
Expand Down
10 changes: 8 additions & 2 deletions macos/ReactTestApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
Expand All @@ -14,6 +14,7 @@
193EF08F247A799D00BE8C79 /* Manifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193EF08E247A799D00BE8C79 /* Manifest.swift */; };
193EF093247A830200BE8C79 /* UIViewController+ReactTestApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 193EF091247A830200BE8C79 /* UIViewController+ReactTestApp.m */; };
193EF098247B130700BE8C79 /* ReactInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193EF097247B130700BE8C79 /* ReactInstance.swift */; };
19510B70291D717200E4CED7 /* BridgeDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 19510B6F291D717200E4CED7 /* BridgeDelegate.mm */; };
1960F339258C97C400AEC7A2 /* Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1960F338258C97C400AEC7A2 /* Session.swift */; };
1963A06527C82F7E0013D276 /* React+Fabric.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1963A06427C82F7E0013D276 /* React+Fabric.mm */; };
196C22652490CBAB00449D3C /* React+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 196C22632490CBAB00449D3C /* React+Compatibility.m */; };
Expand Down Expand Up @@ -56,6 +57,8 @@
193EF092247A830200BE8C79 /* UIViewController+ReactTestApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+ReactTestApp.h"; path = "../ReactTestAppShared/UIViewController+ReactTestApp.h"; sourceTree = "<group>"; };
193EF094247A84DA00BE8C79 /* ReactTestApp-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ReactTestApp-Bridging-Header.h"; path = "../ReactTestAppShared/ReactTestApp-Bridging-Header.h"; sourceTree = "<group>"; };
193EF097247B130700BE8C79 /* ReactInstance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReactInstance.swift; path = ../ReactTestAppShared/ReactInstance.swift; sourceTree = "<group>"; };
19510B6E291D717200E4CED7 /* BridgeDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BridgeDelegate.h; path = ../ReactTestAppShared/BridgeDelegate.h; sourceTree = "<group>"; };
19510B6F291D717200E4CED7 /* BridgeDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BridgeDelegate.mm; path = ../ReactTestAppShared/BridgeDelegate.mm; sourceTree = "<group>"; };
1960F338258C97C400AEC7A2 /* Session.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Session.swift; path = ../ReactTestAppShared/Session.swift; sourceTree = "<group>"; };
1963A06327C82F7E0013D276 /* React+Fabric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "React+Fabric.h"; path = "../ReactTestAppShared/React+Fabric.h"; sourceTree = "<group>"; };
1963A06427C82F7E0013D276 /* React+Fabric.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "React+Fabric.mm"; path = "../ReactTestAppShared/React+Fabric.mm"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -124,6 +127,8 @@
193EF097247B130700BE8C79 /* ReactInstance.swift */,
1960F338258C97C400AEC7A2 /* Session.swift */,
193EF064247A736200BE8C79 /* ViewController.swift */,
19510B6E291D717200E4CED7 /* BridgeDelegate.h */,
19510B6F291D717200E4CED7 /* BridgeDelegate.mm */,
193EF094247A84DA00BE8C79 /* ReactTestApp-Bridging-Header.h */,
196C22642490CBAB00449D3C /* React+Compatibility.h */,
196C22632490CBAB00449D3C /* React+Compatibility.m */,
Expand Down Expand Up @@ -317,14 +322,15 @@
buildActionMask = 2147483647;
files = (
193EF063247A736200BE8C79 /* AppDelegate.swift in Sources */,
19510B70291D717200E4CED7 /* BridgeDelegate.mm in Sources */,
193EF08F247A799D00BE8C79 /* Manifest.swift in Sources */,
19C4C89327710D8500157870 /* Manifest+Decoder.swift in Sources */,
196C22652490CBAB00449D3C /* React+Compatibility.m in Sources */,
1963A06527C82F7E0013D276 /* React+Fabric.mm in Sources */,
193EF098247B130700BE8C79 /* ReactInstance.swift in Sources */,
1960F339258C97C400AEC7A2 /* Session.swift in Sources */,
193EF065247A736200BE8C79 /* ViewController.swift in Sources */,
193EF093247A830200BE8C79 /* UIViewController+ReactTestApp.m in Sources */,
193EF065247A736200BE8C79 /* ViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"/example/{metro,react-native}.config.js",
"/ios",
"/macos",
"/plugins",
"/schema.json",
"/scripts/*.js",
"/scripts/apply-config-plugins.mjs",
Expand Down
38 changes: 38 additions & 0 deletions plugins/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// @ts-check
const { withMod } = require("@expo/config-plugins");

/**
* @typedef {import("@expo/config-plugins").ExportedConfig} ExportedConfig
* @typedef {import("@expo/config-plugins").Mod} Mod
*/

/**
* Provides the `BridgeDelegate` file for modification.
* @param {ExportedConfig} config Exported config
* @param {Mod} action Method to run on the mod when the config is compiled
* @returns {ExportedConfig} Modified config
*/
function withBridgeDelegate(config, action) {
return withMod(config, {
platform: "ios",
mod: "bridgeDelegate",
action,
});
}

/**
* Provides the `SceneDelegate` file for modification.
* @param {ExportedConfig} config Exported config
* @param {Mod} action Method to run on the mod when the config is compiled
* @returns {ExportedConfig} Modified config
*/
function withSceneDelegate(config, action) {
return withMod(config, {
platform: "ios",
mod: "sceneDelegate",
action,
});
}

exports.withBridgeDelegate = withBridgeDelegate;
exports.withSceneDelegate = withSceneDelegate;
96 changes: 96 additions & 0 deletions plugins/reanimated.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// @ts-check
const { createRunOncePlugin } = require("@expo/config-plugins");
const {
mergeContents,
} = require("@expo/config-plugins/build/utils/generateCode");
const { withBridgeDelegate } = require("./index");

/**
* @typedef {import("@expo/config-plugins").ExportedConfig} ExportedConfig
*/

const NAME = "react-native-reanimated";

/**
* Adds specified contents to an existing file with a generated header.
* @param {string} tag Tag used to generate a unique header
* @param {string} src Contents of the source file
* @param {string} newSrc Contents to be added
* @param {RegExp} anchor `RegExp` providing the position at which contents is added
* @returns {string} The merged content
*/
function addContents(tag, src, newSrc, anchor) {
return mergeContents({
tag: `${NAME}-${tag}`,
src,
newSrc,
anchor,
offset: 1,
comment: "//",
}).contents;
}

/**
* Plugin to inject Reanimated's JSI executor in the React bridge delegate.
*
* Only applies to iOS.
*
* @param {ExportedConfig} config Exported config
* @returns {ExportedConfig} Modified config
*/
function withReanimatedExecutor(config) {
return withBridgeDelegate(config, (config) => {
if (config.modResults.language !== "objcpp") {
throw new Error(
"`BridgeDelegate` is not in Objective-C++ (did that change recently?)"
);
}

// Add Reanimated headers
config.modResults.contents = addContents(
"header",
config.modResults.contents,
[
"#if !USE_TURBOMODULE",
"#pragma clang diagnostic push",
'#pragma clang diagnostic ignored "-Wnullability-completeness"',
"",
"#import <RNReanimated/REAInitializer.h>",
"",
"#if __has_include(<reacthermes/HermesExecutorFactory.h>)",
"#import <reacthermes/HermesExecutorFactory.h>",
"using ExecutorFactory = HermesExecutorFactory;",
"#elif __has_include(<React/HermesExecutorFactory.h>)",
"#import <React/HermesExecutorFactory.h>",
"using ExecutorFactory = HermesExecutorFactory;",
"#else",
"#import <React/JSCExecutorFactory.h>",
"using ExecutorFactory = JSCExecutorFactory;",
"#endif",
"",
"#pragma clang diagnostic pop",
"#endif // !USE_TURBOMODULE",
].join("\n"),
/#import "BridgeDelegate\.h"/
);

// Install Reanimated's JSI executor runtime
const indent = " ";
config.modResults.contents = addContents(
"executor",
config.modResults.contents,
[
`${indent}const auto installer = reanimated::REAJSIExecutorRuntimeInstaller(bridge, nullptr);`,
`${indent}return std::make_unique<ExecutorFactory>(RCTJSIExecutorRuntimeInstaller(installer));`,
].join("\n"),
/\/\/ jsExecutorFactoryForBridge: \(USE_TURBOMODULE=0\)/
);
return config;
});
}

module.exports = createRunOncePlugin(
withReanimatedExecutor,
NAME,
"UNVERSIONED"
);
4 changes: 4 additions & 0 deletions scripts/config-plugins/plugins/withIosBaseMods.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ const defaultProviders = {
};

// `react-native-test-app` files
defaultProviders["bridgeDelegate"] = modifyFilePath(
expoProviders.appDelegate,
"ReactTestApp/BridgeDelegate.mm"
);
defaultProviders["sceneDelegate"] = modifyFilePath(
expoProviders.appDelegate,
"ReactTestApp/SceneDelegate.swift"
Expand Down

0 comments on commit b5c0844

Please sign in to comment.