Add 3D Touch quick actions tutorial

3d touch quick actions tutorial

With the introduction of the iPhone 6S (plus), Apple added a pressure-sensitive layer to their screen.  This creates a bunch of new UX possibilities for creating apps.  It’s possible to do a hard press on an application icon and get shortcuts which take you to a specific point in your app.  For example, if you do a hard-press on the Photo’s app icon you can quickly search for an image, check the most recent images or see your favourites.  It’s also possible to make these quick actions dynamic, meaning that you can add and remove actions based on the state of your application.

3D touch quick actions
3D touch quick actions

In this tutorial I will show you how you can add these quick actions to your application icon.

Define action in Info.plist

The different options which are visible when you press on your application icon are defined in your info.plist file.

First you need to create a new row in your plist and give it the key UIApplicationShortcutItems and set the type to Array. You can now add a dictionary for every quick action.

Select the row you’ve just created and add a new row to the array, set the type to Dictionary.

Within this dictionary you have to add rows with specific keys and values.  You can choose from the following options. The ones with a * in front of the name are required.

  • * UIApplicationShortcutItemType: an unique string you choose to identify inside of your app which action has to be triggered. For example be.thenerd.my-app.create-user
  • * UIApplicationShortcutItemTitle: the string the user sees.  If the string is too long, it will be wrapped on 2 lines if there is no subtitle set (see the next key). If a subtitle is set, the string will be truncated.
  • UIApplicationShortcutItemSubtitle: optional, string which is shown to the user just below the title.
  • UIApplicationShortcutItemIconType: optional, you can use a system-defined icon (the list of keys can be found here)
  • UIApplicationShortcutItemIconFileoptional, the name of the image file in your app bundle or assets catalog. The template files to create your custom icon file can be found here.
  • UIApplicationShortcutItemUserInfooptional, a dictionary with custom data you want to use.

This will give you the following result.

3D touch quick actions
App shorcut

Get notified on selection

Alright, so how do we get notified when the user selects a shortcut?  After selection the method application:performActionForShortcutItem:completionHandler gets called.  Implement this method in your AppDelegate file.

If you tap on the shortcut you’ll see that this message pops up in your console. But how do we know which shortcut has been tapped?

This method has 3 arguments:

  1. application: a reference to the shared UIApplication instance
  2. shortcutItem: a reference to the UIApplicationShortcutItem object
  3. completionHandler: a closure which gets executed when your quick action code completes.

Remember you have specified the UIApplicationShortcutItemType key? With that unique string you can check which action you have to run. To access this string, you just fetch the value of the type property from the shortcutItem argument.

It might be a good idea to create an enum with all possible values, so you don’t make any spelling mistakes!  I’ll create a method handleShortcut:shortcutItem in which you can check what type it is and return a boolean if the action succeeded or not.  You need this because the application:performActionForShortcutItem:completionHandler: method requires that you return a boolean via the completionHandler argument.

One more thing

There is one caveat … there is a difference between launching your application and going from an inactive state to an active state.

This means you are responsible to make sure that application:performActionForShortcutItem:completionHandler: is called conditionally if for example application:didFinishLaunchingWithOptions: has already handled the application shortcut.

So how can we do this?

We will use a boolean in application:didFinishLaunchingWithOptions: to check if we need to call application:performActionForShortcutItem:completionHandler:.

Now we’ll have to check if the UIApplicationLaunchOptionsShortcutItemKey is available in the launchOptions dictionary argument.  If this is the case, we will store the instance of UIApplicationShortcutItem in a property so we can reference it later and set our boolean to false, because we don’t want the application:performActionForShortcutItem:completionHandler: to be called again.

Now we can safely implement applicationDidBecomeActive: and check if the shortcutItem property has been set.  If so, the app is not coming from a background state.

And that’s it!

