Skip to content

Commit 149ed11

Browse files
committed
feat: implement XR module
1 parent 77f00b4 commit 149ed11

25 files changed

+284
-152
lines changed

packages/react-native/Libraries/Spatial/NativeSpatialManager.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/react-native/Libraries/Spatial/Spatial.d.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/react-native/Libraries/Spatial/Spatial.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

packages/react-native/Libraries/SwiftExtensions/RCTMainWindow.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import SwiftUI
2-
import React
3-
42

53
/**
64
This SwiftUI struct returns main React Native scene. It should be used only once as it conains setup code.

packages/react-native/Libraries/SwiftExtensions/React-RCTSwiftExtensions.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ Pod::Spec.new do |s|
2424
s.frameworks = ["UIKit", "SwiftUI"]
2525

2626
s.dependency "React-Core"
27-
s.dependency "React-RCTSpatial"
27+
s.dependency "React-RCTXR"
2828
end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* @flow strict
3+
* @format
4+
*/
5+
6+
export * from '../../src/private/specs/visionos_modules/NativeXRModule';
7+
import NativeXRModule from '../../src/private/specs/visionos_modules/NativeXRModule';
8+
export default NativeXRModule;
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#import <Foundation/Foundation.h>
22
#import <React/RCTBridgeModule.h>
33

4-
@interface RCTSpatialManager : NSObject <RCTBridgeModule>
4+
@interface RCTXRModule : NSObject <RCTBridgeModule>
55

66
@end
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,47 @@
1-
#import <React/RCTSpatialManager.h>
1+
#import <React/RCTXRModule.h>
2+
3+
#import <FBReactNativeSpec_visionOS/FBReactNativeSpec_visionOS.h>
24

3-
#import <FBReactNativeSpec/FBReactNativeSpec.h>
45
#import <React/RCTBridge.h>
56
#import <React/RCTConvert.h>
67
#import <React/RCTUtils.h>
7-
#import "RCTSpatial-Swift.h"
8+
#import "RCTXR-Swift.h"
89

9-
@interface RCTSpatialManager () <NativeSpatialManagerSpec>
10+
@interface RCTXRModule () <NativeXRModuleSpec>
1011
@end
1112

