Streaming is available in most browsers,
and in the Developer app.
-
Evolve your document launch experience
Make your document-based app stand out, and bring its unique identity into focus with the new document launch experience. Learn how to leverage the new API to customize the first screen people see when they launch your app. Utilize the new system-provided design, and amend it with custom actions, delightful decorative views, and impressive animations.
Chapters
- 0:00 - Introduction
- 1:01 - Design overview
- 2:18 - Getting started with SwiftUI
- 3:13 - Getting started with UIKit
- 4:11 - Customization
- 6:42 - Adding template support to your app
Resources
- Building a document-based app with SwiftUI
- Customizing a document-based app’s launch experience
- Forum: UI Frameworks
Related Videos
WWDC23
WWDC20
-
Download
Hello! My name is Julia, and I am an engineer on the SwiftUI team.
In this video, I will talk about document-based applications, and new ways to make them stand out.
Showcase your document-based app and its unique identity by adopting the new, customizable launch experience. The new design gracefully guides people to creating their first document, providing great customization options and first-class support for document creation from templates.
Today, I will highlight some of the key features of the new document launch experience.
You’ll learn how to integrate the new design into your existing application.
And finally, I will introduce some of the new APIs that enable you to showcase your app’s uniqueness.
Let's get started with an overview of the design.
A great example of an app that has adopted the new launch experience is Playgrounds for iPadOS. Let me take you through the features and show how Playgrounds used them for this design.
Meet Byte, a character from Swift Playgrounds.
It guides and encourages developers as they learn Swift! Byte, along with other decorative views in front of and behind the title view are foreground and background accessories.
They allow you to bring elements unique to your app into the launch experience. The app’s name is displayed front and center.
Playgrounds opens a selection of coding tutorials when the primary button is tapped. On tap of the secondary button, Playgrounds creates a new app and opens the editor. The browser is configured to display documents with file formats that are supported by the app. The background can be replaced with a plain color, a gradient, an image, or a custom view of your choosing. I love this new experience, and want to adopt it in one of my apps. And I have a great candidate! I have a storytelling app that I built for my niece, Yael. She loves composing stories, and I want to make her writing experience even better.
I have used a document group scene to specify the document providing closure and the view that displays the open document.
When compiled with the iOS 17 SDK, the writing app displays the system document browser on launch.
Now, if I recompile it with the iOS 18 SDK the app launches to the all-new design. The “Create Document" button in the center of the title view is displayed automatically because the app supports document creation. The same functionality is available to UIKit document-based applications. It is supported for apps with UIDocumentViewController set as the window's root view controller.
If your app uses UIDocumentViewController to display documents, it is likely presented from a UIDocumentBrowserViewController which is the root of the window’s view controller hierarchy.
You needed to specify the browser view controller’s delegate to present the document upon selection. The new launch experience already contains its own browser, so to enable the new design in your app simply replace the root with the UIDocumentViewController. For a detailed overview of UIDocumentViewController, be sure to check out the Build better document-based apps video from WWDC23. Let’s pause and recap.
So far, we have covered how to incorporate the new design into your app It’s a great start! Now, I would like to introduce new API that will enable you to further enhance your app’s launch experience.
My niece’s favorite color is pink. I think that a pink alien jungle image will be a great background for the Writing app launch experience.
To specify the background, in my SwiftUI app definition I declare DocumentGroupLaunchScene, new to iOS 18.
Next, I can change the title of the “Create Document” button by providing a NewDocumentButton with the title I like.
Now, I want to bring into the launch experience some elements that are specific to my app. Another thing that my niece likes, and is excited about, is robots.
Maybe I can inspire her to write her own stories about robots? I’ll add one to the design. I want to position the robot image along the leading edge of the title view and an alien flower along the trailing edge. To provide accessories, I'll use the accessory view builder parameter. Think of the accessory view as a canvas on which you put all the images and views, and position them relative to the scene bounds and the title view’s frame.
The accessory view builders provide a geometry parameter, which contains the frame of the scene, and of the title view.
Lay out accessories using modifiers like position() or offset().
I want to add two accessory views, one along the leading edge of the title view, and another one, an alien flower, next to the trailing edge.
If your app uses UIDocumentViewController to display documents, make your customizations using the new launchOptions property.
viewDidLoad is a great place to configure your document view controller’s launch options.
Now you know how to add decorative views to your design. Images of the robot and an alien flower complete, liven up the view, and make it truly unique. Yael will be thrilled to see it! Many apps offer the ability to create documents from app-defined templates.
Templates act as a great starting point for documents that need to adhere to a consistent format, layout, or style. The Playgrounds app on iPadOS offers a rich set of templates that guide developers on how to animate views, recognize gestures, and play sounds. The templates can be stored on disk, or downloaded from web, like in Playgrounds.
I know my niece would love to choose from a few templates, with some starting material for her stories. Let’s add the option to create a new document from a template now! For that, I need to add one more action button. I’ll title the button Choose a Template.
When the button is tapped, SwiftUI calls an async closure asking you to return a document created from a template.
If you want to return a document later, after presenting a template picker view, create a continuation in the closure and save it. Present a sheet or a full screen cover with your custom view to choose a template. You can pass the continuation to the TemplatePicker, and resume it from there. After a user chooses a template, the app creates a document with this template, and returns it to SwiftUI by calling the continuation. SwiftUI will create a new document by copying the given template. For UIKit apps, first define a UIDocument.CreationIntent to represent your document template.
Then, in your UIDocumentViewController subclass, assign the launch option's primary or secondary action to be a create document action with this intent. To handle requests for new documents, assign the delegate of the launch option's browser view controller. Finally, read the browser’s active document creation intent to determine which document to create.
And here it is. After adding a few lines of code, the app supports creating stories with predefined structure and plot type! You should build your template picker with a custom design that suits your app best. The new launch experience is great, and I am so excited to see it incorporated into your apps.
Get started adopting it by recompiling your SwiftUI apps with the iOS 18 SDK.
Then, add a DocumentGroupLaunchScene to customize the launch experience, and showcase your app’s unique identity.
For UIKit apps, make UIDocumentViewController the root view controller and apply your customizations to the launch options. Every application has something special about it. Emphasize your app's uniqueness, and make it recognizable on first sight by adopting the new API. Thanks for watching this video! And tell your app’s story through the document launch experience!
-
-
2:38 - Document-based application
@main struct WritingApp: App { var body: some Scene { DocumentGroup(newDocument: { StoryDocument() }) { file in StoryView(document: $file.document) } } }
-
3:26 - Presenting a document from the browser in iOS 17
class DocumentViewController: UIDocumentViewController { ... } let documentViewController = DocumentViewController() let browserViewController = UIDocumentBrowserViewController( forOpening: [.plainText] ) window.rootViewController = browserViewController
-
3:38 - Presenting a document from the browser in iOS 17
class DocumentViewController: UIDocumentViewController { ... } let documentViewController = DocumentViewController() let browserViewController = UIDocumentBrowserViewController( forOpening: [.plainText] ) window.rootViewController = browserViewController browserViewController.delegate = self
-
3:43 - Presenting a document from the browser in iOS 17
class DocumentViewController: UIDocumentViewController { ... } let documentViewController = DocumentViewController() let browserViewController = UIDocumentBrowserViewController( forOpening: [.plainText] ) window.rootViewController = browserViewController browserViewController.delegate = self // MARK: UIDocumentBrowserViewControllerDelegate func documentBrowser( _ browser: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL] ) { guard let url = documentURLs.first else { return } documentViewController.document = StoryDocument(fileURL: url) browser.present(documentViewController, animated: true) }
-
3:56 - Presenting a document from the browser in iOS 18
class DocumentViewController: UIDocumentViewController { ... } let documentViewController = DocumentViewController() window.rootViewController = documentViewController
-
4:38 - Customize the document launch experience: background
DocumentGroup( newDocument: { StoryDocument() } ) { file in StoryView(document: $file.document) } DocumentGroupLaunchScene { ... } background: { Image(.pinkJungle) .resizable() .aspectRatio(contentMode: .fill) }
-
4:49 - Customize the document launch experience: new document button title
DocumentGroup( newDocument: { StoryDocument() } ) { file in StoryView(document: $file.document) } DocumentGroupLaunchScene { NewDocumentButton("Start Writing") } background: { Image(.pinkJungle) .resizable() .aspectRatio(contentMode: .fill) }
-
5:29 - Customize the document launch experience: accessory views
DocumentGroupLaunchScene { NewDocumentButton("Start Writing") } background: { Image(.pinkJungle) .resizable() .aspectRatio(contentMode: .fill) } overlayAccessoryView: { }
-
5:44 - Position accessory views
DocumentGroupLaunchScene { NewDocumentButton("Start Writing") } background: { Image(.pinkJungle) .resizable() .aspectRatio(contentMode: .fill) } overlayAccessoryView: { geometry in }
-
5:53 - Position accessory views
DocumentGroupLaunchScene { NewDocumentButton("Start Writing") } background: { ... } overlayAccessoryView: { geometry in ZStack { Image(.robot) .position( x: geometry.titleViewFrame.minX, y: geometry.titleViewFrame.minY ) Image(.plant) .position( x: geometry.titleViewFrame.maxX, y: geometry.titleViewFrame.maxY ) } }
-
6:11 - Customize the document launch experience in a UIKit app
class DocumentViewController: UIDocumentViewController { override func viewDidLoad() { super.viewDidLoad() // Update the background launchOptions.background.image = UIImage(resource: .pinkJungle) // Add foreground accessories launchOptions.foregroundAccessoryView = ForegroundAccessoryView() } }
-
7:31 - Create a document from a template: add a button
DocumentGroupLaunchScene { NewDocumentButton("Start Writing") NewDocumentButton("Choose a Template", for: StoryDocument.self) { } }
-
7:45 - Create a document from a template: return document later
@State private var creationContinuation: CheckedContinuation<StoryDocument?, any Error>? DocumentGroupLaunchScene { NewDocumentButton("Start Writing") NewDocumentButton("Choose a Template", for: StoryDocument.self) { try await withCheckedThrowingContinuation { continuation in self.creationContinuation = continuation } } }
-
7:56 - Create a document from a template: present a template picker
@State private var creationContinuation: CheckedContinuation<StoryDocument?, any Error>? @State private var isTemplatePickerPresented = false DocumentGroupLaunchScene { NewDocumentButton("Start Writing") NewDocumentButton("Choose a Template", for: StoryDocument.self) { try await withCheckedThrowingContinuation { continuation in self.creationContinuation = continuation self.isTemplatePickerPresented = true } } .sheet(isPresented: $isTemplatePickerPresented) { TemplatePicker(continuation: $creationContinuation } }
-
8:07 - Create a document from a template: template picker view
struct TemplatePicker: View { @Binding var creationContinuation: CheckedContinuation<StoryDocument?, any Error>? var body: some View { Button("Three Act Structure") { creationContinuation?.resume(returning: StoryDocument.threeActStructure()) creationContinuation = nil } } } extension StoryDocument { static func threeActStructure() -> Self { Self.init(...) } }
-
8:20 - Create a document from a template in UIKit
extension UIDocument.CreationIntent { static let template = UIDocument.CreationIntent("template") }
-
8:29 - Create a document from a template in UIKit
launchOptions.secondaryAction = LaunchOptions.createDocumentAction(with: .template) launchOptions.browserViewController.delegate = self // MARK: UIDocumentBrowserViewControllerDelegate func documentBrowser( _ browser: UIDocumentBrowserViewController, didRequestDocumentCreationWithHandler importHandler: @escaping (URL?, ImportMode) -> Void) { switch browser.activeDocumentCreationIntent { case .template: presentTemplatePicker(with: importHandler) default: let newDocumentURL = // ... importHandler(newDocumentURL, .copy) } }
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.