Today's weekly build of Elements .2415 includes support for building UIKit for Mac applications with Oxygene, C#, Swift and Java.

In case you have been living under a rock the past year or so, UIKit for Mac (also referred to as Marzipan, or Project Catalyst) is Apple's effort to allow for more easy porting of iPad and iPhone apps to the Mac, officially announced at WWDC2019 earlier this month.

As you all know Elements already makes it easy to share a lot of non-visual code — not just between Mac and iOS, but also other platforms, such as Android or Windows. But the UI level is still very different between Mac (using AppKit) and iOS (using the newer UIKit). With UIKit for Mac, developers can use the same UI framework for both Apple platforms.

Of course, building a great Mac app will always require a little extra effort and attention to detail for the platform, but getting an iPhone or iPad app running on the Mac is now basically just a single click away:

In Project Settings, you'll see a new "Support UIKit for Mac" option for your iOS app. Simply set it to YES, and you're done. It's really that easy.

Once you toggle the option, you will see that you can now Select "Mac" as run target up in the CrossBox device picker. Select it, press ⌘R, and your app will build and run locally (or via SSH, if you're on Windows) on your the Mac.

You can build and work on UIKit for Mac apps on any version of macOS (different than Xcode, which requires you to work on Catalina!), but of course to run them, you will need to be on macOS 10.15 Catalina (the first two betas have been pretty stable for me so far, so don't be afraid ;).

Build Destinations

UIKit for Mac applications are not a separate project from your iOS app; instead they add a new — what we call — "Build Destination" to your project. All iOS apps support two build destinations by default: "Device" and "Simulator". Which version gets built is determined by what target device you have selected (and a rebuild will always build both). Changing the device toggles between two separate sets of framework references ("iOS 13.0" or "iOS Simulator 13.0") influences other build behavior (such as whether to code-sign your app, or to create a .ipa), what CPU architecture(s) to build, and where to put the final output.

UIKit for Mac simply adds a third build destination that uses its own set of frameworks ("UIKitForMac 13.o") and rules for how to package your app. When you have "Mac" selected as your target device, that's the build destination that will be used, and rebuilding an app with the option enabled will always build all three.

Extra Settings

UIKit for Mac exposes some additional settings you might want to tweak, which will show in Project Settings once you toggle the master switch.

  • "Application Icon for Mac" lets you specify a custom .icns file to provide a beautiful 512-point application icon, just as you would for a traditional AppKit-based Mac app.
  • "Bundle Identifier for Mac" lets you override the bundle identifier (which needs to be different than your iOS app, if you want to ship to the Mac App Store). If you leave this untouched, Elements will take care of making it unique for you.
  • "Entitlements File for Mac" lets you specify a separate .entitlements file for the Mac version of your app, which might be needed because macOS and iOS use different entitlements (e.g. sandboxed Mac apps need an entitlement to enable network access, while iOS apps do not).

You will need a Code Signing Certificate set up for your UIKit for Mac app, just as you do when building for an iOS device (this is different than building for the Simulator, where you can get away without). In my testing so far, it seems you can use the same certificates that you use for iOS; you can also use Developer ID, if you do not want to ship to the Mac App Store.

What About AppKit?

Can you mix AppKit and UIKit in the same app? Sure thing! Just add a reference to the AppKit framework, add, say, a Window Controller and a .NIB, and off you go:

Xcode won't let you do this!

Of course once you add AppKit, you're entering Mac-only territory, and that part of your app cannot be shared with iOS, where AppKit does not exist. You can use conditional compilation such as #if UIKITFORMAC or if defined("UIKITFORMAC") { ... } to handle these Mac-specific parts of your app.

Check it out now

Support for UIKit for Mac is in today's build, .2415, which is on the Stable channel and thus available for everybody, including as free trial and for users of the free Swift-only edition. Grab your copy now and get your iOS ready for the Mac!

Make sure to grab the latest Xcode 11 beta from Apple, and also check out Apple's guides and documentation for UIKIt for Mac, here.