Add iOS 9’s Quick Actions shortcut support in 15 minutes right now !

September 14, 2015

Apple introduced 3D touch (/force touch for iOS) functionality in iOS 9. API is divided into 3 parts. Quick actions, Peek and Pop, Pressure Sensitivity. This functionality will be available in iOS 9 at launch. Meaning you can already submit apps with support for it right now. I will only delve into Quick Action support which is most straight forward and no brainer. With a bit of luck it can all be done in 15 min. Let me however start by disclaimer, that at the time of writing of this article I have no way of testing any sample code as neither simulator in Xcode 7 nor 7.1 beta support 3D touch simulation and iPhone 6s is still over a week away. I will update this post as soon as I’m able to actually test it. If you’d like to hear about update, you can follow me here @stringCode. Without further a due, let’s dive in !

Update : I have now been able to test Quick actions using @conradev hack. You can find out how here. I’m happy to report that everything seems to work exactly as expected ! Thanks to @aligatr for making me aware of it.

Quick Actions

Quick Actions are basically home screen icon shortcuts. There are two ways they can be supported. Static or dynamic. iOS 9 displays up to four Home screen quick actions for your app. Within this limit, the system shows your static quick actions first, starting at the topmost position in the menu. If your static items do not exhaust the limit and you have also defined dynamic quick actions, then one or more of your dynamic quick actions is displayed.

Static Actions are defined in Info.plist through UIApplicationShortcutItems array of dictionaries. You can provide values for following keys in each dictionary :

  • UIApplicationShortcutItemType (required) – required unique string identifier for shortcut item
  • UIApplicationShortcutItemTitle (required) – shortcut item title string that appears in UI
  • UIApplicationShortcutItemSubtitle (optional) – shortcut item subtitle string that appears in UI
  • UIApplicationShortcutItemIconType (optional) – system provided icon. Full list of supported values can be found here.
  • UIApplicationShortcutItemIconFile (optional) – custom icon image name in assets catalog (if provided, UIApplicationShortcutItemIconType is ignored). Image should be 35×35 points single colour temple image. Full description of all supported keys can be found here.

With shortcut items defined in Info.plist we need to respond to them. There is app delegate method application(_:performActionForShortcutItem:completionHandler:) that gets called when user taps on quick action. There is a completions block that you have to call once you performed shortcut action. As I understand it, this is where you would adjust your view controller hierarchy to respond to action and then call completion block. It’s not that simple though.

There is a dance that needs to be done depending whether app is being launched or only coming to foreground. You have to check in application:didFinishLaunchingWithOptions: or application:willFinishLaunchingWithOptions: whether you are being launched from shortcut. Do this by checking for UIApplicationLaunchOptionsShortcutItemKey in launchOptions dictionary. If you are indeed getting launched from shortcut, you are to setup appropriate view controller hierarchy right there and return false from application:willFinishLaunchingWithOptions:. This will prevent application(_:performActionForShortcutItem:completionHandler:) from getting called.

Here are sample code of how Im handling it. Whole sample app can be dowloaded github sample code.


import UIKit


@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    enum ShortcutType: String {
        case Torquiose = "reverse.domain.turquoise"
        case Red = "reverse.domain.red"
    }
    
    var window: UIWindow?

    static let applicationShortcutUserInfoIconKey = "applicationShortcutUserInfoIconKey"

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        var launchedFromShortCut = false
        //Check for ShortCutItem
        if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsShortcutItemKey] as? UIApplicationShortcutItem {
            launchedFromShortCut = true
            handleShortCutItem(shortcutItem)
        }
        
        //Return false incase application was lanched from shorcut to prevent
        //application(_:performActionForShortcutItem:completionHandler:) from being called
        return !launchedFromShortCut
    }

    func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: Bool -> Void) {
        let handledShortCutItem = handleShortCutItem(shortcutItem)
        completionHandler(handledShortCutItem)
    }
    
    func handleShortCutItem(shortcutItem: UIApplicationShortcutItem) -> Bool {
        var handled = false
        //Get type string from shortcutItem
        if let shortcutType = ShortcutType.init(rawValue: shortcutItem.type) {
            //Get root navigation viewcontroller and its first controller
            let rootNavigationViewController = window!.rootViewController as? UINavigationController
            let rootViewController = rootNavigationViewController?.viewControllers.first as UIViewController?
            //Pop to root view controller so that approperiete segue can be performed
            rootNavigationViewController?.popToRootViewControllerAnimated(false)
            
            switch shortcutType {
            case .Torquiose:
                rootViewController?.performSegueWithIdentifier(toTurquoiseSeque, sender: nil)
                handled = true
            case.Red:
                rootViewController?.performSegueWithIdentifier(toRedSeque, sender: nil)
                handled = true
            }
        }
        return handled
    }
}

Dynamic actions can be created using UIApplicationShortcutItem and UIMutableApplicationShortcutItem classes. Simply create objects and add them UIApplication’s shortcutItems property. There is quite a bit of potentially tricky additional complexity when it come to managing these dynamic shortcuts. I will not delve into it here.

And that is all there is to it. Here are some useful related links and source material for this post :

And finally let’s hear Johny tell us about how insanely great 3D touch really is !

#Blog posts, #Coding, #iOS Development, #Swift