@rnx-kit/react-native-host 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ReactNativeHost.podspec +31 -5
- package/cocoa/RNXFabricAdapter.h +9 -0
- package/cocoa/RNXFabricAdapter.mm +27 -0
- package/cocoa/RNXHostConfig.h +41 -0
- package/cocoa/RNXHostReleaser.h +19 -0
- package/cocoa/RNXHostReleaser.mm +74 -0
- package/cocoa/RNXTurboModuleAdapter.h +29 -0
- package/cocoa/RNXTurboModuleAdapter.mm +84 -0
- package/cocoa/ReactNativeHost+View.mm +44 -0
- package/cocoa/ReactNativeHost.h +56 -0
- package/cocoa/ReactNativeHost.mm +169 -0
- package/cocoa/ReactNativeHost.xcodeproj/project.pbxproj +1 -0
- package/package.json +2 -2
package/ReactNativeHost.podspec
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
require 'json'
|
|
2
2
|
|
|
3
|
+
source_files = 'cocoa/*.{h,m,mm}'
|
|
4
|
+
public_header_files = 'cocoa/{ReactNativeHost,RNXHostConfig}.h'
|
|
5
|
+
|
|
3
6
|
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
7
|
version = package['version']
|
|
5
8
|
repository = package['repository']
|
|
9
|
+
repo_dir = repository['directory']
|
|
10
|
+
|
|
11
|
+
new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1'
|
|
12
|
+
preprocessor_definitions = ['FOLLY_NO_CONFIG=1']
|
|
13
|
+
if new_arch_enabled
|
|
14
|
+
preprocessor_definitions << 'RCT_NEW_ARCH_ENABLED=1'
|
|
15
|
+
preprocessor_definitions << 'USE_FABRIC=1'
|
|
16
|
+
preprocessor_definitions << 'USE_TURBOMODULE=1'
|
|
17
|
+
end
|
|
6
18
|
|
|
7
19
|
Pod::Spec.new do |s|
|
|
8
20
|
s.name = 'ReactNativeHost'
|
|
@@ -17,14 +29,28 @@ Pod::Spec.new do |s|
|
|
|
17
29
|
s.osx.deployment_target = '10.15'
|
|
18
30
|
|
|
19
31
|
s.dependency 'React-Core'
|
|
32
|
+
s.dependency 'React-cxxreact'
|
|
33
|
+
|
|
34
|
+
if new_arch_enabled
|
|
35
|
+
s.dependency 'ReactCommon/turbomodule/core'
|
|
36
|
+
s.dependency 'React-RCTFabric'
|
|
37
|
+
end
|
|
20
38
|
|
|
21
|
-
s.pod_target_xcconfig = {
|
|
39
|
+
s.pod_target_xcconfig = {
|
|
40
|
+
'CLANG_CXX_LANGUAGE_STANDARD' => 'gnu++17',
|
|
41
|
+
'DEFINES_MODULE' => 'YES',
|
|
42
|
+
'GCC_PREPROCESSOR_DEFINITIONS' => preprocessor_definitions,
|
|
43
|
+
'HEADER_SEARCH_PATHS' => [
|
|
44
|
+
'$(PODS_ROOT)/Headers/Private/React-Core',
|
|
45
|
+
'$(PODS_ROOT)/boost',
|
|
46
|
+
],
|
|
47
|
+
}
|
|
22
48
|
|
|
23
49
|
# Include both package and repository relative paths to allow the podspec to
|
|
24
50
|
# be consumed from both a local path, and as a podspec outside a spec
|
|
25
51
|
# repository.
|
|
26
|
-
s.source_files =
|
|
27
|
-
"#{
|
|
28
|
-
s.public_header_files =
|
|
29
|
-
"#{
|
|
52
|
+
s.source_files = source_files, # :path
|
|
53
|
+
"#{repo_dir}/#{source_files}" # :podspec
|
|
54
|
+
s.public_header_files = public_header_files, # :path
|
|
55
|
+
"#{repo_dir}/#{public_header_files}" # :podspec
|
|
30
56
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#import "RNXFabricAdapter.h"
|
|
2
|
+
|
|
3
|
+
#ifdef USE_FABRIC
|
|
4
|
+
#pragma clang diagnostic push
|
|
5
|
+
#pragma clang diagnostic ignored "-Wcomma"
|
|
6
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
|
7
|
+
#import <React/RCTSurfacePresenter.h>
|
|
8
|
+
#import <React/RCTSurfacePresenterBridgeAdapter.h>
|
|
9
|
+
#import <react/config/ReactNativeConfig.h>
|
|
10
|
+
#pragma clang diagnostic pop
|
|
11
|
+
#endif // USE_FABRIC
|
|
12
|
+
|
|
13
|
+
NSObject *RNXInstallSurfacePresenterBridgeAdapter(RCTBridge *bridge)
|
|
14
|
+
{
|
|
15
|
+
#ifdef USE_FABRIC
|
|
16
|
+
auto contextContainer = std::make_shared<facebook::react::ContextContainer const>();
|
|
17
|
+
auto reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
|
|
18
|
+
contextContainer->insert("ReactNativeConfig", reactNativeConfig);
|
|
19
|
+
|
|
20
|
+
auto bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge
|
|
21
|
+
contextContainer:contextContainer];
|
|
22
|
+
bridge.surfacePresenter = bridgeAdapter.surfacePresenter;
|
|
23
|
+
return bridgeAdapter;
|
|
24
|
+
#else
|
|
25
|
+
return nil;
|
|
26
|
+
#endif // USE_FABRIC
|
|
27
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
#import <React/RCTBridgeDelegate.h>
|
|
4
|
+
#import <React/RCTLog.h>
|
|
5
|
+
|
|
6
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
7
|
+
|
|
8
|
+
/// Configuration object for ``ReactNativeHost``.
|
|
9
|
+
@protocol RNXHostConfig <RCTBridgeDelegate>
|
|
10
|
+
|
|
11
|
+
@optional
|
|
12
|
+
|
|
13
|
+
/// Returns whether the loading view should be visible while loading JavaScript.
|
|
14
|
+
@property (nonatomic, readonly) BOOL isDevLoadingViewEnabled;
|
|
15
|
+
|
|
16
|
+
/// Returns whether the bridge should be released when the app is backgrounded.
|
|
17
|
+
@property (nonatomic, readonly) BOOL shouldReleaseBridgeWhenBackgrounded;
|
|
18
|
+
|
|
19
|
+
/// Logs a message.
|
|
20
|
+
- (void)logWithLevel:(RCTLogLevel)level
|
|
21
|
+
source:(RCTLogSource)source
|
|
22
|
+
filename:(NSString *)filename
|
|
23
|
+
line:(NSNumber *)line
|
|
24
|
+
message:(NSString *)message
|
|
25
|
+
__attribute__((__swift_name__("log(_:source:filename:line:message:)")));
|
|
26
|
+
|
|
27
|
+
// Called when the bridge has been instantiated.
|
|
28
|
+
- (void)onBridgeInstantiated:(RCTBridge *)bridge;
|
|
29
|
+
|
|
30
|
+
// Called when the bridge is about to be shut down.
|
|
31
|
+
- (void)onBridgeWillShutDown:(RCTBridge *)bridge;
|
|
32
|
+
|
|
33
|
+
// Called when the bridge has been shut down.
|
|
34
|
+
- (void)onBridgeDidShutDown;
|
|
35
|
+
|
|
36
|
+
/// Handles a fatal error.
|
|
37
|
+
- (void)onFatalError:(NSError *)error;
|
|
38
|
+
|
|
39
|
+
@end
|
|
40
|
+
|
|
41
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
@class RCTBridge;
|
|
4
|
+
@class ReactNativeHost;
|
|
5
|
+
|
|
6
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
7
|
+
|
|
8
|
+
/// Releases resources held by a `ReactNativeHost` instance based on app state.
|
|
9
|
+
@interface RNXHostReleaser : NSObject
|
|
10
|
+
|
|
11
|
+
- (instancetype)init NS_UNAVAILABLE;
|
|
12
|
+
|
|
13
|
+
- (instancetype)initWithHost:(ReactNativeHost *)host NS_DESIGNATED_INITIALIZER;
|
|
14
|
+
|
|
15
|
+
- (void)setBridge:(__weak RCTBridge *)bridge;
|
|
16
|
+
|
|
17
|
+
@end
|
|
18
|
+
|
|
19
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#import "RNXHostReleaser.h"
|
|
2
|
+
|
|
3
|
+
#import <React/RCTBridge.h>
|
|
4
|
+
#import <React/RCTUIManager.h>
|
|
5
|
+
#import <React/RCTUIManagerUtils.h>
|
|
6
|
+
|
|
7
|
+
#import "ReactNativeHost.h"
|
|
8
|
+
|
|
9
|
+
@implementation RNXHostReleaser {
|
|
10
|
+
#if !TARGET_OS_OSX
|
|
11
|
+
__weak ReactNativeHost *_host;
|
|
12
|
+
__weak NSDictionary<NSNumber *, UIView *> *_viewRegistry;
|
|
13
|
+
#endif // !TARGET_OS_OSX
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
- (instancetype)initWithHost:(ReactNativeHost *)host
|
|
17
|
+
{
|
|
18
|
+
if (self = [super init]) {
|
|
19
|
+
#if !TARGET_OS_OSX
|
|
20
|
+
_host = host;
|
|
21
|
+
|
|
22
|
+
NSNotificationCenter *notificationCenter = NSNotificationCenter.defaultCenter;
|
|
23
|
+
[notificationCenter addObserver:self
|
|
24
|
+
selector:@selector(onAppDidEnterBackground:)
|
|
25
|
+
name:UIApplicationDidEnterBackgroundNotification
|
|
26
|
+
object:nil];
|
|
27
|
+
#endif // !TARGET_OS_OSX
|
|
28
|
+
}
|
|
29
|
+
return self;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
- (void)setBridge:(__weak RCTBridge *)bridge
|
|
33
|
+
{
|
|
34
|
+
#if !TARGET_OS_OSX
|
|
35
|
+
// This may initialize `RCTAccessibilityManager` and must therefore be run
|
|
36
|
+
// on the main queue.
|
|
37
|
+
__weak typeof(self) weakSelf = self;
|
|
38
|
+
RCTExecuteOnMainQueue(^{
|
|
39
|
+
typeof(self) strongSelf = weakSelf;
|
|
40
|
+
if (strongSelf == nil) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
RCTUIManager *manager = bridge.uiManager;
|
|
45
|
+
if (manager == nil) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// `addUIBlock` must be called on the UIManager queue.
|
|
50
|
+
RCTExecuteOnUIManagerQueue(^{
|
|
51
|
+
[manager addUIBlock:^(RCTUIManager *uiManager,
|
|
52
|
+
NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
53
|
+
typeof(self) strongSelf = weakSelf;
|
|
54
|
+
if (strongSelf == nil) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
strongSelf->_viewRegistry = viewRegistry;
|
|
59
|
+
}];
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
#endif // !TARGET_OS_OSX
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#if !TARGET_OS_OSX
|
|
66
|
+
- (void)onAppDidEnterBackground:(NSNotification *)note
|
|
67
|
+
{
|
|
68
|
+
if (_viewRegistry.count == 0) {
|
|
69
|
+
[_host shutdown];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
#endif // !TARGET_OS_OSX
|
|
73
|
+
|
|
74
|
+
@end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#include <memory>
|
|
2
|
+
|
|
3
|
+
#import <Foundation/Foundation.h>
|
|
4
|
+
|
|
5
|
+
#if USE_TURBOMODULE
|
|
6
|
+
#import <ReactCommon/RCTTurboModuleManager.h>
|
|
7
|
+
#endif // USE_TURBOMODULE
|
|
8
|
+
|
|
9
|
+
@class RCTBridge;
|
|
10
|
+
|
|
11
|
+
namespace facebook::react
|
|
12
|
+
{
|
|
13
|
+
class JSExecutorFactory;
|
|
14
|
+
} // namespace facebook::react
|
|
15
|
+
|
|
16
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
17
|
+
|
|
18
|
+
#if USE_TURBOMODULE
|
|
19
|
+
@interface RNXTurboModuleAdapter : NSObject <RCTTurboModuleManagerDelegate>
|
|
20
|
+
#else
|
|
21
|
+
@interface RNXTurboModuleAdapter : NSObject
|
|
22
|
+
#endif // USE_TURBOMODULE
|
|
23
|
+
|
|
24
|
+
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:
|
|
25
|
+
(RCTBridge *)bridge;
|
|
26
|
+
|
|
27
|
+
@end
|
|
28
|
+
|
|
29
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#import "RNXTurboModuleAdapter.h"
|
|
2
|
+
|
|
3
|
+
#define FOLLY_NO_CONFIG 1
|
|
4
|
+
#pragma clang diagnostic push
|
|
5
|
+
#pragma clang diagnostic ignored "-Wcomma"
|
|
6
|
+
#import <cxxreact/JSExecutor.h>
|
|
7
|
+
#pragma clang diagnostic pop
|
|
8
|
+
|
|
9
|
+
#if USE_TURBOMODULE
|
|
10
|
+
#import <React/CoreModulesPlugins.h>
|
|
11
|
+
#import <ReactCommon/RCTTurboModuleManager.h>
|
|
12
|
+
|
|
13
|
+
#if __has_include(<React/RCTAppSetupUtils.h>) // <0.72
|
|
14
|
+
#import <React/RCTAppSetupUtils.h>
|
|
15
|
+
#define USE_RUNTIME_SCHEDULER 0
|
|
16
|
+
#else
|
|
17
|
+
#import <RCTAppSetupUtils.h>
|
|
18
|
+
|
|
19
|
+
#import <React/RCTSurfacePresenterBridgeAdapter.h>
|
|
20
|
+
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
|
|
21
|
+
#import <react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h>
|
|
22
|
+
#define USE_RUNTIME_SCHEDULER 1
|
|
23
|
+
#endif // __has_include(<React/RCTAppSetupUtils.h>)
|
|
24
|
+
|
|
25
|
+
#endif // USE_TURBOMODULE
|
|
26
|
+
|
|
27
|
+
@implementation RNXTurboModuleAdapter {
|
|
28
|
+
#if USE_TURBOMODULE
|
|
29
|
+
RCTTurboModuleManager *_turboModuleManager;
|
|
30
|
+
#endif // USE_TURBOMODULE
|
|
31
|
+
#if USE_RUNTIME_SCHEDULER
|
|
32
|
+
std::shared_ptr<facebook::react::RuntimeScheduler> _runtimeScheduler;
|
|
33
|
+
#endif // USE_RUNTIME_SCHEDULER
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:
|
|
37
|
+
(RCTBridge *)bridge
|
|
38
|
+
{
|
|
39
|
+
#if USE_TURBOMODULE
|
|
40
|
+
// jsExecutorFactoryForBridge: (USE_TURBOMODULE=1)
|
|
41
|
+
#if USE_RUNTIME_SCHEDULER
|
|
42
|
+
_runtimeScheduler =
|
|
43
|
+
std::make_shared<facebook::react::RuntimeScheduler>(RCTRuntimeExecutorFromBridge(bridge));
|
|
44
|
+
auto callInvoker =
|
|
45
|
+
std::make_shared<facebook::react::RuntimeSchedulerCallInvoker>(_runtimeScheduler);
|
|
46
|
+
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
|
|
47
|
+
delegate:self
|
|
48
|
+
jsInvoker:callInvoker];
|
|
49
|
+
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager, _runtimeScheduler);
|
|
50
|
+
#else
|
|
51
|
+
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
|
|
52
|
+
delegate:self
|
|
53
|
+
jsInvoker:bridge.jsCallInvoker];
|
|
54
|
+
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
|
|
55
|
+
#endif // USE_RUNTIME_SCHEDULER
|
|
56
|
+
#else
|
|
57
|
+
// jsExecutorFactoryForBridge: (USE_TURBOMODULE=0)
|
|
58
|
+
return nullptr;
|
|
59
|
+
#endif // USE_TURBOMODULE
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// MARK: - RCTTurboModuleManagerDelegate details
|
|
63
|
+
#if USE_TURBOMODULE
|
|
64
|
+
|
|
65
|
+
- (Class)getModuleClassFromName:(const char *)name
|
|
66
|
+
{
|
|
67
|
+
return RCTCoreModulesClassProvider(name);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
- (std::shared_ptr<facebook::react::TurboModule>)
|
|
71
|
+
getTurboModule:(const std::string &)name
|
|
72
|
+
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
|
|
73
|
+
{
|
|
74
|
+
return nullptr;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
|
|
78
|
+
{
|
|
79
|
+
return RCTAppSetupDefaultModuleFromClass(moduleClass);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#endif // USE_TURBOMODULE
|
|
83
|
+
|
|
84
|
+
@end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#import "ReactNativeHost.h"
|
|
2
|
+
|
|
3
|
+
#ifdef USE_FABRIC
|
|
4
|
+
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
|
|
5
|
+
#else
|
|
6
|
+
#import <React/RCTRootView.h>
|
|
7
|
+
#endif // USE_FABRIC
|
|
8
|
+
|
|
9
|
+
@implementation ReactNativeHost (View)
|
|
10
|
+
|
|
11
|
+
+ (instancetype)hostFromRootView:(RNXView *)rootView
|
|
12
|
+
{
|
|
13
|
+
if (![rootView respondsToSelector:@selector(bridge)]) {
|
|
14
|
+
return nil;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
id bridge = [rootView performSelector:@selector(bridge)];
|
|
18
|
+
if (![bridge respondsToSelector:@selector(delegate)]) {
|
|
19
|
+
return nil;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
id delegate = [bridge performSelector:@selector(delegate)];
|
|
23
|
+
if (![delegate isKindOfClass:self]) {
|
|
24
|
+
return nil;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return delegate;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
- (RNXView *)viewWithModuleName:(NSString *)moduleName
|
|
31
|
+
initialProperties:(NSDictionary *)initialProperties;
|
|
32
|
+
{
|
|
33
|
+
#ifdef USE_FABRIC
|
|
34
|
+
return [[RCTFabricSurfaceHostingProxyRootView alloc] initWithBridge:self.bridge
|
|
35
|
+
moduleName:moduleName
|
|
36
|
+
initialProperties:initialProperties];
|
|
37
|
+
#else
|
|
38
|
+
return [[RCTRootView alloc] initWithBridge:self.bridge
|
|
39
|
+
moduleName:moduleName
|
|
40
|
+
initialProperties:initialProperties];
|
|
41
|
+
#endif // USE_FABRIC
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
#import <React/RCTBridgeDelegate.h>
|
|
4
|
+
|
|
5
|
+
#import "RNXHostConfig.h"
|
|
6
|
+
|
|
7
|
+
#if TARGET_OS_OSX
|
|
8
|
+
@class NSView;
|
|
9
|
+
typedef NSView RNXView;
|
|
10
|
+
#else
|
|
11
|
+
@class UIView;
|
|
12
|
+
typedef UIView RNXView;
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
16
|
+
|
|
17
|
+
/// Hosts a React Native instance.
|
|
18
|
+
@interface ReactNativeHost : NSObject <RCTBridgeDelegate>
|
|
19
|
+
|
|
20
|
+
@property (nonatomic, readonly, nullable) RCTBridge *bridge;
|
|
21
|
+
|
|
22
|
+
- (instancetype)init NS_UNAVAILABLE;
|
|
23
|
+
|
|
24
|
+
- (instancetype)initWithConfig:(id<RNXHostConfig>)config NS_DESIGNATED_INITIALIZER
|
|
25
|
+
NS_SWIFT_NAME(init(_:));
|
|
26
|
+
|
|
27
|
+
- (void)shutdown;
|
|
28
|
+
|
|
29
|
+
/// Calls the specified block when the desired native module is retrieved. Note
|
|
30
|
+
/// that this may initialize the module.
|
|
31
|
+
///
|
|
32
|
+
/// - Parameters:
|
|
33
|
+
/// - moduleClass: Class of the native module to initialize or retrieve
|
|
34
|
+
/// - block: Block that gets called when the native module is retrieved
|
|
35
|
+
- (void)usingModule:(Class)moduleClass
|
|
36
|
+
block:(void (^)(id<RCTBridgeModule> _Nullable))block
|
|
37
|
+
NS_SWIFT_NAME(using(module:block:));
|
|
38
|
+
|
|
39
|
+
@end
|
|
40
|
+
|
|
41
|
+
@interface ReactNativeHost (View)
|
|
42
|
+
|
|
43
|
+
+ (nullable instancetype)hostFromRootView:(RNXView *)rootView NS_SWIFT_NAME(host(from:));
|
|
44
|
+
|
|
45
|
+
/// Creates a React root view with the specified module and initial properties.
|
|
46
|
+
///
|
|
47
|
+
/// - Parameters:
|
|
48
|
+
/// - moduleName: Name of the module to create root view of
|
|
49
|
+
/// - initialProperties: Properties passed to the module
|
|
50
|
+
- (RNXView *)viewWithModuleName:(NSString *)moduleName
|
|
51
|
+
initialProperties:(nullable NSDictionary *)initialProperties
|
|
52
|
+
NS_SWIFT_NAME(view(moduleName:initialProperties:));
|
|
53
|
+
|
|
54
|
+
@end
|
|
55
|
+
|
|
56
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#import "ReactNativeHost.h"
|
|
2
|
+
|
|
3
|
+
#define FOLLY_NO_CONFIG 1
|
|
4
|
+
#pragma clang diagnostic push
|
|
5
|
+
#pragma clang diagnostic ignored "-Wcomma"
|
|
6
|
+
#import <cxxreact/JSExecutor.h>
|
|
7
|
+
#pragma clang diagnostic pop
|
|
8
|
+
|
|
9
|
+
#import <React/RCTBridge.h>
|
|
10
|
+
#import <React/RCTBundleURLProvider.h>
|
|
11
|
+
#import <React/RCTCxxBridgeDelegate.h>
|
|
12
|
+
#import <React/RCTDevLoadingViewSetEnabled.h>
|
|
13
|
+
#import <React/RCTUtils.h>
|
|
14
|
+
|
|
15
|
+
#import "RNXFabricAdapter.h"
|
|
16
|
+
#import "RNXHostConfig.h"
|
|
17
|
+
#import "RNXHostReleaser.h"
|
|
18
|
+
#import "RNXTurboModuleAdapter.h"
|
|
19
|
+
|
|
20
|
+
@interface ReactNativeHost () <RCTCxxBridgeDelegate>
|
|
21
|
+
@end
|
|
22
|
+
|
|
23
|
+
@implementation ReactNativeHost {
|
|
24
|
+
__weak id<RNXHostConfig> _config;
|
|
25
|
+
RNXTurboModuleAdapter *_turboModuleAdapter;
|
|
26
|
+
NSObject *_surfacePresenterBridgeAdapter;
|
|
27
|
+
RCTBridge *_bridge;
|
|
28
|
+
NSLock *_isShuttingDown;
|
|
29
|
+
RNXHostReleaser *_hostReleaser;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
- (instancetype)initWithConfig:(id<RNXHostConfig>)config
|
|
33
|
+
{
|
|
34
|
+
if (self = [super init]) {
|
|
35
|
+
if ([config respondsToSelector:@selector(isDevLoadingViewEnabled)]) {
|
|
36
|
+
RCTDevLoadingViewSetEnabled([config isDevLoadingViewEnabled]);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if ([config respondsToSelector:@selector(logWithLevel:source:filename:line:message:)]) {
|
|
40
|
+
RCTSetLogFunction(^(RCTLogLevel level,
|
|
41
|
+
RCTLogSource source,
|
|
42
|
+
NSString *filename,
|
|
43
|
+
NSNumber *line,
|
|
44
|
+
NSString *message) {
|
|
45
|
+
[config logWithLevel:level source:source filename:filename line:line message:message];
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if ([config respondsToSelector:@selector(onFatalError:)]) {
|
|
50
|
+
RCTSetFatalHandler(^(NSError *error) {
|
|
51
|
+
[config onFatalError:error];
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
_config = config;
|
|
56
|
+
#if USE_FABRIC || USE_TURBOMODULE
|
|
57
|
+
_turboModuleAdapter = [[RNXTurboModuleAdapter alloc] init];
|
|
58
|
+
#endif
|
|
59
|
+
_isShuttingDown = [[NSLock alloc] init];
|
|
60
|
+
|
|
61
|
+
if ([config respondsToSelector:@selector(shouldReleaseBridgeWhenBackgrounded)] &&
|
|
62
|
+
[config shouldReleaseBridgeWhenBackgrounded]) {
|
|
63
|
+
_hostReleaser = [[RNXHostReleaser alloc] initWithHost:self];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
(void)self.bridge; // Initialize the bridge now
|
|
67
|
+
}
|
|
68
|
+
return self;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
- (RCTBridge *)bridge
|
|
72
|
+
{
|
|
73
|
+
if (![_isShuttingDown tryLock]) {
|
|
74
|
+
NSAssert(NO, @"Tried to access the bridge while shutting down");
|
|
75
|
+
return nil;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@try {
|
|
79
|
+
if (_bridge == nil) {
|
|
80
|
+
_bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil];
|
|
81
|
+
_surfacePresenterBridgeAdapter = RNXInstallSurfacePresenterBridgeAdapter(_bridge);
|
|
82
|
+
[_hostReleaser setBridge:_bridge];
|
|
83
|
+
if ([_config respondsToSelector:@selector(onBridgeInstantiated:)]) {
|
|
84
|
+
[_config onBridgeInstantiated:_bridge];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return _bridge;
|
|
89
|
+
} @finally {
|
|
90
|
+
[_isShuttingDown unlock];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
- (void)shutdown
|
|
95
|
+
{
|
|
96
|
+
if ([_config respondsToSelector:@selector(onBridgeWillShutDown:)]) {
|
|
97
|
+
[_config onBridgeWillShutDown:_bridge];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
[_isShuttingDown lock];
|
|
101
|
+
|
|
102
|
+
@try {
|
|
103
|
+
[_bridge invalidate];
|
|
104
|
+
_bridge = nil;
|
|
105
|
+
|
|
106
|
+
if ([_config respondsToSelector:@selector(onBridgeDidShutDown)]) {
|
|
107
|
+
[_config onBridgeDidShutDown];
|
|
108
|
+
}
|
|
109
|
+
} @finally {
|
|
110
|
+
[_isShuttingDown unlock];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
- (void)usingModule:(Class)moduleClass block:(void (^)(id<RCTBridgeModule> _Nullable))block
|
|
115
|
+
{
|
|
116
|
+
const BOOL requiresMainQueueSetup =
|
|
117
|
+
[moduleClass respondsToSelector:@selector(requiresMainQueueSetup)] &&
|
|
118
|
+
[moduleClass requiresMainQueueSetup];
|
|
119
|
+
if (requiresMainQueueSetup && !RCTIsMainQueue()) {
|
|
120
|
+
__weak id weakSelf = self;
|
|
121
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
122
|
+
[weakSelf usingModule:moduleClass block:block];
|
|
123
|
+
});
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
id<RCTBridgeModule> bridgeModule = [self.bridge moduleForClass:moduleClass];
|
|
128
|
+
block(bridgeModule);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// MARK: - RCTBridgeDelegate details
|
|
132
|
+
|
|
133
|
+
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
|
134
|
+
{
|
|
135
|
+
NSURL *sourceURL = [_config sourceURLForBridge:bridge];
|
|
136
|
+
if (sourceURL != nil) {
|
|
137
|
+
return sourceURL;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"
|
|
141
|
+
fallbackURLProvider:^NSURL * {
|
|
142
|
+
return nil;
|
|
143
|
+
}];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
|
|
147
|
+
{
|
|
148
|
+
return [_config respondsToSelector:@selector(extraModulesForBridge:)]
|
|
149
|
+
? [_config extraModulesForBridge:bridge]
|
|
150
|
+
: @[];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// MARK: - RCTCxxBridgeDelegate details
|
|
154
|
+
|
|
155
|
+
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:
|
|
156
|
+
(RCTBridge *)bridge
|
|
157
|
+
{
|
|
158
|
+
#if USE_TURBOMODULE
|
|
159
|
+
// jsExecutorFactoryForBridge: (USE_TURBOMODULE=1)
|
|
160
|
+
return [_turboModuleAdapter jsExecutorFactoryForBridge:bridge];
|
|
161
|
+
#else
|
|
162
|
+
// jsExecutorFactoryForBridge: (USE_TURBOMODULE=0)
|
|
163
|
+
return nullptr;
|
|
164
|
+
#endif // USE_TURBOMODULE
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// MARK: - Private
|
|
168
|
+
|
|
169
|
+
@end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/* Dummy file so @react-native-community/cli recognizes this as an iOS package */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rnx-kit/react-native-host",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Simplify React Native initialization",
|
|
5
5
|
"homepage": "https://github.com/microsoft/rnx-kit/tree/main/packages/react-native-host#readme",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"ReactNativeHost.podspec",
|
|
13
13
|
"android/",
|
|
14
|
-
"
|
|
14
|
+
"cocoa/"
|
|
15
15
|
],
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|