You can find the source code for this project on Github.

 

 

 

 

 

 

 

  • Christian “ReloS” Soler

    How to i get the controller which action was clicked? I get nil if i try this on viewDidLoad:
    let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
    print(“At Controller (delegate.shortcutItem?.type)”)
    I am new to iOS development.

    • You’ll always end up in the AppDelegate’s method when the user used a quick action. Within that method you’ll have to do a check on the type you have specified for the shortcutItem.
      Within that check, you can then create the view controller and present it to the user. I’ve updated the sample project on GitHub, so you can check out the code.

  • You’ll always end up in the AppDelegate’s method when the user used a quick action. Within that method you’ll have to do a check on the type you have specified for the shortcutItem.
    Within that check, you can then create the view controller and present it to the user. I’ve updated the sample project on GitHub, so you can check out the code.

    • Christian “ReloS” Soler

      Thanks. Worked great.

  • Pingback: 3D Touch peek and pop tutorial for Swift()

  • Red Tube

    app crash with error: fatal error: unexpectedly found nil while unwrapping an Optional value

    when i try to edit a UITextField

    any way to fix it

    I’m adding the outlet as:
    @IBOutlet weak var Field: UITextField!

    and

    func handleShortcut( shortcutItem:UIApplicationShortcutItem ) -> Bool {
    print(“Handling shortcut”)
    var succeeded = false
    if( shortcutItem.type == “item.1” ) {
    print(“- Handling (shortcutItem.type)”)
    Field.text == “”
    succeeded = true
    }

    • Did you check if the Field variable is already initialised. ViewDidLoad hasn’t probably been called yet, so your outlet is still nil which results in a crash if you try to access it at Field.text.

      Also, you are not doing an assignment on Field.text, but an evaluation because you are using double == characters.

      You’ll first have to get a reference to your view controller, then assign the value you want to pass to the view controller and visualise it in viewDidLoad (or any lifecycle method which get called after that).

      You can check my code on Github where I’ve added a few days ago such an example.

      Regards,
      Frederik

      • Red Tube

        still not working, the app crash every time i try to change the value of the field, i tried viewdidload, applicationdidfinishlaunching, awakefromnib and also tried making a function that gets activated after 5 seconds from taping the quick action and i used the app for a few seconds before the 5 seconds was over then when the action got called the app crashed.

        func handleShortcut( shortcutItem:UIApplicationShortcutItem ) -> Bool {
        print(“Handling shortcut”)
        var succeeded = false
        if( shortcutItem.type == “item.1” ) {
        print(“- Handling (shortcutItem.type)”)
        self.performSelector(“Action”, withObject: nil, afterDelay: 5)
        succeeded = true
        }
        }

        func Action(){
        Field.text = “whatever”
        }

        however when i link a UIButton as an action and use it to change the text in the field the app does not crash

        any ideas

  • matte_car

    I followed your tutorial but quick actions doesn’t appear in springboard. Should I only set quick actions in plist and manage them in AppDelegate, right? Or there’s something else to do? Thank you!

    • Kevin

      There must be something wrong in the plist if they are not showing (assuming you are testing on an iPhone 6s)

      Have a look at the example I’ve done here based on Federik’s tutorial: http://i.imgur.com/ufHxSqH.png

      You can leave the icon file, subtitle and type blank to test the shortcut before working on the code to handle them.

      Just make sure the structure for UIApplicationShortcutItems looks identical for you.

      • matte_car

        That’s my info.plist https://uploads.disquscdn.com/images/bd3c584bf2704a20d11ab24613d33746ce38e39619aa5fe2cce0ba5fdac1572e.png

        Icon doesn’t contain extension because image is in Asset (and however action should be displayed without icon).
        I’ll try writing another type but unluckily I haven’t an iPhone 6S so I have to TestFlight beta to someone which as an iPhone 6S and it’s pretty longer… Would you like to be a tester?!

        • Kevin

          Ah I see the issue here. The name of the array.
          You have:
          UIApplicationShortcutItem
          change to
          UIApplicationShortcutItems

          • matte_car

            You’ve an eagle eye!! It was the problem!!
            Thank you very much!

          • Kevin

            no worries, i make mistakes like that all the time too 🙂

  • Kevin

    The way you have handled:

    var shortcutItem: UIApplicationShortcutItem?

    Works great if the lowest iOS target is 9, but what if we need to support older versions as well? What is the best way to handle this?

    I tried the new @available swift2 checking but on AppDelegate – that results in a crash on every device under ios9. Using @available on performActionForShortcutItem works well though.

    I’m stuck how to handle this 😐

    • rajat khanna

      exactly, the tutorial was not a complete guide !

  • matte_car

    I’ve got another trouble. I had created my two quick actions. Now I want invert their order on screen so I inverted their order in UIApplicationShortcutItems array but app keep displaying quick actions in previous order. I tried cleaning xCode, removing pp from iPhone, ecc but it’s the same…

    • Kevin

      as far as I know iOS will use the number in the item dictionary to dictate the order. So Item ‘0’ will always prioritize over Item ‘1’ and so on.
      So when you say you inverted the order, did you change the dictionary names to match the order you require?
      Item 1 would become Item 0
      Item 0 would become Item 1

      • matte_car

        In inverted title, subtitle, icon and type between item 0 and 1 (copy and paste from an item to another…)

    • If you want to change the order of your quick actions, you just have to change the order of the items inside the UIApplicationShortcutItems array in your plist like Kevin said.

    • lucascaton

      Same is happening here! How did you end up fixing it?

  • Chris Harper

    You mentioned, “It’s also possible to make these quick actions dynamic, meaning that you can add and remove actions based on the state of your application”, but didn’t follow-up on how that’s done. Any insight into how to make shortcuts dynamic (different options, icons, etc.)? Thanks!

  • miff

    In Info.plist before you need: UIApplicationShortcutItems

  • Yet another amateur question. I’m trying to use 3d Touch for a Spritekite game to start a new game in hard/easy mode. It works when the app wasn’t launched before, but once started, I’m unable to detect if it was started via a shortcut.

    The operation with view controllers is still a close book for me, so within the GameScene.swift I’m getting the status with this command:

    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    forceSelection = appDelegate.forceSelection

    At the AppDelegate.swift the selection of the view controller is commented out, because I’ve always got the following error:

    *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘Storyboard () doesn’t contain a view controller with identifier ‘Game View Controller”

    Anybody who is able to give me a hint?

    -Stephan-

  • Arthur Van Siclen

    Here is a question: in iOS 10, any idea how to hide a Today Widget from the home-screen quick action sheet? I can’t find the method…

    • Arthur Van Siclen

      Figured it out… in the info.plist, implement this key: “Home Screen Widget” with NULL.

      • Okrad D

        But did that pass to App store ?