diff --git a/.gitignore b/.gitignore index ef42e55d313f5a..aee9764b437df7 100644 --- a/.gitignore +++ b/.gitignore @@ -155,6 +155,7 @@ vendor/ # CircleCI .circleci/generated_config.yml - # Jest Integration /packages/react-native-fantom/build/ +.circleci/storage +.yarn diff --git a/packages/react-native/Libraries/SwiftExtensions/React-RCTSwiftExtensions.podspec b/packages/react-native/Libraries/SwiftExtensions/React-RCTSwiftExtensions.podspec index d5dbdafe37ff6d..531f1d8172ca7d 100644 --- a/packages/react-native/Libraries/SwiftExtensions/React-RCTSwiftExtensions.podspec +++ b/packages/react-native/Libraries/SwiftExtensions/React-RCTSwiftExtensions.podspec @@ -24,4 +24,5 @@ Pod::Spec.new do |s| s.frameworks = ["UIKit", "SwiftUI"] s.dependency "React-Core" + s.dependency "React-RCTXR" end diff --git a/packages/react-native/Libraries/XR/ImmersiveBridge.swift b/packages/react-native/Libraries/XR/ImmersiveBridge.swift new file mode 100644 index 00000000000000..45fdbcf4087b00 --- /dev/null +++ b/packages/react-native/Libraries/XR/ImmersiveBridge.swift @@ -0,0 +1,55 @@ +import Foundation +import SwiftUI + +@objc public enum ImmersiveSpaceResult: Int { + case opened + case userCancelled + case error +} + +public typealias CompletionHandlerType = (_ result: ImmersiveSpaceResult) -> Void + +/** + * Utility view used to bridge the gap between SwiftUI environment and UIKit. + * + * Calls `openImmersiveSpace` when view appears in the UIKit hierarchy and `dismissImmersiveSpace` when removed. + */ +struct ImmersiveBridgeView: View { + @Environment(\.openImmersiveSpace) private var openImmersiveSpace + @Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace + + var spaceId: String + var completionHandler: CompletionHandlerType + + var body: some View { + EmptyView() + .onAppear { + Task { + let result = await openImmersiveSpace(id: spaceId) + + switch result { + case .opened: + completionHandler(.opened) + case .error: + completionHandler(.error) + case .userCancelled: + completionHandler(.userCancelled) + default: + break + } + } + } + .onDisappear { + Task { await dismissImmersiveSpace() } + } + } +} + +@objc public class ImmersiveBridgeFactory: NSObject { + @objc public static func makeImmersiveBridgeView( + spaceId: String, + completionHandler: @escaping CompletionHandlerType + ) -> UIViewController { + return UIHostingController(rootView: ImmersiveBridgeView(spaceId: spaceId, completionHandler: completionHandler)) + } +} diff --git a/packages/react-native/Libraries/XR/NativeXRModule.js b/packages/react-native/Libraries/XR/NativeXRModule.js new file mode 100644 index 00000000000000..c34b296bc3e4a5 --- /dev/null +++ b/packages/react-native/Libraries/XR/NativeXRModule.js @@ -0,0 +1,8 @@ +/** + * @flow strict + * @format + */ + +export * from '../../src/private/specs/visionos_modules/NativeXRModule'; +import NativeXRModule from '../../src/private/specs/visionos_modules/NativeXRModule'; +export default NativeXRModule; diff --git a/packages/react-native/Libraries/XR/RCTXRModule.h b/packages/react-native/Libraries/XR/RCTXRModule.h new file mode 100644 index 00000000000000..450d8ad4681619 --- /dev/null +++ b/packages/react-native/Libraries/XR/RCTXRModule.h @@ -0,0 +1,6 @@ +#import +#import + +@interface RCTXRModule : NSObject + +@end diff --git a/packages/react-native/Libraries/XR/RCTXRModule.mm b/packages/react-native/Libraries/XR/RCTXRModule.mm new file mode 100644 index 00000000000000..8b5db6c7cbd008 --- /dev/null +++ b/packages/react-native/Libraries/XR/RCTXRModule.mm @@ -0,0 +1,88 @@ +#import + +#import + +#import +#import +#import +#import "RCTXR-Swift.h" + +@interface RCTXRModule () +@end + +@implementation RCTXRModule { + UIViewController *_immersiveBridgeView; +} + +RCT_EXPORT_MODULE() + +RCT_EXPORT_METHOD(endSession + : (RCTPromiseResolveBlock)resolve reject + : (RCTPromiseRejectBlock)reject) +{ + [self removeImmersiveBridge]; + resolve(nil); +} + + +RCT_EXPORT_METHOD(requestSession + : (NSString *)sessionId resolve + : (RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +{ + RCTExecuteOnMainQueue(^{ + UIWindow *keyWindow = RCTKeyWindow(); + UIViewController *rootViewController = keyWindow.rootViewController; + + if (self->_immersiveBridgeView == nil) { + self->_immersiveBridgeView = [ImmersiveBridgeFactory makeImmersiveBridgeViewWithSpaceId:sessionId + completionHandler:^(enum ImmersiveSpaceResult result){ + if (result == ImmersiveSpaceResultError) { + reject(@"ERROR", @"Immersive Space failed to open, the system cannot fulfill the request.", nil); + [self removeImmersiveBridge]; + } else if (result == ImmersiveSpaceResultUserCancelled) { + reject(@"ERROR", @"Immersive Space canceled by user", nil); + [self removeImmersiveBridge]; + } else if (result == ImmersiveSpaceResultOpened) { + resolve(nil); + } + }]; + + [rootViewController.view addSubview:self->_immersiveBridgeView.view]; + [rootViewController addChildViewController:self->_immersiveBridgeView]; + [self->_immersiveBridgeView didMoveToParentViewController:rootViewController]; + } else { + reject(@"ERROR", @"Immersive Space already opened", nil); + } + }); +} + +- (facebook::react::ModuleConstants)constantsToExport { + return [self getConstants]; +} + +- (facebook::react::ModuleConstants)getConstants { + __block facebook::react::ModuleConstants constants; + RCTUnsafeExecuteOnMainQueueSync(^{ + constants = facebook::react::typedConstants({ + .supportsMultipleScenes = RCTSharedApplication().supportsMultipleScenes + }); + }); + + return constants; +} + +- (void) removeImmersiveBridge +{ + RCTExecuteOnMainQueue(^{ + [self->_immersiveBridgeView willMoveToParentViewController:nil]; + [self->_immersiveBridgeView.view removeFromSuperview]; + [self->_immersiveBridgeView removeFromParentViewController]; + self->_immersiveBridgeView = nil; + }); +} + +- (std::shared_ptr)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); +} + +@end diff --git a/packages/react-native/Libraries/XR/XR.d.ts b/packages/react-native/Libraries/XR/XR.d.ts new file mode 100644 index 00000000000000..11d397a4ebde34 --- /dev/null +++ b/packages/react-native/Libraries/XR/XR.d.ts @@ -0,0 +1,9 @@ + +export interface XRStatic { + requestSession(sessionId: string): Promise; + endSession(): Promise; + supportsMultipleScenes: boolean; +} + +export const XR: XRStatic; +export type XR = XRStatic; diff --git a/packages/react-native/Libraries/XR/XR.js b/packages/react-native/Libraries/XR/XR.js new file mode 100644 index 00000000000000..3487429aff1bb5 --- /dev/null +++ b/packages/react-native/Libraries/XR/XR.js @@ -0,0 +1,33 @@ +/** + * @format + * @flow strict + * @jsdoc + */ + +import NativeXRModule from './NativeXRModule'; + +const XR = { + requestSession: (sessionId?: string): Promise => { + if (NativeXRModule != null && NativeXRModule.requestSession != null) { + return NativeXRModule.requestSession(sessionId); + } + return Promise.reject(new Error('NativeXRModule is not available')); + }, + endSession: (): Promise => { + if (NativeXRModule != null && NativeXRModule.endSession != null) { + return NativeXRModule.endSession(); + } + return Promise.reject(new Error('NativeXRModule is not available')); + }, + // $FlowIgnore[unsafe-getters-setters] + get supportsMultipleScenes(): boolean { + if (NativeXRModule == null) { + return false; + } + + const nativeConstants = NativeXRModule.getConstants(); + return nativeConstants.supportsMultipleScenes || false; + }, +}; + +module.exports = XR; diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index b56956a0396f5b..c2f919b1c30195 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -9553,6 +9553,22 @@ declare module.exports: WebSocketInterceptor; " `; +exports[`public API should not change unintentionally Libraries/XR/NativeXRModule.js 1`] = ` +"export * from \\"../../src/private/specs/visionos_modules/NativeXRModule\\"; +declare export default typeof NativeXRModule; +" +`; + +exports[`public API should not change unintentionally Libraries/XR/XR.js 1`] = ` +"declare const XR: { + requestSession: (sessionId?: string) => Promise, + endSession: () => Promise, + get supportsMultipleScenes(): boolean, +}; +declare module.exports: XR; +" +`; + exports[`public API should not change unintentionally Libraries/YellowBox/YellowBoxDeprecated.js 1`] = ` "declare const React: $FlowFixMe; type Props = $ReadOnly<{||}>; @@ -9673,6 +9689,7 @@ declare module.exports: { get PushNotificationIOS(): PushNotificationIOS, get Settings(): Settings, get Share(): Share, + get XR(): XR, get StyleSheet(): StyleSheet, get Systrace(): Systrace, get ToastAndroid(): ToastAndroid, diff --git a/packages/react-native/React-Core.podspec b/packages/react-native/React-Core.podspec index 2848b325c73e59..53ac10262d5b6e 100644 --- a/packages/react-native/React-Core.podspec +++ b/packages/react-native/React-Core.podspec @@ -41,6 +41,7 @@ header_subspecs = { 'RCTSettingsHeaders' => 'Libraries/Settings/*.h', 'RCTTextHeaders' => 'Libraries/Text/**/*.h', 'RCTVibrationHeaders' => 'Libraries/Vibration/*.h', + 'RCTXRHeaders' => 'Libraries/XR/*.h', } frameworks_search_paths = [] diff --git a/packages/react-native/React.podspec b/packages/react-native/React.podspec index 59b9f8319ae306..2d085e63040906 100644 --- a/packages/react-native/React.podspec +++ b/packages/react-native/React.podspec @@ -53,4 +53,5 @@ Pod::Spec.new do |s| s.dependency "React-RCTSettings", version s.dependency "React-RCTText", version s.dependency "React-RCTVibration", version + s.dependency "React-RCTXR", version end diff --git a/packages/react-native/React/Base/RCTUtils.m b/packages/react-native/React/Base/RCTUtils.m index 559031c306da2e..d4b61aa0796834 100644 --- a/packages/react-native/React/Base/RCTUtils.m +++ b/packages/react-native/React/Base/RCTUtils.m @@ -580,6 +580,13 @@ BOOL RCTRunningInAppExtension(void) continue; } + #if TARGET_OS_VISION + /// Presenting scenes over Immersive Spaces leads to crash: "Presentations are not permitted within volumetric window scenes." + if (scene.session.role == UISceneSessionRoleImmersiveSpaceApplication) { + continue; + } +#endif + if (scene.activationState == UISceneActivationStateForegroundActive) { foregroundActiveScene = scene; break; diff --git a/packages/react-native/index.js b/packages/react-native/index.js index 31f568698f6f2a..33381d473d5202 100644 --- a/packages/react-native/index.js +++ b/packages/react-native/index.js @@ -96,6 +96,7 @@ import typeof Platform from './Libraries/Utilities/Platform'; import typeof useColorScheme from './Libraries/Utilities/useColorScheme'; import typeof useWindowDimensions from './Libraries/Utilities/useWindowDimensions'; import typeof Vibration from './Libraries/Vibration/Vibration'; +import typeof XR from './Libraries/XR/XR'; import typeof YellowBox from './Libraries/YellowBox/YellowBoxDeprecated'; import typeof DevMenu from './src/private/devmenu/DevMenu'; @@ -314,6 +315,9 @@ module.exports = { get Share(): Share { return require('./Libraries/Share/Share'); }, + get XR(): XR { + return require('./Libraries/XR/XR'); + }, get StyleSheet(): StyleSheet { return require('./Libraries/StyleSheet/StyleSheet'); }, diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 4db4e7b6097537..b0ff1951b2a7b6 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -157,6 +157,13 @@ "android": {}, "jsSrcsDir": "src" }, + { + "name": "FBReactNativeSpec_visionOS", + "type": "modules", + "ios": {}, + "android": {}, + "jsSrcsDir": "src/private/specs/visionos_modules" + }, { "name": "rncore", "type": "components", diff --git a/packages/react-native/scripts/cocoapods/utils.rb b/packages/react-native/scripts/cocoapods/utils.rb index 4a3dc7d3da68ae..0c2d691bf27c2f 100644 --- a/packages/react-native/scripts/cocoapods/utils.rb +++ b/packages/react-native/scripts/cocoapods/utils.rb @@ -646,6 +646,7 @@ def self.react_native_pods "glog", "hermes-engine", "React-hermes", + "React-RCTXR", # visionOS ] end diff --git a/packages/react-native/scripts/react_native_pods.rb b/packages/react-native/scripts/react_native_pods.rb index 53682acd13dd14..5ee7863cf083cd 100644 --- a/packages/react-native/scripts/react_native_pods.rb +++ b/packages/react-native/scripts/react_native_pods.rb @@ -135,6 +135,7 @@ def use_react_native! ( pod 'RCTDeprecation', :path => "#{prefix}/ReactApple/Libraries/RCTFoundation/RCTDeprecation" pod 'React-RCTFBReactNativeSpec', :path => "#{prefix}/React" pod 'React-RCTSwiftExtensions', :path => "#{prefix}/Libraries/SwiftExtensions" + pod 'React-RCTXR', :path => "#{prefix}/Libraries/XR" if hermes_enabled setup_hermes!(:react_native_path => prefix) diff --git a/packages/react-native/src/private/specs/visionos_modules/NativeXRModule.js b/packages/react-native/src/private/specs/visionos_modules/NativeXRModule.js new file mode 100644 index 00000000000000..ce8d22dca68c49 --- /dev/null +++ b/packages/react-native/src/private/specs/visionos_modules/NativeXRModule.js @@ -0,0 +1,21 @@ +/** + * @flow strict + * @format + */ + +import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport'; + +import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry'; + +export type XRModuleConstants = {| + +supportsMultipleScenes?: boolean, +|}; + +export interface Spec extends TurboModule { + +getConstants: () => XRModuleConstants; + + +requestSession: (sessionId?: string) => Promise; + +endSession: () => Promise; +} + +export default (TurboModuleRegistry.get('XRModule'): ?Spec); diff --git a/packages/react-native/types/index.d.ts b/packages/react-native/types/index.d.ts index 63fc7e3096dac8..717e3aea50806a 100644 --- a/packages/react-native/types/index.d.ts +++ b/packages/react-native/types/index.d.ts @@ -148,6 +148,7 @@ export * from '../Libraries/Utilities/Dimensions'; export * from '../Libraries/Utilities/PixelRatio'; export * from '../Libraries/Utilities/Platform'; export * from '../Libraries/Vibration/Vibration'; +export * from '../Libraries/XR/XR'; export * from '../Libraries/YellowBox/YellowBoxDeprecated'; export * from '../Libraries/vendor/core/ErrorUtils'; export { diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index e90bb19081fe5a..f23ba8dd7633cf 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -15,17 +15,16 @@ PODS: - RCT-Folly (= 2024.11.18.00) - RCTRequired - RCTTypeSafety + - React-Codegen - React-Core - React-debug - React-Fabric - - React-featureflags - React-graphics - React-ImageManager - React-NativeModulesApple - React-RCTFabric - React-rendererdebug - React-utils - - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga @@ -58,17 +57,16 @@ PODS: - RCT-Folly (= 2024.11.18.00) - RCTRequired - RCTTypeSafety + - React-Codegen - React-Core - React-debug - React-Fabric - - React-featureflags - React-graphics - React-ImageManager - React-NativeModulesApple - React-RCTFabric - React-rendererdebug - React-utils - - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga @@ -110,9 +108,27 @@ PODS: - React-RCTSettings (= 1000.0.0) - React-RCTText (= 1000.0.0) - React-RCTVibration (= 1000.0.0) - - React-RCTWindowManager (= 1000.0.0) - React-RCTXR (= 1000.0.0) - React-callinvoker (1000.0.0) + - React-Codegen (1000.0.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-FabricImage + - React-graphics + - React-jsi + - React-jsiexecutor + - React-NativeModulesApple + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core - React-Core (1000.0.0): - glog - hermes-engine @@ -120,11 +136,9 @@ PODS: - RCTDeprecation - React-Core/Default (= 1000.0.0) - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -137,11 +151,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -153,11 +165,10 @@ PODS: - RCT-Folly (= 2024.11.18.00) - RCTDeprecation - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector + - React-jsinspector (= 1000.0.0) - React-perflogger - React-runtimescheduler - React-utils @@ -171,11 +182,10 @@ PODS: - React-Core/Default (= 1000.0.0) - React-Core/RCTWebSocket (= 1000.0.0) - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector + - React-jsinspector (= 1000.0.0) - React-perflogger - React-runtimescheduler - React-utils @@ -188,11 +198,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -205,11 +213,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -222,11 +228,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -239,11 +243,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -256,11 +258,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -273,11 +273,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -290,11 +288,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -307,11 +303,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -324,11 +318,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -341,11 +333,9 @@ PODS: - RCTDeprecation - React-Core/Default - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils @@ -358,7 +348,6 @@ PODS: - RCTDeprecation - React-Core/Default (= 1000.0.0) - React-cxxreact - - React-featureflags - React-hermes - React-jsi - React-jsiexecutor @@ -374,9 +363,9 @@ PODS: - fmt (= 11.0.2) - RCT-Folly (= 2024.11.18.00) - RCTTypeSafety (= 1000.0.0) + - React-Codegen - React-Core/CoreModulesHeaders (= 1000.0.0) - React-jsi (= 1000.0.0) - - React-jsinspector - React-NativeModulesApple - React-RCTBlob - React-RCTFBReactNativeSpec @@ -394,7 +383,7 @@ PODS: - React-callinvoker (= 1000.0.0) - React-debug (= 1000.0.0) - React-jsi (= 1000.0.0) - - React-jsinspector + - React-jsinspector (= 1000.0.0) - React-logger (= 1000.0.0) - React-perflogger (= 1000.0.0) - React-runtimeexecutor (= 1000.0.0) @@ -449,7 +438,6 @@ PODS: - React-Fabric/telemetry (= 1000.0.0) - React-Fabric/templateprocessor (= 1000.0.0) - React-Fabric/uimanager (= 1000.0.0) - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -470,7 +458,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -491,7 +478,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -512,7 +498,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -533,7 +518,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -557,7 +541,6 @@ PODS: - React-Fabric/components/legacyviewmanagerinterop (= 1000.0.0) - React-Fabric/components/root (= 1000.0.0) - React-Fabric/components/view (= 1000.0.0) - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -578,7 +561,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -599,7 +581,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -620,7 +601,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -663,7 +643,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -705,7 +684,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -726,7 +704,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -747,7 +724,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -790,7 +766,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -834,7 +809,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -855,7 +829,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -1246,7 +1219,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi - React-jsiexecutor (= 1000.0.0) - - React-jsinspector + - React-jsinspector (= 1000.0.0) - React-perflogger (= 1000.0.0) - React-runtimeexecutor - React-idlecallbacksnativemodule (1000.0.0): @@ -1293,7 +1266,6 @@ PODS: - RCT-Folly (= 2024.11.18.00) - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - - React-jsinspector - React-perflogger (= 1000.0.0) - React-jsinspector (1000.0.0): - DoubleConversion @@ -1328,7 +1300,6 @@ PODS: - React-Core - React-cxxreact - React-jsi - - React-jsinspector - React-runtimeexecutor - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core @@ -1346,6 +1317,7 @@ PODS: - React-RCTAnimation (1000.0.0): - RCT-Folly (= 2024.11.18.00) - RCTTypeSafety + - React-Codegen - React-Core/RCTAnimationHeaders - React-jsi - React-NativeModulesApple @@ -1384,7 +1356,6 @@ PODS: - React-Core/RCTBlobHeaders - React-Core/RCTWebSocket - React-jsi - - React-jsinspector - React-NativeModulesApple - React-RCTFBReactNativeSpec - React-RCTNetwork @@ -1398,7 +1369,6 @@ PODS: - React-Fabric - React-FabricComponents - React-FabricImage - - React-featureflags - React-graphics - React-ImageManager - React-jsi @@ -1425,6 +1395,7 @@ PODS: - React-RCTImage (1000.0.0): - RCT-Folly (= 2024.11.18.00) - RCTTypeSafety + - React-Codegen - React-Core/RCTImageHeaders - React-jsi - React-NativeModulesApple @@ -1432,6 +1403,7 @@ PODS: - React-RCTNetwork - ReactCommon - React-RCTLinking (1000.0.0): + - React-Codegen - React-Core/RCTLinkingHeaders (= 1000.0.0) - React-jsi (= 1000.0.0) - React-NativeModulesApple @@ -1441,6 +1413,7 @@ PODS: - React-RCTNetwork (1000.0.0): - RCT-Folly (= 2024.11.18.00) - RCTTypeSafety + - React-Codegen - React-Core/RCTNetworkHeaders - React-jsi - React-NativeModulesApple @@ -1448,6 +1421,7 @@ PODS: - ReactCommon - React-RCTPushNotification (1000.0.0): - RCTTypeSafety + - React-Codegen - React-Core/RCTPushNotificationHeaders - React-jsi - React-NativeModulesApple @@ -1456,6 +1430,7 @@ PODS: - React-RCTSettings (1000.0.0): - RCT-Folly (= 2024.11.18.00) - RCTTypeSafety + - React-Codegen - React-Core/RCTSettingsHeaders - React-jsi - React-NativeModulesApple @@ -1463,7 +1438,6 @@ PODS: - ReactCommon - React-RCTSwiftExtensions (1000.0.0): - React-Core - - React-RCTWindowManager - React-RCTXR - React-RCTTest (1000.0.0): - RCT-Folly (= 2024.11.18.00) @@ -1549,7 +1523,6 @@ PODS: - React-featureflags - React-hermes - React-jsi - - React-jsinspector - React-jsitracing - React-RuntimeCore - React-utils @@ -1560,7 +1533,6 @@ PODS: - React-callinvoker - React-cxxreact - React-debug - - React-featureflags - React-jsi - React-performancetimeline - React-rendererconsistency @@ -1599,6 +1571,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - ReactCommon (1000.0.0): + - React-logger (= 1000.0.0) - ReactCommon/turbomodule (= 1000.0.0) - ReactCommon-Samples (1000.0.0): - DoubleConversion @@ -1606,6 +1579,7 @@ PODS: - fmt (= 11.0.2) - hermes-engine - RCT-Folly + - React-Codegen - React-Core - React-cxxreact - React-jsi @@ -1648,7 +1622,6 @@ PODS: - React-callinvoker (= 1000.0.0) - React-cxxreact (= 1000.0.0) - React-debug (= 1000.0.0) - - React-featureflags (= 1000.0.0) - React-jsi (= 1000.0.0) - React-logger (= 1000.0.0) - React-perflogger (= 1000.0.0) @@ -1660,17 +1633,16 @@ PODS: - RCT-Folly (= 2024.11.18.00) - RCTRequired - RCTTypeSafety + - React-Codegen - React-Core - React-debug - React-Fabric - - React-featureflags - React-graphics - React-ImageManager - React-NativeModulesApple - React-RCTFabric - React-rendererdebug - React-utils - - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga @@ -1696,6 +1668,7 @@ DEPENDENCIES: - RCTTypeSafety (from `../react-native/Libraries/TypeSafety`) - React (from `../react-native/`) - React-callinvoker (from `../react-native/ReactCommon/callinvoker`) + - React-Codegen (from `build/generated/ios`) - React-Core (from `../react-native/`) - React-Core/RCTWebSocket (from `../react-native/`) - React-CoreModules (from `../react-native/React/CoreModules`) @@ -1706,8 +1679,6 @@ DEPENDENCIES: - React-Fabric (from `../react-native/ReactCommon`) - React-FabricComponents (from `../react-native/ReactCommon`) - React-FabricImage (from `../react-native/ReactCommon`) - - React-featureflags (from `../react-native/ReactCommon/react/featureflags`) - - React-featureflagsnativemodule (from `../react-native/ReactCommon/react/nativemodule/featureflags`) - React-graphics (from `../react-native/ReactCommon/react/renderer/graphics`) - React-hermes (from `../react-native/ReactCommon/hermes`) - React-idlecallbacksnativemodule (from `../react-native/ReactCommon/react/nativemodule/idlecallbacks`) @@ -1793,6 +1764,8 @@ EXTERNAL SOURCES: :path: "../react-native/" React-callinvoker: :path: "../react-native/ReactCommon/callinvoker" + React-Codegen: + :path: build/generated/ios React-Core: :path: "../react-native/" React-CoreModules: @@ -1811,10 +1784,6 @@ EXTERNAL SOURCES: :path: "../react-native/ReactCommon" React-FabricImage: :path: "../react-native/ReactCommon" - React-featureflags: - :path: "../react-native/ReactCommon/react/featureflags" - React-featureflagsnativemodule: - :path: "../react-native/ReactCommon/react/nativemodule/featureflags" React-graphics: :path: "../react-native/ReactCommon/react/renderer/graphics" React-hermes: diff --git a/packages/rn-tester/RNTester-visionOS/App.swift b/packages/rn-tester/RNTester-visionOS/App.swift index 39224b803cce1b..8e28482981e8a6 100644 --- a/packages/rn-tester/RNTester-visionOS/App.swift +++ b/packages/rn-tester/RNTester-visionOS/App.swift @@ -5,8 +5,11 @@ import React_RCTSwiftExtensions @main struct RNTesterApp: App { @UIApplicationDelegateAdaptor var delegate: AppDelegate + @State private var immersionLevel: ImmersionStyle = .full var body: some Scene { RCTMainWindow(moduleName: "RNTesterApp") + ImmersiveSpace(id: "TestImmersiveSpace") {} + .immersionStyle(selection: $immersionLevel, in: .mixed, .progressive, .full) } } diff --git a/packages/rn-tester/RNTester-visionOS/Info.plist b/packages/rn-tester/RNTester-visionOS/Info.plist index 940d4ef45518db..20f75e2afa73d1 100644 --- a/packages/rn-tester/RNTester-visionOS/Info.plist +++ b/packages/rn-tester/RNTester-visionOS/Info.plist @@ -7,7 +7,7 @@ UIApplicationPreferredDefaultSceneSessionRole UIWindowSceneSessionRoleApplication UIApplicationSupportsMultipleScenes - + UISceneConfigurations diff --git a/packages/rn-tester/js/examples/XR/XRExample.js b/packages/rn-tester/js/examples/XR/XRExample.js new file mode 100644 index 00000000000000..b9bd48e3f5c2c3 --- /dev/null +++ b/packages/rn-tester/js/examples/XR/XRExample.js @@ -0,0 +1,71 @@ +/** + * 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. + * + * @format + * @flow + */ + +'use strict'; + +const {XR} = require('@callstack/react-native-visionos'); +const React = require('react'); +const {Alert, Button, StyleSheet, Text, View} = require('react-native'); + +const OpenXRSession = () => { + const [isOpen, setIsOpen] = React.useState(false); + + const openXRSession = async () => { + try { + if (!XR.supportsMultipleScenes) { + Alert.alert('Error', 'Multiple scenes are not supported'); + return; + } + await XR.requestSession('TestImmersiveSpace'); + setIsOpen(true); + } catch (e) { + Alert.alert('Error', e.message); + setIsOpen(false); + } + }; + + const closeXRSession = async () => { + if (isOpen) { + await XR.endSession(); + } + }; + + return ( + + Is XR session open: {isOpen} +