Low hanging fruit for iOS apps running on visionOS

Tim Johnsen
3 min readFeb 4, 2024

--

visionOS is here! If you’re anything like me you might’ve not had much bandwidth to prep your iOS apps for it. In the past week of tinkering I’ve found a few small things iOS app developers can do to improve their apps when running on visionOS.

Detecting when you’re running on visionOS

When iOS apps are running on Apple Silicon Macs there’s a handy API you can check: isiOSAppOnMac. Unfortunately there’s no equivalent official API for iOS apps to detect when they’re running on visionOS. The good news is that I’ve found a public class that’s only available when running on visionOS that you can check for the availability of. If this class exists it means you’re running on visionOS.

BOOL TJIsOnVisionOSDevice(void)
{
static BOOL isOnVisionOSDevice = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
isOnVisionOSDevice = (NSClassFromString(@"UIWindowSceneGeometryPreferencesVision") != nil);
});
return isOnVisionOSDevice;
}

I’ve filed feedback with Apple to add an official API (FB13577576) and recommend you do the same if you’d find it useful. Be sure to explain why you’d find this API useful in the feedback!

Simple improvements you can make when running on visionOS

Bypass SFSafariViewController

SFSafariViewController shows an empty page and launches Safari.app when running on visionOS.

SFSafariViewController just shows an interstitial and launches Safari.app on visionOS

I’d recommend opening Safari directly and cutting out the ugly interstitial page when running on visionOS since it serves no purpose. Bonus: this is also the case for iOS apps running on macOS, I’d recommend using isiOSAppOnMac and opening Safari directly there too!

Custom dark mode setting

iOS apps running on visionOS seem to be forced into light mode with no way to enable dark mode. I don’t normally recommend having in-app settings for light/dark mode (just match the OS!), but since visionOS doesn’t give users the choice I’ve made an exception in Opener when running on visionOS. I’d recommend adding a toggle to opt into dark mode when visionOS is detected.

Opener’s visionOS-only custom dark mode toggle

If you’ve implemented light/dark mode using the APIs built into iOS switching your whole app is easy: just set your app’s window's overrideUserInterfaceStyle to UIUserInterfaceStyleDark when your custom setting is enabled.

// In your app delegate somewhere
- (void)darkModeSettingDidChange
{
if (/* your custom setting is enabled */) {
self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
} else {
self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleUnspecified;
}
}

Device model logging

At the very least it might be useful to know if anybody’s using your app on visionOS. If you have existing logging in place for device type, you can leverage the TJIsOnVisionOSDevice code above to accurately record that you’re running on a Vision Pro instead of a virtual iPad. Here’s an example of where I’m doing this in the logger I use for my apps.

Hope this was useful, happy coding!

--

--

Tim Johnsen

iOS developer at Retro.app. Previously Patreon, Instagram, Pinterest, Flipboard. Creator of Opener, Close-up, and other apps.