iPadOS Multiple Window Support

iPadOS 13 was launched during WWDC 2019. Finally, the iPad got a separate OS.
Introduction of Multiple Window Support in iPadOS is a game-changing move. It allows us to open multiple instances of an application at the same time.

This awesome feature is incredibly useful when it comes to viewing multiple messages, emails or comparing notes and map routes. I believe Multiple Window Support would give rise to interesting multiplayer games really soon!

Our Goal For Today

  • Knowing how the application lifecycle changes for Multiple Window Support
  • A bird’s eye view at UIScene API
  • Implementing Multiple Window Support in two different ways:
    • By User Input
    • By Drag And Drop

Without wasting any more time, let’s get started.

Enabling Multi-Window Support

It’s easy, just jump into the Project Navigator | General Settings and ensure that Support Multiple Window checkbox is enabled.

ios-multiple-window-support-enable

Once this is done, Multiple Window Support boolean property is set in the info.plist. Before we dig deep into the API changes and implementation let’s address the elephant in the room:

Multiple Window Support is NOT Split Screen Support.
Split Screen Support was introduced in iOS 9 to allow viewing different apps in one window. Multiple Window Support allows viewing multiple instances of one app.

splitscreen-vs-multiple-window-ipados13

Changes In AppDelegate And App Lifecycle

Multi-Window Support has brought in major changes to the AppDelegate class. It is much lighter now. All the heavy weight lifting part is done by the SceneDelegate class. If you peek into the AppDelegate in any iOS 13 Xcode Project, you’ll see it has very few methods.

UIApplicationDelegate is not notified when the application goes and comes from the background in iOS 13 and above.
A newly introduced protocol UIWindowSceneDelegate handles the notifications across multiple windows of an application.

The following properties of the UIApplication class are now deprecated:

  • statusBarStyle
  • statusBarHidden
  • statusBarOrientation
  • open(_:options:completionHandler:)
  • keyWindows

Thanks to Multi-Window Support, now windows are scenes! So everything you see in the App Switcher is a separate scene starting iPadOS 13.

UIScene API: A Bird’s eye view

Multiple Window Support uses UIScene API under the hood. The two most essential classes of this API are:

  • UIWindowScene – This is responsible for managing multiple windows of an application.
  • UISceneSession – This represents a persisted state of the scene. Multiple UIScenes store there specific information such as role, user info with the Scene Session.

NSUserActivity is used to capture the state of a scene. This state is used to restore a previously used scene or create a new scene with the current viewing content.

If the above information didn’t make sense to you, don’t freak out! A hands on implementation in the next section will definitely make things clearer.

Implementation

We’ll be creating a simple iPadOS Application that displays an image.
Let’s start by adding a button that creates a new scene/window of the application.

Creating A New Scene On User Click

The following code creates a new Scene on user input:

let activity = NSUserActivity(activityType: VCActivityType)
UIApplication.shared.requestSceneSessionActivation(nil, userActivity: activity, options: nil, errorHandler: nil)

requestSceneSessionActivation is responsible for activating an existing scene or creating a new scene!

Here’s a screengrab from the iPad Application.

ipados-multi-window-support-demo

This was straight. Now let’s hop onto the Drag And Drop mechanism and see what needs to be done there.

Creating a New Scene Using Drag And Drop

We’ll implement the Drag interaction on the ImageView.
For that, we need to conform to the UIDragInteractionDelegate protocol and set it’s iteraction on the UIImageView instance.

photo?.isUserInteractionEnabled = true
photo?.addInteraction(UIDragInteraction(delegate: self))

Implementing Drag Function

extension ViewController : UIDragInteractionDelegate{
    func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
        if let imageView = interaction.view as? UIImageView {
            guard let image = imageView.image else { return [] }
            let provider = NSItemProvider(object: image)
            
            
            let userActivity = NSUserActivity(activityType: VCActivityType)
            provider.registerObject(userActivity, visibility: .all)
            let item = UIDragItem(itemProvider: provider)
            
            
            print("here...")
            return [item]
        }
        
        return []
    }
}

Lastly, we need to add the activity type key in the info.plist file:

ipados-multi-window-nsuseractivity-types

Our iPad Application is now ready for multi-window support via dragging.

ipados-multi-window-drag-and-drop

We’ve set CIFilters on the images to compare the same image across different filters.

There’s more! In the next parts, we’ll deal with State Restoration and Syncing data across multiple windows in iPadOS.

The full source code of this tutorial is available in the Github Repository.

Leave a Reply

Your email address will not be published. Required fields are marked *