12-
@implementation RCTSpatialManager {
13+
@implementation RCTXRModule {
1314
UIViewController *_immersiveBridgeView;
1415
}
1516

1617
RCT_EXPORT_MODULE()
1718

18-
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
19-
return std::make_shared<facebook::react::NativeSpatialManagerSpecJSI>(params);
20-
}
21-
22-
RCT_EXPORT_METHOD(dismissImmersiveSpace
19+
RCT_EXPORT_METHOD(endSession
2320
: (RCTPromiseResolveBlock)resolve reject
2421
: (RCTPromiseRejectBlock)reject)
2522
{
26-
RCTExecuteOnMainQueue(^{
27-
[self->_immersiveBridgeView willMoveToParentViewController:nil];
28-
[self->_immersiveBridgeView.view removeFromSuperview];
29-
[self->_immersiveBridgeView removeFromParentViewController];
30-
self->_immersiveBridgeView = nil;
31-
32-
resolve(nil);
33-
});
23+
[self removeImmersiveBridge];
24+
resolve(nil);
3425
}
3526

36-
RCT_EXPORT_METHOD(openImmersiveSpace
37-
: (NSString *)sceneId resolve
27+
28+
RCT_EXPORT_METHOD(requestSession
29+
: (NSString *)sessionId resolve
3830
: (RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
3931
{
4032
RCTExecuteOnMainQueue(^{
4133
UIWindow *keyWindow = RCTKeyWindow();
4234
UIViewController *rootViewController = keyWindow.rootViewController;
4335

4436
if (self->_immersiveBridgeView == nil) {
45-
self->_immersiveBridgeView = [ImmersiveBridgeFactory makeImmersiveBridgeViewWithSpaceId:sceneId
46-
completionHandler:^(enum ImmersiveSpaceResult result){
37+
self->_immersiveBridgeView = [ImmersiveBridgeFactory makeImmersiveBridgeViewWithSpaceId:sessionId
38+
completionHandler:^(enum ImmersiveSpaceResult result){
4739
if (result == ImmersiveSpaceResultError) {
4840
reject(@"ERROR", @"Immersive Space failed to open, the system cannot fulfill the request.", nil);
41+
[self removeImmersiveBridge];
4942
} else if (result == ImmersiveSpaceResultUserCancelled) {
5043
reject(@"ERROR", @"Immersive Space canceled by user", nil);
44+
[self removeImmersiveBridge];
5145
} else if (result == ImmersiveSpaceResultOpened) {
5246
resolve(nil);
5347
}
@@ -62,4 +56,33 @@ @implementation RCTSpatialManager {
6256
});
6357
}
6458

59+
- (facebook::react::ModuleConstants<JS::NativeXRModule::Constants::Builder>)constantsToExport {
60+
return [self getConstants];
61+
}
62+
63+
- (facebook::react::ModuleConstants<JS::NativeXRModule::Constants>)getConstants {
64+
__block facebook::react::ModuleConstants<JS::NativeXRModule::Constants> constants;
65+
RCTUnsafeExecuteOnMainQueueSync(^{
66+
constants = facebook::react::typedConstants<JS::NativeXRModule::Constants>({
67+
.supportsMultipleScenes = RCTSharedApplication().supportsMultipleScenes
68+
});
69+
});
70+
71+
return constants;
72+
}
73+
74+
- (void) removeImmersiveBridge
75+
{
76+
RCTExecuteOnMainQueue(^{
77+
[self->_immersiveBridgeView willMoveToParentViewController:nil];
78+
[self->_immersiveBridgeView.view removeFromSuperview];
79+
[self->_immersiveBridgeView removeFromParentViewController];
80+
self->_immersiveBridgeView = nil;
81+
});
82+
}
83+
84+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
85+
return std::make_shared<facebook::react::NativeXRModuleSpecJSI>(params);
86+
}
87+
6588
@end

packages/react-native/Libraries/Spatial/React-RCTSpatial.podspec renamed to packages/react-native/Libraries/XR/React-RCTXR.podspec

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ header_search_paths = [
2121
]
2222

2323
Pod::Spec.new do |s|
24-
s.name = "React-RCTSpatial"
24+
s.name = "React-RCTXR"
2525
s.version = version
26-
s.summary = "Spatial module for React Native."
26+
s.summary = "XR module for React Native."
2727
s.homepage = "https://reactnative.dev/"
2828
s.documentation_url = "https://reactnative.dev/docs/settings"
2929
s.license = package["license"]
@@ -33,7 +33,7 @@ Pod::Spec.new do |s|
3333
s.source = source
3434
s.source_files = "*.{m,mm,swift}"
3535
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
36-
s.header_dir = "RCTSpatial"
36+
s.header_dir = "RCTXR"
3737
s.pod_target_xcconfig = {
3838
"USE_HEADERMAP" => "YES",
3939
"CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
@@ -43,7 +43,7 @@ Pod::Spec.new do |s|
4343
s.dependency "RCT-Folly", folly_version
4444
s.dependency "RCTTypeSafety"
4545
s.dependency "React-jsi"
46-
s.dependency "React-Core/RCTSpatialHeaders"
46+
s.dependency "React-Core/RCTXRHeaders"
4747

4848
add_dependency(s, "React-Codegen", :additional_framework_paths => ["build/generated/ios"])
4949
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
export interface XRStatic {
3+
requestSession(sessionId: string): Promise<void>;
4+
endSession(): Promise<void>;
5+
supportsMultipleScenes: boolean;
6+
}
7+
8+
export const XR: XRStatic;
9+
export type XR = XRStatic;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @format
3+
* @flow strict
4+
* @jsdoc
5+
*/
6+
7+
import NativeXRModule from './NativeXRModule';
8+
9+
const XR = {
10+
requestSession: (sessionId?: string): Promise<void> => {
11+
if (NativeXRModule != null && NativeXRModule.requestSession != null) {
12+
return NativeXRModule.requestSession(sessionId);
13+
}
14+
return Promise.reject(new Error('NativeXRModule is not available'));
15+
},
16+
endSession: (): Promise<void> => {
17+
if (NativeXRModule != null && NativeXRModule.endSession != null) {
18+
return NativeXRModule.endSession();
19+
}
20+
return Promise.reject(new Error('NativeXRModule is not available'));
21+
},
22+
// $FlowIgnore[unsafe-getters-setters]
23+
get supportsMultipleScenes(): boolean {
24+
if (NativeXRModule == null) {
25+
return false;
26+
}
27+
28+
const nativeConstants = NativeXRModule.getConstants();
29+
return nativeConstants.supportsMultipleScenes || false;
30+
},
31+
};
32+
33+
module.exports = XR;

packages/react-native/React-Core.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ header_subspecs = {
3737
'RCTSettingsHeaders' => 'Libraries/Settings/*.h',
3838
'RCTTextHeaders' => 'Libraries/Text/**/*.h',
3939
'RCTVibrationHeaders' => 'Libraries/Vibration/*.h',
40-
'RCTSpatialHeaders' => 'Libraries/Spatial/*.h',
40+
'RCTXRHeaders' => 'Libraries/XR/*.h',
4141
}
4242

4343
frameworks_search_paths = []

packages/react-native/React.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,5 @@ Pod::Spec.new do |s|
5353
s.dependency "React-RCTSettings", version
5454
s.dependency "React-RCTText", version
5555
s.dependency "React-RCTVibration", version
56-
s.dependency "React-RCTSpatial", version
56+
s.dependency "React-RCTXR", version
5757
end

packages/react-native/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ import typeof ReactNative from './Libraries/Renderer/shims/ReactNative';
7171
import type {HostComponent as _HostComponentInternal} from './Libraries/Renderer/shims/ReactNativeTypes';
7272
import typeof Settings from './Libraries/Settings/Settings';
7373
import typeof Share from './Libraries/Share/Share';
74-
import typeof Spatial from './Libraries/Spatial/Spatial';
7574
import typeof {PlatformColor} from './Libraries/StyleSheet/PlatformColorValueTypes';
7675
// Plugins
7776
import typeof {DynamicColorIOS} from './Libraries/StyleSheet/PlatformColorValueTypesIOS';
@@ -90,6 +89,7 @@ import typeof Platform from './Libraries/Utilities/Platform';
9089
import typeof useColorScheme from './Libraries/Utilities/useColorScheme';
9190
import typeof useWindowDimensions from './Libraries/Utilities/useWindowDimensions';
9291
import typeof Vibration from './Libraries/Vibration/Vibration';
92+
import typeof XR from './Libraries/XR/XR';
9393
import typeof YellowBox from './Libraries/YellowBox/YellowBoxDeprecated';
9494

9595
const warnOnce = require('./Libraries/Utilities/warnOnce');
@@ -296,8 +296,8 @@ module.exports = {
296296
get Share(): Share {
297297
return require('./Libraries/Share/Share');
298298
},
299-
get Spatial(): Spatial {
300-
return require('./Libraries/Spatial/Spatial');
299+
get XR(): XR {
300+
return require('./Libraries/XR/XR');
301301
},
302302
get StyleSheet(): StyleSheet {
303303
return require('./Libraries/StyleSheet/StyleSheet');

packages/react-native/package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@
143143
"android": {},
144144
"jsSrcsDir": "src"
145145
},
146+
{
147+
"name": "FBReactNativeSpec_visionOS",
148+
"type": "modules",
149+
"ios": {},
150+
"android": {},
151+
"jsSrcsDir": "src/private/specs/visionos_modules"
152+
},
146153
{
147154
"name": "rncore",
148155
"type": "components",

packages/react-native/scripts/cocoapods/utils.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ def self.react_native_pods
601601
"glog",
602602
"hermes-engine",
603603
"React-hermes",
604-
"React-RCTSpatial", # visionOS
604+
"React-RCTXR", # visionOS
605605
]
606606
end
607607

packages/react-native/scripts/react_native_pods.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def use_react_native! (
133133
pod 'React-nativeconfig', :path => "#{prefix}/ReactCommon"
134134
pod 'RCTDeprecation', :path => "#{prefix}/ReactApple/Libraries/RCTFoundation/RCTDeprecation"
135135
pod 'React-RCTSwiftExtensions', :path => "#{prefix}/Libraries/SwiftExtensions"
136-
pod 'React-RCTSpatial', :path => "#{prefix}/Libraries/Spatial"
136+
pod 'React-RCTXR', :path => "#{prefix}/Libraries/XR"
137137

138138
if hermes_enabled
139139
setup_hermes!(:react_native_path => prefix)

packages/react-native/src/private/specs/modules/NativeSpatialManager.js

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @flow strict
3+
* @format
4+
*/
5+
6+
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
7+
8+
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
9+
10+
export type XRModuleConstants = {|
11+
+supportsMultipleScenes?: boolean,
12+
|};
13+
14+
export interface Spec extends TurboModule {
15+
+getConstants: () => XRModuleConstants;
16+
17+
+requestSession: (sessionId?: string) => Promise<void>;
18+
+endSession: () => Promise<void>;
19+
}
20+
21+
export default (TurboModuleRegistry.get<Spec>('XRModule'): ?Spec);

0 commit comments

Comments
 (0)