How to get real screen size in Mac Catalyst

I'm trying to port a game to macOS using Mac Catalyst. The game content doesn't dynamically resize and I'm trying to force a fixed 3:4 aspect ratio (like an iPad on portrait) at the start of the app, so I've added this to my AppDelegate class:

Code Block swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        #if targetEnvironment(macCatalyst)
/* some margin */
            let titleHeight: CGFloat = 34 * 4
            UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.forEach { windowScene in
                windowScene.titlebar?.titleVisibility = .hidden
                /* screen seems to always be 1920x1080 ??? */
                let height = windowScene.screen.nativeBounds.height - titleHeight
                let width = 3 * height / 4
                windowScene.sizeRestrictions?.minimumSize = CGSize(width: width, height: height)
                windowScene.sizeRestrictions?.maximumSize = CGSize(width: width, height: height)
            }
        #endif
}


That works in fixing the aspect, but the window looks small in a 15-inch MacBook Pro. nativeBounds is always 1920x1080, where the native resolution should be 1920x1200. UIScreen.main gives me 1920x1080 as well.

How can I get the real size of the screen?

Replies

The real screen sizes should now be reported to Catalyst apps in Big Sur. In Catalina, screen sizes are always reported as 1920x1080.
That's good news. Is there any workaround for Catalina?
I verified that nativeBounds and bounds work correctly in macOS 11.0.1. However, the size for sizeRestrictions does not like either of those values.

I have a 15-inch MacBook Pro, and for the default Retina display settings I get:

Code Block
nativeBounds: 3360x2100
bounds: 1680x1050
nativeScale: 2
scale: 2


However, if I set the height in sizeRestrictions fixed to 1050, the window is too short. If I set it to 2100, the window is approximately 30% taller than the screen and out of bounds.

I read in the UI Guidelines that Mac Catalyst apps get scaled 77% down, so a height for approximately 1400 seems to work here. Is there a way to get this scale programatically?

At the moment, I hard-coded 1.3 * screen.bounds.height in the code. I'm not 100% that is the correct value for sizeRestrictions though, or if it just happens to be right in this screen.
I finally found the answer:

"Optimize Interface for Mac"


Had the same problem: "maximizing" the UIWindow made it about 1/3 too small using UIScreen.main.bounds, and about 50% too large with UIScreen.main.nativeBounds.

Now, according to the UI guidelines, "you can choose the "Optimize Interface for Mac" setting, or Mac idiom, in Xcode. With the Mac idiom, your app takes on an even more Mac-like appearance and the system doesn’t scale your app’s layout."

This is in the same place where you enable macOS for the iOS/Catalyst app, under your project settings --> your project's target --> General --> Deployment Info.

Change "Scale Interface to Match iPad" to "Optimize Interface for Mac."

Here is how I changed my SceneDelegate --> scene willConnectTo: code:

Code Block swift
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
#if targetEnvironment(macCatalyst)
if let titlebar = windowScene.titlebar,
let sizes = windowScene.sizeRestrictions {
titlebar.titleVisibility = .hidden
titlebar.toolbar = nil
sizes.minimumSize = window.screen.bounds.size
sizes.maximumSize = window.screen.bounds.size
}
#endif
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}