Home Screen Quick Actions for iOS: Getting Started
Learn how to integrate Static and Dynamic Home Screen Quick Actions into your SwiftUI iOS app. By Felipe Laso-Marsetti.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Home Screen Quick Actions for iOS: Getting Started
20 mins
Quick actions are a great way to provide your users fast access to your app’s common functionality within the home screen. iOS 13 introduced the concept of quick actions, where a user can touch and hold an app icon to display a set of shortcuts or actions to perform right from the home screen.
All apps have quick actions to edit the home screen or delete the app by default:
Developers can also provide their own quick actions to provide users with powerful shortcuts to common app functionality. The iOS Camera app has actions to take different types of photos or to record a video. A shopping app might let you jump directly to your orders or wishlist, and a messaging app might show your favorite contacts so you can easily access them.
I’m sure you can think of ways that quick actions would benefit your users. In this tutorial you’re going to learn about:
- Static quick actions, which are always available for your app.
- Dynamic quick actions, which your app can define at runtime.
- How to support both types of quick action in the sample project, a note-taking app called Note Buddy.
Getting Started
Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.
Note Buddy is a note-taking app with some basic functionality:
- Add, edit or delete notes with a title and body.
- Favorite a note.
- Store your notes between launches.
- Auto-sort notes by last modified date.
Open the project, then build and run. You’ll see this note page:
To power Note Buddy’s functionality, you’ll find the Note
model and its associated NoteStore
class in the Models group.
Moving on to SwiftUI, in the Views group, you have:
-
NoteList
: Shows a list of all your notes sorted by last modified date. -
NoteRow
: The view for a note row within the note list. It shows the note’s title, body and whether the user marked it as a favorite. -
EditNote
: An editor for modifying your note’s title, body or changing the favorite status. -
NavigationLink+Value
: A helper extension to make programmatic navigation a little easier when you have an associated data model to push.
Finally, AppMain
describes your app with a reference to the NoteStore
and a body which sets up the NoteList
view within a WindowGroup
and correctly injects the appropriate environment values.
Before you dive in to coding, it’s time to take a closer look at what the two types of quick actions are, and how they work.
Static vs. Dynamic Quick Actions
There are two types of quick actions available to you: static and dynamic.
You use static actions for actions that never change in your app, like the Mail app’s New Message action.
Use dynamic actions if your actions might change under certain conditions or depend on specific data or state. For example, the Messages app will add quick actions for all of your pinned conversations.
In both cases, you add code to handle a specific action that gets triggered. Since adding static quick actions is quicker, you’ll start with those.
Creating Static Quick Actions
Static quick actions are a great way to let your users create a new note.
First, add model code to assist you in handling a triggered action. Right-click the Models group and then click New File… ▸ Swift File. Name your new file Action and click Create.
Replace the contents of the file with:
import UIKit
// 1
enum ActionType: String {
case newNote = "NewNote"
}
// 2
enum Action: Equatable {
case newNote
// 3
init?(shortcutItem: UIApplicationShortcutItem) {
// 4
guard let type = ActionType(rawValue: shortcutItem.type) else {
return nil
}
// 5
switch type {
case .newNote:
self = .newNote
}
}
}
// 6
class ActionService: ObservableObject {
static let shared = ActionService()
// 7
@Published var action: Action?
}
A lot is going on. Here’s what you added:
- You create an enum called
ActionType
backed by aString
. You’ll use the string values later to help identify different types of action your app will perform. ThenewNote
case will identify the action for creating a New Note. - You create another enum called
Action
that looks similar, but is justEquatable
. This might look a little repetitive, but it’ll make sense when you add other actions later on. - Then you create a failable initializer that accepts an instance of
UIApplicationShortcutItem
. The system uses this type to describe different quick actions. - Here, you ensure that you’re creating an
Action
for a knownActionType
, otherwise you returnnil
. - Switch on the different possible
ActionType
values known to your app. You can then use the information available to describe the correctAction
. - Define an
ObservableObject
class you can later pass into the SwiftUI environment as well as provide a singleton accessor for later when you work with UIKit code. - Define a
@Published
property that can represent an action your app should perform.
The aim of the Action concept is for you to model quick actions your app supports and work with them safely when mapping between UIApplicationShortcutItem
.
Now, open AppMain.swift. Above noteStore
, add a new property for ActionService
:
private let actionService = ActionService.shared
Then update the body
implementation to ensure that the service is injected into the view hierarchy and that NoteList
can access it:
var body: some Scene {
WindowGroup {
NoteList()
.environmentObject(actionService)
.environmentObject(noteStore)
.environment(\.managedObjectContext, noteStore.container.viewContext)
}
}
ActionService
is available in the SwiftUI environment, and it’s time to use it. Open NoteList.swift in the Views group and add the following properties under noteStore
:
@EnvironmentObject var actionService: ActionService
@Environment(\.scenePhase) var scenePhase
Not only are you accessing the ActionService
class, you’ll also need access to the ScenePhase
, which is a property that notifies you when your app becomes active and when it enters the background.
At the bottom of the view, add the following method:
func performActionIfNeeded() {
// 1
guard let action = actionService.action else { return }
// 2
switch action {
case .newNote:
createNewNote()
}
// 3
actionService.action = nil
}
This method does three things:
- Checks if there’s an action in the
ActionService
. - Switches on the type of action and invokes the
createNewNote()
action forAction.newNote
. - Removes the action from the
ActionService
since it was performed.
You need to trigger this code whenever your app becomes active. You’ll use the onChange(of:perform:)
view modifier with the scenePhase
property that you added earlier.
Add the following code after the closing brace of the toolbar
modifier:
// 1
.onChange(of: scenePhase) { newValue in
// 2
switch newValue {
case .active:
performActionIfNeeded()
// 3
default:
break
}
}
Here, the code:
- Adds a modifier to the
List
that will fire its closure whenever thescenePhase
changes. - Using the argument provided, it switches on the value. If it’s
.active
, it’ll call your newperformActionIfNeeded()
method. - Since you don’t care about the other states, such as
.inactive
or.background
, it doesn’t do anything.