Implementing Home Screen Quick Actions in Swift

With Twin Cities Pride 2017 fast approaching, we decided to make some changes to our accompanying iOS app, taking advantage of new iPhone features. The Pride app serves as a guide for the festival and parade, and is written in Swift 3.0. One newly implemented feature is known as Home Screen Quick Actions. This feature gives users with an iPhone 6s or 7 the ability to “3D touch” an app icon on their home screen to use app shortcuts. We used this feature to show users shortcuts to the parade, events, and map pages of the app.

A screenshot of an iPhone home screen, displaying the icon of the pride festival app, with three home screen quick actions directly above it. Everything else is blurred.
Home screen quick actions in the Twin Cities Pride Festival iOS app

Static Versus Dynamic Actions

There are two types of quick actions: static and dynamic. Static actions for an app are defined in a project’s Info.list file, and don’t change. Dynamic actions, meanwhile, are defined at runtime and can change (based on user actions, for example). Although only static actions were needed for our purposes, we decided to implement our actions as dynamic to avoid the “stringly” nature of defining them in the Info.list file. This also allows us to implement dynamic, changing quick actions in the future.

ShortcutManager

We created a Swift struct named ShortcutManager with just two methods:

func shortcutItems() -> [UIApplicationShortcutItem]
func handle(shortcutItem: UIApplicationShortcutItem) -> Bool

The first method provides an array of our three UIApplicationShortcutItem objects, and the second one is called from the app delegate when a user taps on a shortcut item. One UIApplicationShortcutItem corresponds to a quick action. The second method changes tabs based on the identifier of the shortcut item.

Because our app still supports iOS 8.0 and home screen quick actions are exclusive to iOS 9 and above, the ShortcutManager is declared to be available for iOS 9.0 and above only, by adding @available(iOS 9.0, *) on a line above the class declaration.

An enum is used for the shortcut identifiers:

enum ShortcutIdentifier: String {
  case openMap
  case openEvents
  case openParade
}

And a UIApplicationShortcutItem is defined in shortcutItems() as such:

UIApplicationShortcutItem(type: ShortcutIdentifier.openMap.rawValue,
                          localizedTitle: "Map",
                          localizedSubtitle: nil,
                          icon: UIApplicationShortcutIcon(templateImageName: "map_icon"),
                          userInfo: nil)

In the app delegate, the shortcut items are set like this:

if #available(iOS 9.0, *) {
  application.shortcutItems = ShortcutManager.sharedInstance.shortcutItems()
}

Similar to @available(iOS 9.0, *) earlier, using #available(iOS 9.0, *) causes the code in the conditional block to run only if the device has iOS 9.0 or above.

Handling shortcut item selections happens like this:

@available(iOS 9.0, *)
func application(_ application: UIApplication,
                 performActionFor shortcutItem: UIApplicationShortcutItem,
                 completionHandler: @escaping (Bool) -> Void) {
  completionHandler(ShortcutManager.sharedInstance.handle(shortcutItem: shortcutItem))
}

With quick actions defined dynamically, we can display a quick action to access the next upcoming event or provide directions to the festival based on user location in future versions of the app.

Twin Cities Pride 2017 is available for iOS and can be downloaded here.