Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swift India Conf 2019: Effective Migration to Mac Catalyst

Swift India Conf 2019: Effective Migration to Mac Catalyst

Speaker: Noah Gilmore, iOS Engineer, PlanGrid

Twitter: https://twitter.com/noahsark769/

Bio: Noah Gilmore is a San Francisco transplant and web developer turned iOS developer. By day he works at PlanGrid on their app which manages blueprint data and construction workflow on iPads, and by night he codes side projects like Trestle. He's passionate about writing clean, simple software that's easy to use and easy to test. When he's not coding, you can find him playing piano and retro video games.

Abstract: Starting in macOS Catalina, it’s possible to compile UIKit apps to run on macOS. This new environment can be confusing, since parts of UIKit work differently, and parts of AppKit are available to your iPad app! We’ll explore how to adapt your iPad app for Mac effectively and take a closer look into implementing macOS features like menu bars, toolbars, and window controls with UIKit.


Swift India

July 28, 2019


  1. Effective Migration to Mac Catalyst Noah Gilmore @noahsark769 Swift India,

    July 26th 2019
  2. @noahsark769 What is Catalyst? - Introduced at WWDC 2019 -

    Allows a UIKit codebase to compile into an AppKit Mac app
  3. @noahsark769 What is Catalyst? UIKit UIView, UIWindow, UIViewController, ... AppKit

    NSView, NSWindow, NSViewController, ...
  4. @noahsark769 What is Catalyst? Catalyst UIKit UIView, UIWindow, UIViewController, ...

    AppKit NSView, NSWindow, NSViewController, ...
  5. @noahsark769 What is Catalyst? - “Mac Catalyst”, “UIKitForMac”, “iPad Apps

    for Mac” (formerly “Marzipan”) refer to the same thing
  6. @noahsark769 PlanGrid

  7. @noahsark769 CIFilter.io

  8. @noahsark769 https://github.com/noahsark769/CatalystPlayground

  9. @noahsark769 Agenda - Beyond the checkbox - Mac patterns in

    UIKit - AppKit bundles (and demo) - Should I use Catalyst?
  10. Beyond the Checkbox

  11. @noahsark769 Check the checkbox

  12. @noahsark769 Things that might not work - UIWebView - CoreTelephony

    (used by analytics libraries) - Your cross-platform static library (.a) - Things that don’t make sense: ARKit, etc @noahsark769
  13. @noahsark769 Conditional compilation #if targetEnvironment(macCatalyst) import AppKit #endif

  14. @noahsark769 Conditional compilation This will cause a link error! #if

    canImport(UIKit) print(UIWebView.self) #endif
  15. @noahsark769 Conditional compilation WARNING: The second statement will be printed!

    #if os(macOS) print("Mac") #else print("iOS") #endif
  16. @noahsark769 Dependencies - Submit pull requests or support tickets for

    dependencies - Request distribution of static libraries in .xcframework format
  17. Mac Patterns in UIKit

  18. @noahsark769 CatalystPlayground - Demonstrates all of these patterns - https://github.com/noahsark769/CatalystPlayground

  19. @noahsark769 AppKit #if targetEnvironment(macCatalyst) import AppKit #endif

  20. @noahsark769 Windows

  21. @noahsark769 Windows - Use UISceneSession APIs in the same way

    as on iOS
  22. @noahsark769 Windows UIApplication.shared.requestSceneSessionActivation( nil, userActivity: nil, options: nil, errorHandler: nil

  23. @noahsark769 Windows guard let containingScene = self.view.window?.windowScene else { return

    } UIApplication.shared.requestSceneSessionDestruction( containingScene.session, options: nil, errorHandler: nil )
  24. @noahsark769 Windows - New windows assume system-assigned size and position

    - When the user drags, windows resize and update your autolayout constraints - No way to update the size or position of the window with code
  25. @noahsark769 App Menus

  26. @noahsark769 App Menus - Use UIMenuBuilder (on your app delegate)

  27. @noahsark769 App Menus override func buildMenu(with builder: UIMenuBuilder) { super.buildMenu(with:

    builder) builder.insertChild(UIMenu( __title: "Jump", image: nil, identifier: UIMenu.Identifier(rawValue: "jump"), options: [], children: [ // ... ] ), atEndOfMenu: .view) }
  28. @noahsark769 App Menus - Use a child UIKeyCommand for keyboard

    shortcut enabled items - Can also be used for non-menu keyCommands on your first responder let command = UIKeyCommand( input: "J", modifierFlags: [.command], action: #selector(self.jumpSelected(_:)) ) command.title = "Jump to Windows"
  29. @noahsark769 App Menus - Use UICommand for items without shortcuts

    let noShortcutCommand = UICommand( __title: "No shortcut", image: nil, action: #selector(self.noShortcutSelected), propertyList: nil )
  30. @noahsark769 App Menus - Catalyst automatically provides a menu based

    on the app’s configuration
  31. @noahsark769 Touch Bar extension TouchBarViewController: NSTouchBarProvider { var touchBar: NSTouchBar?

    { let bar = NSTouchBar() let identifier = NSTouchBarItem.Identifier(rawValue: "clickme") bar.defaultItemIdentifiers = [identifier] bar.templateItems = [ NSButtonTouchBarItem( identifier: identifier, title: "button", target: self, action: #selector(didTapClickMe(_:)) ) ] return bar } }
  32. @noahsark769 Touch Bar - All system default touch bar items

    available (color picker, slider, etc) - No NSCustomTouchBarItem
  33. @noahsark769 Tool Bar

  34. @noahsark769 Tool Bar - UIWindowScene has a UITitleBar which you

    can give an NSToolbar - Initialize an NSToolbarItem with a UIBarButtonItem - Custom views (and images) are not supported - Import <UIKit/NSToolbar+UIKitAdditions.h>
  35. @noahsark769 Tool Bar #if targetEnvironment(macCatalyst) if let titlebar = scene.titlebar

    { let toolbar = NSToolbar(identifier: "toolbar") toolbar.delegate = self titlebar.toolbar = toolbar titlebar.titleVisibility = .hidden } #endif
  36. extension SceneDelegate: NSToolbarDelegate { var identifiers: [NSToolbarItem.Identifier] { return [

    NSToolbarItem.Identifier(rawValue: "test"), .flexibleSpace, NSToolbarItem.Identifier(rawValue: "other") ] } func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { return self.identifiers } func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { return self.identifiers } // ... }
  37. @noahsark769 Tool Bar func toolbar( _ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier:

    NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool ) -> NSToolbarItem? { switch itemIdentifier.rawValue { case "test": let item = NSToolbarItem( itemIdentifier: itemIdentifier, barButtonItem: UIBarButtonItem( barButtonSystemItem: .add, target: self, action: #selector(didTapAddButton) ) ) return item default: return nil } }
  38. @noahsark769 Other AppKit components - Drag and Drop - UIDragInteraction,

    UIDropInteraction, beta 4 issues - Context Menus - UIContextMenuInteraction - File access - UIDocumentPickerViewController
  39. @noahsark769 How much of AppKit can I import? - Pretty

    much just NSTouchBar and NSToolbar - No direct access to NSWindow - No complicated views like NSTableView
  40. AppKit Bundles

  41. @noahsark769 AppKit Bundles - Write an AppKit Plug-In bundle and

    import using NSBundle - Plug-In bundles have access to the full AppKit runtime (NSApplication, NSWindow, etc) - Present panels, control windows, etc - Communicate with UIKit via NotificationCenter or Obj-C interface - No mixing UIKit and AppKit view hierarchies
  42. @noahsark769 Demo time https://github.com/noahsark769/SwiftIndiaDemo

  43. Should I use Catalyst?

  44. New macOS app without iPad equivalent Consider using SwiftUI or

    AppKit instead ❌ @noahsark769
  45. New, cross-platform app Consider using SwiftUI with shared Views ❌

  46. Don’t want to learn AppKit, like me AppKit is more

    approachable than ever ❌ @noahsark769
  47. ✅ Significant existing UIKit iPad app ✅ Small number of

    external dependencies ✅ Little need for macOS-specific UI ✅ Experimental feature support @noahsark769
  48. Further reading - WWDC 2019 #205: Introducing iPad Apps for

    Mac - WWDC 2019 #235: Taking iPad Apps for Mac to the Next Level - WWDC 2019 #212: Introducing Multiple Windows on iPad - Ultimate Catalyst Guide - Beyond the Checkbox with Catalyst and AppKit @noahsark769
  49. Thank you