diff --git a/src/framework/xr/xr-manager.js b/src/framework/xr/xr-manager.js index 61b5fac1b37..70bfa1c5ed8 100644 --- a/src/framework/xr/xr-manager.js +++ b/src/framework/xr/xr-manager.js @@ -317,7 +317,7 @@ class XrManager extends EventHandler { // 2. Space class // 3. Controllers class - if (this._supported) { + if (this._supported && XrManager._allowsSpatialTracking()) { navigator.xr.addEventListener('devicechange', () => { this._deviceAvailabilityCheck(); }); @@ -325,6 +325,29 @@ class XrManager extends EventHandler { } } + /** + * The startup availability probe calls {@link navigator.xr.isSessionSupported}, which the + * browser blocks - logging a `xr-spatial-tracking is not allowed in this document` permissions + * policy violation - when the `xr-spatial-tracking` feature is disallowed for the document (for + * example when the app runs in an iframe without `allow="xr-spatial-tracking"`). Only skip the + * probe when the policy explicitly disallows the feature; when the Feature Policy API is + * unavailable (e.g. Safari / visionOS) we cannot tell, so proceed as before. + * + * @returns {boolean} - True if the probe should run. + * @private + */ + static _allowsSpatialTracking() { + const featurePolicy = platform.browser && document.featurePolicy; + if (featurePolicy?.allowsFeature) { + const allowed = featurePolicy.allowsFeature('xr-spatial-tracking'); + if (!allowed) { + Debug.warn('WebXR availability detection skipped: the "xr-spatial-tracking" feature is disallowed for this document. If XR is needed, add allow="xr-spatial-tracking" to the embedding iframe or send a matching Permissions-Policy header.'); + } + return allowed; + } + return true; + } + /** * Tests whether an immersive WebXR session of the given type can run on the specified graphics * backend. Unlike {@link XrManager#isAvailable}, this is a static method that can be called