@reactvision/react-viro 2.54.0 → 2.55.0
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/README.md +85 -46
- package/android/react_viro/react_viro-release.aar +0 -0
- package/android/viro_renderer/viro_renderer-release.aar +0 -0
- package/components/AR/ViroARCamera.tsx +5 -0
- package/components/AR/ViroARImageMarker.tsx +5 -0
- package/components/AR/ViroARObjectMarker.tsx +5 -0
- package/components/AR/ViroARPlane.tsx +5 -0
- package/components/AR/ViroARPlaneSelector.tsx +5 -0
- package/components/AR/ViroARScene.tsx +5 -0
- package/components/AR/ViroARSceneNavigator.tsx +54 -0
- package/components/Studio/StudioARScene.tsx +368 -0
- package/components/Studio/StudioSceneNavigator.tsx +191 -0
- package/components/Studio/VRTStudioModule.ts +40 -0
- package/components/Studio/domain/animationRegistry.ts +86 -0
- package/components/Studio/domain/collisionBindingsRuntime.ts +93 -0
- package/components/Studio/domain/collisionPairKey.ts +15 -0
- package/components/Studio/domain/dragConfiguration.ts +48 -0
- package/components/Studio/domain/materialConfig.ts +276 -0
- package/components/Studio/domain/physicsConfig.ts +204 -0
- package/components/Studio/domain/sceneNavigationHandler.ts +150 -0
- package/components/Studio/domain/studioMaterials.ts +33 -0
- package/components/Studio/domain/triggerImageRegistry.ts +64 -0
- package/components/Studio/domain/useStudioShaderTimeUniforms.ts +51 -0
- package/components/Studio/domain/useStudioShaderViewportUniforms.ts +52 -0
- package/components/Studio/domain/viroNodeFactory.tsx +323 -0
- package/components/Studio/index.ts +18 -0
- package/components/Studio/types.ts +164 -0
- package/components/Types/ViroEvents.ts +53 -0
- package/components/Utilities/VRModuleOpenXR.ts +50 -0
- package/components/Utilities/VRQuestNavigatorBridge.ts +168 -0
- package/components/Utilities/ViroPlatform.ts +52 -0
- package/components/Utilities/ViroVersion.ts +1 -1
- package/components/Utilities/useAnySourceHover.ts +55 -0
- package/components/Utilities/useAnySourcePressed.ts +70 -0
- package/components/ViroQuestEntryPoint.tsx +79 -0
- package/components/ViroVRSceneNavigator.tsx +44 -19
- package/components/ViroXRSceneNavigator.tsx +217 -0
- package/components/VisionOS/ViroVisionOSModule.ts +93 -0
- package/dist/components/AR/ViroARCamera.d.ts +1 -1
- package/dist/components/AR/ViroARCamera.js +5 -0
- package/dist/components/AR/ViroARImageMarker.d.ts +1 -1
- package/dist/components/AR/ViroARImageMarker.js +5 -0
- package/dist/components/AR/ViroARObjectMarker.d.ts +1 -1
- package/dist/components/AR/ViroARObjectMarker.js +5 -0
- package/dist/components/AR/ViroARPlane.d.ts +1 -1
- package/dist/components/AR/ViroARPlane.js +5 -0
- package/dist/components/AR/ViroARPlaneSelector.d.ts +1 -1
- package/dist/components/AR/ViroARPlaneSelector.js +5 -0
- package/dist/components/AR/ViroARScene.d.ts +1 -1
- package/dist/components/AR/ViroARScene.js +5 -0
- package/dist/components/AR/ViroARSceneNavigator.d.ts +13 -0
- package/dist/components/AR/ViroARSceneNavigator.js +36 -0
- package/dist/components/Studio/StudioARScene.d.ts +15 -0
- package/dist/components/Studio/StudioARScene.js +299 -0
- package/dist/components/Studio/StudioSceneNavigator.d.ts +31 -0
- package/dist/components/Studio/StudioSceneNavigator.js +174 -0
- package/dist/components/Studio/VRTStudioModule.d.ts +15 -0
- package/dist/components/Studio/VRTStudioModule.js +31 -0
- package/dist/components/Studio/domain/animationRegistry.d.ts +11 -0
- package/dist/components/Studio/domain/animationRegistry.js +67 -0
- package/dist/components/Studio/domain/collisionBindingsRuntime.d.ts +21 -0
- package/dist/components/Studio/domain/collisionBindingsRuntime.js +54 -0
- package/dist/components/Studio/domain/collisionPairKey.d.ts +8 -0
- package/dist/components/Studio/domain/collisionPairKey.js +15 -0
- package/dist/components/Studio/domain/dragConfiguration.d.ts +20 -0
- package/dist/components/Studio/domain/dragConfiguration.js +37 -0
- package/dist/components/Studio/domain/materialConfig.d.ts +56 -0
- package/dist/components/Studio/domain/materialConfig.js +239 -0
- package/dist/components/Studio/domain/physicsConfig.d.ts +69 -0
- package/dist/components/Studio/domain/physicsConfig.js +165 -0
- package/dist/components/Studio/domain/sceneNavigationHandler.d.ts +12 -0
- package/dist/components/Studio/domain/sceneNavigationHandler.js +112 -0
- package/dist/components/Studio/domain/studioMaterials.d.ts +6 -0
- package/dist/components/Studio/domain/studioMaterials.js +30 -0
- package/dist/components/Studio/domain/triggerImageRegistry.d.ts +13 -0
- package/dist/components/Studio/domain/triggerImageRegistry.js +47 -0
- package/dist/components/Studio/domain/useStudioShaderTimeUniforms.d.ts +6 -0
- package/dist/components/Studio/domain/useStudioShaderTimeUniforms.js +48 -0
- package/dist/components/Studio/domain/useStudioShaderViewportUniforms.d.ts +6 -0
- package/dist/components/Studio/domain/useStudioShaderViewportUniforms.js +48 -0
- package/dist/components/Studio/domain/viroNodeFactory.d.ts +28 -0
- package/dist/components/Studio/domain/viroNodeFactory.js +193 -0
- package/dist/components/Studio/index.d.ts +3 -0
- package/dist/components/Studio/index.js +7 -0
- package/dist/components/Studio/types.d.ts +149 -0
- package/dist/components/Studio/types.js +4 -0
- package/dist/components/Types/ViroEvents.d.ts +49 -1
- package/dist/components/Types/ViroEvents.js +1 -0
- package/dist/components/Utilities/VRModuleOpenXR.d.ts +32 -0
- package/dist/components/Utilities/VRModuleOpenXR.js +44 -0
- package/dist/components/Utilities/VRQuestNavigatorBridge.d.ts +85 -0
- package/dist/components/Utilities/VRQuestNavigatorBridge.js +124 -0
- package/dist/components/Utilities/ViroPlatform.d.ts +10 -0
- package/dist/components/Utilities/ViroPlatform.js +43 -0
- package/dist/components/Utilities/ViroVersion.d.ts +1 -1
- package/dist/components/Utilities/ViroVersion.js +1 -1
- package/dist/components/Utilities/useAnySourceHover.d.ts +36 -0
- package/dist/components/Utilities/useAnySourceHover.js +48 -0
- package/dist/components/Utilities/useAnySourcePressed.d.ts +37 -0
- package/dist/components/Utilities/useAnySourcePressed.js +61 -0
- package/dist/components/ViroQuestEntryPoint.d.ts +13 -0
- package/dist/components/ViroQuestEntryPoint.js +104 -0
- package/dist/components/ViroVRSceneNavigator.d.ts +24 -10
- package/dist/components/ViroVRSceneNavigator.js +21 -18
- package/dist/components/ViroXRSceneNavigator.d.ts +54 -0
- package/dist/components/ViroXRSceneNavigator.js +173 -0
- package/dist/components/VisionOS/ViroVisionOSModule.d.ts +65 -0
- package/dist/components/VisionOS/ViroVisionOSModule.js +91 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.js +32 -2
- package/dist/plugins/withViro.d.ts +17 -1
- package/dist/plugins/withViroAndroid.js +312 -7
- package/dist/plugins/withViroIos.js +5 -0
- package/dist/plugins/withViroVisionOS.d.ts +24 -0
- package/dist/plugins/withViroVisionOS.js +265 -0
- package/index.ts +58 -0
- package/ios/ViroReact.podspec +13 -4
- package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreCoreMLSemanticsResources.bundle/Info.plist +0 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreResources.bundle/Info.plist +0 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSession.h +10 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSessioniOS.h +4 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROInputControllerBase.h +74 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROInputType.h +11 -3
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROPlatformUtil.h +13 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VRORenderer.h +8 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Info.plist +0 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Shaders.dat +1 -1
- package/ios/dist/ViroRenderer/ViroKit.framework/ViroKit +0 -0
- package/ios/dist/ViroRenderer/ViroKit.podspec +5 -0
- package/ios/dist/include/VRTARSceneNavigator.h +3 -0
- package/ios/dist/include/VRTStudioModule.h +6 -0
- package/ios/dist/lib/libViroReact.a +0 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.VIRO_VERSION = exports.ViroRotateStateTypes = exports.ViroPinchStateTypes = exports.ViroClickStateTypes = exports.gpsToArWorld = exports.latLngToMercator = exports.checkPermissions = exports.requestRequiredPermissions = exports.isARSupportedOnDevice = exports.polarToCartesianActual = exports.polarToCartesian = exports.ViroTrackingStateConstants = exports.ViroRecordingErrorConstants = void 0;
|
|
3
|
+
exports.ViroQuestEntryPoint = exports.ViroXRSceneNavigator = exports.ViroVRSceneNavigator = exports.ViroVideo = exports.ViroText = exports.ViroSpotLight = exports.ViroSpinner = exports.ViroSphere = exports.ViroSpatialSound = exports.ViroSoundField = exports.ViroSound = exports.ViroAnimatedComponent = exports.ViroAmbientLight = exports.ViroAnimatedImage = exports.Viro360Video = exports.Viro360Image = exports.Viro3DObject = exports.ViroAnimations = exports.ViroSkyBox = exports.ViroSceneNavigator = exports.ViroSurface = exports.ViroScene = exports.ViroQuad = exports.ViroPortalScene = exports.ViroPortal = exports.ViroPolyline = exports.ViroPolygon = exports.ViroParticleEmitter = exports.ViroOrbitCamera = exports.ViroOmniLight = exports.ViroNode = exports.ViroMaterialVideo = exports.ViroARCamera = exports.ViroMaterials = exports.ViroImage = exports.ViroLightingEnvironment = exports.ViroGeometry = exports.ViroFlexView = exports.ViroDirectionalLight = exports.ViroController = exports.ViroCamera = exports.ViroButton = exports.ViroBox = exports.ViroARSceneNavigator = exports.ViroARScene = exports.ViroARPlaneSelector = exports.ViroARPlane = exports.ViroARTrackingTargets = exports.ViroARObjectMarker = exports.ViroARImageMarker = void 0;
|
|
4
|
+
exports.exitImmersiveSpace = exports.enterImmersiveSpace = exports.isVisionOS = exports.ViroVisionOSModule = exports.StudioARScene = exports.StudioSceneNavigator = exports.VIRO_VERSION = exports.ViroRotateStateTypes = exports.ViroPinchStateTypes = exports.ViroClickStateTypes = exports.gpsToArWorld = exports.latLngToMercator = exports.checkPermissions = exports.requestRequiredPermissions = exports.isARSupportedOnDevice = exports.polarToCartesianActual = exports.polarToCartesian = exports.ViroTrackingStateConstants = exports.ViroRecordingErrorConstants = exports.ViroARTrackingReasonConstants = exports.useAnySourcePressed = exports.useAnySourceHover = exports.isQuest = exports.hasOpenXRSupport = exports.Viro3DSceneNavigator = exports.exitVRScene = exports.useVRViewTag = exports.VRModuleOpenXR = exports.VRQuestNavigatorBridge = void 0;
|
|
5
5
|
/**
|
|
6
6
|
* Copyright (c) 2016-present, Viro Media, Inc.
|
|
7
7
|
* All rights reserved.
|
|
@@ -9,6 +9,14 @@ exports.VIRO_VERSION = exports.ViroRotateStateTypes = exports.ViroPinchStateType
|
|
|
9
9
|
*/
|
|
10
10
|
const ViroAnimations_1 = require("./components/Animation/ViroAnimations");
|
|
11
11
|
Object.defineProperty(exports, "ViroAnimations", { enumerable: true, get: function () { return ViroAnimations_1.ViroAnimations; } });
|
|
12
|
+
const Studio_1 = require("./components/Studio");
|
|
13
|
+
Object.defineProperty(exports, "StudioSceneNavigator", { enumerable: true, get: function () { return Studio_1.StudioSceneNavigator; } });
|
|
14
|
+
Object.defineProperty(exports, "StudioARScene", { enumerable: true, get: function () { return Studio_1.StudioARScene; } });
|
|
15
|
+
const ViroVisionOSModule_1 = require("./components/VisionOS/ViroVisionOSModule");
|
|
16
|
+
Object.defineProperty(exports, "ViroVisionOSModule", { enumerable: true, get: function () { return ViroVisionOSModule_1.ViroVisionOSModule; } });
|
|
17
|
+
Object.defineProperty(exports, "isVisionOS", { enumerable: true, get: function () { return ViroVisionOSModule_1.isVisionOS; } });
|
|
18
|
+
Object.defineProperty(exports, "enterImmersiveSpace", { enumerable: true, get: function () { return ViroVisionOSModule_1.enterImmersiveSpace; } });
|
|
19
|
+
Object.defineProperty(exports, "exitImmersiveSpace", { enumerable: true, get: function () { return ViroVisionOSModule_1.exitImmersiveSpace; } });
|
|
12
20
|
const Viro3DObject_1 = require("./components/Viro3DObject");
|
|
13
21
|
Object.defineProperty(exports, "Viro3DObject", { enumerable: true, get: function () { return Viro3DObject_1.Viro3DObject; } });
|
|
14
22
|
const Viro360Image_1 = require("./components/Viro360Image");
|
|
@@ -101,8 +109,17 @@ const ViroVideo_1 = require("./components/ViroVideo");
|
|
|
101
109
|
Object.defineProperty(exports, "ViroVideo", { enumerable: true, get: function () { return ViroVideo_1.ViroVideo; } });
|
|
102
110
|
const ViroVRSceneNavigator_1 = require("./components/ViroVRSceneNavigator");
|
|
103
111
|
Object.defineProperty(exports, "ViroVRSceneNavigator", { enumerable: true, get: function () { return ViroVRSceneNavigator_1.ViroVRSceneNavigator; } });
|
|
112
|
+
const ViroXRSceneNavigator_1 = require("./components/ViroXRSceneNavigator");
|
|
113
|
+
Object.defineProperty(exports, "ViroXRSceneNavigator", { enumerable: true, get: function () { return ViroXRSceneNavigator_1.ViroXRSceneNavigator; } });
|
|
104
114
|
const Viro3DSceneNavigator_1 = require("./components/Viro3DSceneNavigator");
|
|
105
115
|
Object.defineProperty(exports, "Viro3DSceneNavigator", { enumerable: true, get: function () { return Viro3DSceneNavigator_1.Viro3DSceneNavigator; } });
|
|
116
|
+
const ViroPlatform_1 = require("./components/Utilities/ViroPlatform");
|
|
117
|
+
Object.defineProperty(exports, "hasOpenXRSupport", { enumerable: true, get: function () { return ViroPlatform_1.hasOpenXRSupport; } });
|
|
118
|
+
Object.defineProperty(exports, "isQuest", { enumerable: true, get: function () { return ViroPlatform_1.isQuest; } });
|
|
119
|
+
const useAnySourceHover_1 = require("./components/Utilities/useAnySourceHover");
|
|
120
|
+
Object.defineProperty(exports, "useAnySourceHover", { enumerable: true, get: function () { return useAnySourceHover_1.useAnySourceHover; } });
|
|
121
|
+
const useAnySourcePressed_1 = require("./components/Utilities/useAnySourcePressed");
|
|
122
|
+
Object.defineProperty(exports, "useAnySourcePressed", { enumerable: true, get: function () { return useAnySourcePressed_1.useAnySourcePressed; } });
|
|
106
123
|
const ViroUtils_1 = require("./components/Utilities/ViroUtils");
|
|
107
124
|
Object.defineProperty(exports, "polarToCartesian", { enumerable: true, get: function () { return ViroUtils_1.polarToCartesian; } });
|
|
108
125
|
Object.defineProperty(exports, "polarToCartesianActual", { enumerable: true, get: function () { return ViroUtils_1.polarToCartesianActual; } });
|
|
@@ -123,3 +140,16 @@ const ViroSceneNavigator_1 = require("./components/ViroSceneNavigator");
|
|
|
123
140
|
Object.defineProperty(exports, "ViroSceneNavigator", { enumerable: true, get: function () { return ViroSceneNavigator_1.ViroSceneNavigator; } });
|
|
124
141
|
const ViroVersion_1 = require("./components/Utilities/ViroVersion");
|
|
125
142
|
Object.defineProperty(exports, "VIRO_VERSION", { enumerable: true, get: function () { return ViroVersion_1.VIRO_VERSION; } });
|
|
143
|
+
const ViroQuestEntryPoint_1 = require("./components/ViroQuestEntryPoint");
|
|
144
|
+
Object.defineProperty(exports, "ViroQuestEntryPoint", { enumerable: true, get: function () { return ViroQuestEntryPoint_1.ViroQuestEntryPoint; } });
|
|
145
|
+
const VRQuestNavigatorBridge_1 = require("./components/Utilities/VRQuestNavigatorBridge");
|
|
146
|
+
Object.defineProperty(exports, "VRQuestNavigatorBridge", { enumerable: true, get: function () { return VRQuestNavigatorBridge_1.VRQuestNavigatorBridge; } });
|
|
147
|
+
const VRModuleOpenXR_1 = require("./components/Utilities/VRModuleOpenXR");
|
|
148
|
+
Object.defineProperty(exports, "VRModuleOpenXR", { enumerable: true, get: function () { return VRModuleOpenXR_1.VRModuleOpenXR; } });
|
|
149
|
+
Object.defineProperty(exports, "useVRViewTag", { enumerable: true, get: function () { return VRModuleOpenXR_1.useVRViewTag; } });
|
|
150
|
+
Object.defineProperty(exports, "exitVRScene", { enumerable: true, get: function () { return VRModuleOpenXR_1.exitVRScene; } });
|
|
151
|
+
const react_native_1 = require("react-native");
|
|
152
|
+
// Auto-register the Quest VR entry point. VRActivity launches this component
|
|
153
|
+
// as 'VRQuestScene'. Registering here means apps need no manual setup.
|
|
154
|
+
// Apps that need a custom VR root can re-register after importing this package.
|
|
155
|
+
react_native_1.AppRegistry.registerComponent("VRQuestScene", () => ViroQuestEntryPoint_1.ViroQuestEntryPoint);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConfigPlugin } from "@expo/config-plugins";
|
|
2
|
-
export type XrMode = "GVR" | "AR" | "OVR_MOBILE";
|
|
2
|
+
export type XrMode = "GVR" | "AR" | "OVR_MOBILE" | "QUEST";
|
|
3
3
|
/**
|
|
4
4
|
* Anchor provider type.
|
|
5
5
|
* - "none": Disabled
|
|
@@ -55,6 +55,13 @@ export interface ViroConfigurationOptions {
|
|
|
55
55
|
* Written to AndroidManifest as com.reactvision.RVProjectId and to Info.plist as RVProjectId.
|
|
56
56
|
*/
|
|
57
57
|
rvProjectId?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Override the ReactVision platform base URL.
|
|
60
|
+
* Omit for production. Set to a staging URL for testing.
|
|
61
|
+
*
|
|
62
|
+
* Written to AndroidManifest as com.reactvision.RVEndpoint and to Info.plist as RVEndpoint.
|
|
63
|
+
*/
|
|
64
|
+
rvEndpoint?: string;
|
|
58
65
|
/**
|
|
59
66
|
* Anchor provider for both cloud anchors and geospatial anchors.
|
|
60
67
|
* Replaces the deprecated cloudAnchorProvider + geospatialAnchorProvider props.
|
|
@@ -132,6 +139,15 @@ export interface ViroConfigurationOptions {
|
|
|
132
139
|
};
|
|
133
140
|
android?: {
|
|
134
141
|
xRMode?: XrMode[];
|
|
142
|
+
/**
|
|
143
|
+
* Meta Developer Portal App ID (numeric string).
|
|
144
|
+
* Written to AndroidManifest as com.oculus.app_id meta-data.
|
|
145
|
+
* Eliminates the "App Name Unavailable" popup on Meta Quest.
|
|
146
|
+
*
|
|
147
|
+
* Get your App ID from the Meta Developer Portal:
|
|
148
|
+
* https://developer.oculus.com/manage
|
|
149
|
+
*/
|
|
150
|
+
questAppId?: string;
|
|
135
151
|
};
|
|
136
152
|
}
|
|
137
153
|
/**
|
|
@@ -46,9 +46,9 @@ const withBranchAndroid = (config) => {
|
|
|
46
46
|
const viroPlugin = config?.plugins?.find((plugin) => Array.isArray(plugin) && plugin[0] === "@reactvision/react-viro");
|
|
47
47
|
if (Array.isArray(viroPlugin)) {
|
|
48
48
|
if (Array.isArray(viroPlugin[1].android?.xRMode)) {
|
|
49
|
-
viroPluginConfig = (viroPlugin[1].android?.xRMode).filter((mode) => ["AR", "GVR", "OVR_MOBILE"].includes(mode));
|
|
49
|
+
viroPluginConfig = (viroPlugin[1].android?.xRMode).filter((mode) => ["AR", "GVR", "OVR_MOBILE", "QUEST"].includes(mode));
|
|
50
50
|
}
|
|
51
|
-
else if (["AR", "GVR", "OVR_MOBILE"].includes(viroPlugin[1]?.android?.xRMode)) {
|
|
51
|
+
else if (["AR", "GVR", "OVR_MOBILE", "QUEST"].includes(viroPlugin[1]?.android?.xRMode)) {
|
|
52
52
|
viroPluginConfig = [viroPlugin[1]?.android.xRMode];
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -197,6 +197,14 @@ const withViroManifest = (config) => (0, config_plugins_1.withAndroidManifest)(c
|
|
|
197
197
|
},
|
|
198
198
|
});
|
|
199
199
|
}
|
|
200
|
+
if (pluginOptions.rvEndpoint) {
|
|
201
|
+
contents?.manifest?.application?.[0]["meta-data"]?.push({
|
|
202
|
+
$: {
|
|
203
|
+
"android:name": "com.reactvision.RVEndpoint",
|
|
204
|
+
"android:value": pluginOptions.rvEndpoint,
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
}
|
|
200
208
|
// Add location permissions when geospatial provider is active
|
|
201
209
|
if (geospatialAnchorProvider === "arcore" || geospatialAnchorProvider === "reactvision") {
|
|
202
210
|
const existingPermissions = (contents.manifest["uses-permission"] || [])
|
|
@@ -281,14 +289,311 @@ const withViroManifest = (config) => (0, config_plugins_1.withAndroidManifest)(c
|
|
|
281
289
|
"tools:replace": "required",
|
|
282
290
|
},
|
|
283
291
|
});
|
|
292
|
+
// Quest-specific features and permissions — after uses-feature is initialized
|
|
293
|
+
if (viroPluginConfig.includes("QUEST")) {
|
|
294
|
+
contents.manifest["uses-feature"].push({
|
|
295
|
+
$: {
|
|
296
|
+
"android:name": "android.hardware.vr.headtracking",
|
|
297
|
+
"android:required": "true",
|
|
298
|
+
"android:version": "1",
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
contents.manifest["uses-feature"].push({
|
|
302
|
+
$: {
|
|
303
|
+
"android:name": "oculus.software.handtracking",
|
|
304
|
+
"android:required": "false",
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
// XR_FB_passthrough requires this uses-feature; without it the OpenXR
|
|
308
|
+
// runtime silently strips the extension. required=false so apps that
|
|
309
|
+
// only render fully-virtual scenes still install on Quest 2 etc.
|
|
310
|
+
contents.manifest["uses-feature"].push({
|
|
311
|
+
$: {
|
|
312
|
+
"android:name": "com.oculus.feature.PASSTHROUGH",
|
|
313
|
+
"android:required": "false",
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
const existingPermissions = (contents.manifest["uses-permission"] || [])
|
|
317
|
+
.map((p) => p.$?.["android:name"]);
|
|
318
|
+
if (!existingPermissions.includes("com.oculus.permission.HAND_TRACKING")) {
|
|
319
|
+
contents.manifest["uses-permission"].push({
|
|
320
|
+
$: { "android:name": "com.oculus.permission.HAND_TRACKING" },
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
if (!existingPermissions.includes("com.oculus.permission.EYE_TRACKING")) {
|
|
324
|
+
contents.manifest["uses-permission"].push({
|
|
325
|
+
$: { "android:name": "com.oculus.permission.EYE_TRACKING" },
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
284
329
|
return newConfig;
|
|
285
330
|
});
|
|
331
|
+
// ── Quest VRActivity generation ────────────────────────────────────────────────
|
|
332
|
+
/**
|
|
333
|
+
* When QUEST mode is active, generate VRActivity.kt in the app's android source
|
|
334
|
+
* and register it in AndroidManifest with com.oculus.intent.category.VR.
|
|
335
|
+
*
|
|
336
|
+
* VRActivity is a ReactActivity that mounts "VRQuestScene" — a root component
|
|
337
|
+
* the app must register via AppRegistry. Running in a separate Activity with the
|
|
338
|
+
* VR intent category causes Horizon OS to grant exclusive OpenXR display access.
|
|
339
|
+
*/
|
|
340
|
+
const withViroQuestActivity = (config, props) => {
|
|
341
|
+
// Read xRMode directly from config.plugins. We cannot rely on the
|
|
342
|
+
// module-level `viroPluginConfig` here: that variable is only updated
|
|
343
|
+
// when `withBranchAndroid`'s withDangerousMod callback runs (mod-apply
|
|
344
|
+
// time), which is *after* this chain-time check executes. On the first
|
|
345
|
+
// prebuild of a new project, viroPluginConfig still holds the default
|
|
346
|
+
// ["AR", "GVR"] when this plugin is composed, and QUEST mods would be
|
|
347
|
+
// silently skipped — no VRActivity.kt and no manifest entry.
|
|
348
|
+
const viroPluginEntry = config?.plugins?.find((plugin) => Array.isArray(plugin) && plugin[0] === "@reactvision/react-viro");
|
|
349
|
+
let xrModes = ["AR", "GVR"];
|
|
350
|
+
if (Array.isArray(viroPluginEntry)) {
|
|
351
|
+
const xrMode = viroPluginEntry[1]?.android?.xRMode;
|
|
352
|
+
if (Array.isArray(xrMode)) {
|
|
353
|
+
xrModes = xrMode.filter((m) => ["AR", "GVR", "OVR_MOBILE", "QUEST"].includes(m));
|
|
354
|
+
}
|
|
355
|
+
else if (typeof xrMode === "string" &&
|
|
356
|
+
["AR", "GVR", "OVR_MOBILE", "QUEST"].includes(xrMode)) {
|
|
357
|
+
xrModes = [xrMode];
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (!xrModes.includes("QUEST"))
|
|
361
|
+
return config;
|
|
362
|
+
// 1. Generate VRActivity.kt
|
|
363
|
+
config = (0, config_plugins_1.withDangerousMod)(config, [
|
|
364
|
+
"android",
|
|
365
|
+
async (config) => {
|
|
366
|
+
const packageName = config?.android?.package ?? "";
|
|
367
|
+
const packagePath = packageName.split(".");
|
|
368
|
+
const activityDir = path_1.default.join(config.modRequest.platformProjectRoot, "app", "src", "main", "java", ...packagePath);
|
|
369
|
+
if (!fs_1.default.existsSync(activityDir)) {
|
|
370
|
+
fs_1.default.mkdirSync(activityDir, { recursive: true });
|
|
371
|
+
}
|
|
372
|
+
const activityPath = path_1.default.join(activityDir, "VRActivity.kt");
|
|
373
|
+
// Only write if not already present (preserve manual edits)
|
|
374
|
+
if (!fs_1.default.existsSync(activityPath)) {
|
|
375
|
+
const kotlinContent = `package ${packageName}
|
|
376
|
+
|
|
377
|
+
import android.app.Activity
|
|
378
|
+
import android.app.Application
|
|
379
|
+
import android.os.Bundle
|
|
380
|
+
import android.os.Handler
|
|
381
|
+
import android.os.Looper
|
|
382
|
+
import com.facebook.react.ReactActivity
|
|
383
|
+
import com.facebook.react.ReactActivityDelegate
|
|
384
|
+
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
|
|
385
|
+
import com.facebook.react.defaults.DefaultReactActivityDelegate
|
|
386
|
+
import com.facebook.react.runtime.ReactHostImpl
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* VRActivity — generated by @reactvision/react-viro Expo plugin.
|
|
390
|
+
* Carries com.oculus.intent.category.VR so Horizon OS grants exclusive
|
|
391
|
+
* OpenXR display access. Mounts the "VRQuestScene" React root component.
|
|
392
|
+
* Launch via NativeModules.VRLauncher.launchVRScene().
|
|
393
|
+
*
|
|
394
|
+
* Lifecycle (requires React Native >= 0.83 / Expo >= 55):
|
|
395
|
+
* VRActivity and MainActivity share one ReactHostImpl singleton. On Quest,
|
|
396
|
+
* VRActivity launches into a separate task (FLAG_ACTIVITY_NEW_TASK), so
|
|
397
|
+
* MainActivity.onPause is dispatched *later* via ActivityManager IPC —
|
|
398
|
+
* often after VRActivity.onResume has already promoted the host to RESUMED
|
|
399
|
+
* with currentActivity = VRActivity. When that delayed onPause arrives,
|
|
400
|
+
* the standard delegate calls onHostPause(MainActivity); the identity-
|
|
401
|
+
* mismatch assertion is downgraded to a warning by
|
|
402
|
+
* skipActivityIdentityAssertionOnHostPause (set in VRLauncherModule before
|
|
403
|
+
* startActivity), but the rest of onHostPause runs unconditionally:
|
|
404
|
+
* devSupport is disabled and JavaTimerManager clears its TIMERS_EVENTS
|
|
405
|
+
* callback. Result: timers / requestAnimationFrame stop, Metro Fast Refresh
|
|
406
|
+
* dies.
|
|
407
|
+
*
|
|
408
|
+
* We catch this by listening for that delayed MainActivity.onPause via
|
|
409
|
+
* Application.ActivityLifecycleCallbacks.onActivityPaused(other) and re-
|
|
410
|
+
* promoting the host on the main looper. A Handler.post inside our own
|
|
411
|
+
* onResume would fire too early (the ActivityManager hasn't queued
|
|
412
|
+
* MainActivity.onPause yet), which is why we hook the actual pause event.
|
|
413
|
+
*
|
|
414
|
+
* On exit, VRActivity.onPause runs while currentActivity == this, so the
|
|
415
|
+
* identity assertion passes; MainActivity.onResume then re-promotes via
|
|
416
|
+
* its standard delegate. We do *not* re-promote on a self-pause — the
|
|
417
|
+
* onActivityPaused callback skips when other === this.
|
|
418
|
+
*
|
|
419
|
+
* Mutual exclusion with MainActivity:
|
|
420
|
+
* Quest will happily run MainActivity (panel) and VRActivity (immersive) at
|
|
421
|
+
* the same time if the user taps the app icon in the dock while VR is
|
|
422
|
+
* running. The same Application.ActivityLifecycleCallbacks finishes self
|
|
423
|
+
* when any other Activity in this app resumes — returning the user cleanly
|
|
424
|
+
* to the panel.
|
|
425
|
+
*
|
|
426
|
+
* Surface cleanup on destroy:
|
|
427
|
+
* When VRActivity is destroyed we unload its React surface (reactSurface.stop()
|
|
428
|
+
* in bridgeless arch) so its component tree — including all VRT* components
|
|
429
|
+
* — is unmounted. Without this, the React surface stayed alive in the shared
|
|
430
|
+
* ReactHost across VR re-entries, and on the second/third VR launch each
|
|
431
|
+
* stale surface remounted alongside the fresh one. The C++ scene-graph
|
|
432
|
+
* resolves a click hit to a single viewTag, but multiple VRTComponents
|
|
433
|
+
* claimed it across surfaces — most with a ReactContext bound to a
|
|
434
|
+
* destroyed VRActivity. Click events to the stale ReactContexts crashed in
|
|
435
|
+
* ComponentEventDelegate as IllegalArgumentException SoftExceptions and were
|
|
436
|
+
* silently dropped, so onClick took dozens of presses to register.
|
|
437
|
+
* We still no-op the *delegate* onDestroy() so MainActivity keeps its
|
|
438
|
+
* ReactHost; we only stop the surface explicitly.
|
|
439
|
+
*/
|
|
440
|
+
class VRActivity : ReactActivity() {
|
|
441
|
+
|
|
442
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
443
|
+
private var lifecycleCallbacks: Application.ActivityLifecycleCallbacks? = null
|
|
444
|
+
|
|
445
|
+
// Set true on every VRActivity.onResume; consumed by the first
|
|
446
|
+
// onActivityPaused(other) that follows. One-shot — defends against the
|
|
447
|
+
// single MainActivity.onPause that the NEW_TASK ordering schedules late.
|
|
448
|
+
// Without one-shot semantics, every subsequent foreign pause would re-fire
|
|
449
|
+
// ReactHostImpl.onHostResume, which re-fires every LifecycleEventListener
|
|
450
|
+
// (AppState → "active" → ViroXRSceneNavigator's AppState handler calls
|
|
451
|
+
// launchVRScene() again → visible scene flicker).
|
|
452
|
+
private var expectingForeignPause = false
|
|
453
|
+
|
|
454
|
+
override fun getMainComponentName(): String = "VRQuestScene"
|
|
455
|
+
|
|
456
|
+
override fun createReactActivityDelegate(): ReactActivityDelegate =
|
|
457
|
+
object : DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) {
|
|
458
|
+
// VRActivity destruction MUST NOT tear down the shared ReactHost.
|
|
459
|
+
// MainActivity is still alive (and re-foreground after VR exit) and
|
|
460
|
+
// depends on the same ReactContext. The standard delegate's
|
|
461
|
+
// onDestroy forwards to ReactHostImpl.onHostDestroy(VR), which
|
|
462
|
+
// fires LifecycleEventListener.onHostDestroy on every native module
|
|
463
|
+
// — releasing native resources MainActivity still uses. The next
|
|
464
|
+
// Cmd+R reload then runs the JS bundle re-init against a partially
|
|
465
|
+
// destroyed native side and fails with
|
|
466
|
+
// [runtime not ready]: TypeError: Cannot read property
|
|
467
|
+
// 'EventEmitter' of undefined
|
|
468
|
+
// followed by AppRegistryBinding::stopSurface failed and the
|
|
469
|
+
// surface never recovers. By no-op'ing onDestroy here, host
|
|
470
|
+
// destruction is left to MainActivity's standard delegate (the real
|
|
471
|
+
// last activity). The surface itself is stopped explicitly in
|
|
472
|
+
// VRActivity.onDestroy() below.
|
|
473
|
+
override fun onDestroy() {
|
|
474
|
+
// intentionally no-op — see comment above
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
override fun onResume() {
|
|
479
|
+
super.onResume() // delegate.onResume() -> reactHost.onHostResume(this)
|
|
480
|
+
expectingForeignPause = true
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// onPause not overridden: the default delegate forwards to
|
|
484
|
+
// reactHost.onHostPause(this) while currentActivity matches us, which is
|
|
485
|
+
// what we want.
|
|
486
|
+
|
|
487
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
488
|
+
super.onCreate(savedInstanceState)
|
|
489
|
+
val callbacks = object : Application.ActivityLifecycleCallbacks {
|
|
490
|
+
override fun onActivityResumed(other: Activity) {
|
|
491
|
+
if (other !== this@VRActivity && !isFinishing && !isDestroyed) {
|
|
492
|
+
finish()
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
override fun onActivityPaused(other: Activity) {
|
|
496
|
+
if (other === this@VRActivity || isFinishing || isDestroyed) return
|
|
497
|
+
if (!expectingForeignPause) return
|
|
498
|
+
expectingForeignPause = false
|
|
499
|
+
// MainActivity.onPause was dispatched after our onResume (the
|
|
500
|
+
// NEW_TASK race). The standard delegate already called
|
|
501
|
+
// onHostPause(MainActivity), demoting the host to PAUSED and
|
|
502
|
+
// disabling devSupport / clearing JavaTimerManager's frame
|
|
503
|
+
// callback. Re-promote so VR keeps timers + Fast Refresh.
|
|
504
|
+
mainHandler.post {
|
|
505
|
+
if (isFinishing || isDestroyed) return@post
|
|
506
|
+
(reactHost as? ReactHostImpl)?.onHostResume(this@VRActivity)
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
override fun onActivityCreated(a: Activity, b: Bundle?) {}
|
|
510
|
+
override fun onActivityStarted(a: Activity) {}
|
|
511
|
+
override fun onActivityStopped(a: Activity) {}
|
|
512
|
+
override fun onActivitySaveInstanceState(a: Activity, b: Bundle) {}
|
|
513
|
+
override fun onActivityDestroyed(a: Activity) {}
|
|
514
|
+
}
|
|
515
|
+
application.registerActivityLifecycleCallbacks(callbacks)
|
|
516
|
+
lifecycleCallbacks = callbacks
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
override fun onDestroy() {
|
|
520
|
+
// Stop the React surface attached to this VRActivity so its component
|
|
521
|
+
// tree unmounts cleanly. In bridgeless arch this calls
|
|
522
|
+
// reactSurface.stop() + reactSurface = null, leaving the shared
|
|
523
|
+
// ReactHost intact for MainActivity. Without this the React tree from
|
|
524
|
+
// each VR session piles up across re-entries and stale VRTComponents
|
|
525
|
+
// intercept hit-tested viewTags with dead ReactContexts, breaking
|
|
526
|
+
// onClick / onHover until you press dozens of times.
|
|
527
|
+
try {
|
|
528
|
+
reactDelegate?.unloadApp()
|
|
529
|
+
} catch (t: Throwable) {
|
|
530
|
+
android.util.Log.w("VRActivity", "reactDelegate.unloadApp() failed", t)
|
|
531
|
+
}
|
|
532
|
+
lifecycleCallbacks?.let { application.unregisterActivityLifecycleCallbacks(it) }
|
|
533
|
+
lifecycleCallbacks = null
|
|
534
|
+
mainHandler.removeCallbacksAndMessages(null)
|
|
535
|
+
super.onDestroy()
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
`;
|
|
539
|
+
fs_1.default.writeFileSync(activityPath, kotlinContent, "utf-8");
|
|
540
|
+
}
|
|
541
|
+
return config;
|
|
542
|
+
},
|
|
543
|
+
]);
|
|
544
|
+
// 2. Add VRActivity to AndroidManifest
|
|
545
|
+
config = (0, config_plugins_1.withAndroidManifest)(config, async (config) => {
|
|
546
|
+
const app = config.modResults.manifest.application?.[0];
|
|
547
|
+
if (!app)
|
|
548
|
+
return config;
|
|
549
|
+
if (!app.activity)
|
|
550
|
+
app.activity = [];
|
|
551
|
+
const alreadyAdded = app.activity.some((a) => a.$?.["android:name"] === ".VRActivity");
|
|
552
|
+
if (!alreadyAdded) {
|
|
553
|
+
app.activity.push({
|
|
554
|
+
$: {
|
|
555
|
+
"android:name": ".VRActivity",
|
|
556
|
+
"android:screenOrientation": "landscape",
|
|
557
|
+
"android:exported": "false",
|
|
558
|
+
"android:configChanges": "keyboard|keyboardHidden|orientation|screenSize|uiMode",
|
|
559
|
+
"android:launchMode": "singleTask",
|
|
560
|
+
},
|
|
561
|
+
"intent-filter": [
|
|
562
|
+
{
|
|
563
|
+
action: [{ $: { "android:name": "android.intent.action.MAIN" } }],
|
|
564
|
+
category: [
|
|
565
|
+
{ $: { "android:name": "com.oculus.intent.category.VR" } },
|
|
566
|
+
],
|
|
567
|
+
},
|
|
568
|
+
],
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
// Inject com.oculus.app_id into <application> for Meta Quest App Name
|
|
572
|
+
const questAppId = props?.android?.questAppId;
|
|
573
|
+
if (questAppId) {
|
|
574
|
+
if (!app["meta-data"])
|
|
575
|
+
app["meta-data"] = [];
|
|
576
|
+
const alreadyHasAppId = app["meta-data"].some((m) => m.$?.["android:name"] === "com.oculus.app_id");
|
|
577
|
+
if (!alreadyHasAppId) {
|
|
578
|
+
app["meta-data"].push({
|
|
579
|
+
$: {
|
|
580
|
+
"android:name": "com.oculus.app_id",
|
|
581
|
+
"android:value": questAppId,
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return config;
|
|
587
|
+
});
|
|
588
|
+
return config;
|
|
589
|
+
};
|
|
286
590
|
const withViroAndroid = (config, props) => {
|
|
287
|
-
|
|
288
|
-
withViroProjectBuildGradle(config);
|
|
289
|
-
withViroManifest(config);
|
|
290
|
-
withViroSettingsGradle(config);
|
|
291
|
-
withViroAppBuildGradle(config);
|
|
591
|
+
config = withBranchAndroid(config, props);
|
|
592
|
+
config = withViroProjectBuildGradle(config);
|
|
593
|
+
config = withViroManifest(config);
|
|
594
|
+
config = withViroSettingsGradle(config);
|
|
595
|
+
config = withViroAppBuildGradle(config);
|
|
596
|
+
config = withViroQuestActivity(config, props);
|
|
292
597
|
return config;
|
|
293
598
|
};
|
|
294
599
|
exports.withViroAndroid = withViroAndroid;
|
|
@@ -171,6 +171,7 @@ const withDefaultInfoPlist = (config, _props) => {
|
|
|
171
171
|
let googleCloudApiKey;
|
|
172
172
|
let rvApiKey;
|
|
173
173
|
let rvProjectId;
|
|
174
|
+
let rvEndpoint;
|
|
174
175
|
let cloudAnchorProvider;
|
|
175
176
|
let geospatialAnchorProvider;
|
|
176
177
|
let includeARCore;
|
|
@@ -190,6 +191,7 @@ const withDefaultInfoPlist = (config, _props) => {
|
|
|
190
191
|
googleCloudApiKey = pluginOptions.googleCloudApiKey;
|
|
191
192
|
rvApiKey = pluginOptions.rvApiKey;
|
|
192
193
|
rvProjectId = pluginOptions.rvProjectId;
|
|
194
|
+
rvEndpoint = pluginOptions.rvEndpoint;
|
|
193
195
|
// Resolve unified provider prop; old props override for backward compat.
|
|
194
196
|
// Default to "reactvision" only when rvApiKey is present (implies RV intent).
|
|
195
197
|
const defaultProvider2 = pluginOptions.rvApiKey ? "reactvision" : undefined;
|
|
@@ -224,6 +226,9 @@ const withDefaultInfoPlist = (config, _props) => {
|
|
|
224
226
|
if (rvProjectId) {
|
|
225
227
|
config.ios.infoPlist.RVProjectId = rvProjectId;
|
|
226
228
|
}
|
|
229
|
+
if (rvEndpoint) {
|
|
230
|
+
config.ios.infoPlist.RVEndpoint = rvEndpoint;
|
|
231
|
+
}
|
|
227
232
|
// Add location permissions for Geospatial API
|
|
228
233
|
if (geospatialAnchorProvider === "arcore" || geospatialAnchorProvider === "reactvision" || includeARCore === true) {
|
|
229
234
|
config.ios.infoPlist.NSLocationWhenInUseUsageDescription =
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* withViroVisionOS.ts
|
|
3
|
+
*
|
|
4
|
+
* Expo config plugin that adds a visionOS target to your app's Xcode project.
|
|
5
|
+
*
|
|
6
|
+
* What it does:
|
|
7
|
+
* 1. Writes the SwiftUI App entry point (ViroVisionApp.swift) into the target folder
|
|
8
|
+
* 2. Adds a visionOS pod target to the Podfile
|
|
9
|
+
* 3. Creates a visionOS Xcode target in the .pbxproj with correct SDK + build settings
|
|
10
|
+
*
|
|
11
|
+
* Usage in app.json:
|
|
12
|
+
* {
|
|
13
|
+
* "plugins": [
|
|
14
|
+
* ["@reactvision/react-viro", { ... }],
|
|
15
|
+
* "@reactvision/react-viro/plugins/withViroVisionOS"
|
|
16
|
+
* ]
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* After running `expo prebuild`, run `pod install` in ios/ then build the
|
|
20
|
+
* <AppName>Vision target in Xcode targeting the visionOS simulator.
|
|
21
|
+
*/
|
|
22
|
+
import { ConfigPlugin } from "@expo/config-plugins";
|
|
23
|
+
export declare const withViroVisionOS: ConfigPlugin;
|
|
24
|
+
export default withViroVisionOS;
|