Launching with UIApplicationShortcutItem
Asked Answered
F

6

30

I'm implementing some 3D touch quick actions for my iOS 9 app in swift, and I have a curious issue. When my app is in the background and I launch with the quick action, everything goes as planned. When my app is totally dead (i.e. I killed it from the multitasking menu), and I launch with the quick action, the app crashes. I'm having trouble debugging this as once I kill the app, the debug session in Xcode gets detached. Is there a way for me to connect to the app to debug like normal, or is there something in my code that would be causing it? Thanks in advance.

Code:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
    var launchedFromShortCut = false

    //Check for ShortCutItem
    if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsShortcutItemKey] as? UIApplicationShortcutItem
    {
        launchedFromShortCut = true
        self.handleShortCutItem(shortcutItem)
    }

    return !launchedFromShortCut
}

func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void)
{
    self.handleShortCutItem(shortcutItem)
}

func handleShortCutItem(shortcutItem: UIApplicationShortcutItem)
{
    //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


        if let rootViewController = rootNavigationViewController?.viewControllers.first as! LaunchViewController?
        {
            //Pop to root view controller so that approperiete segue can be performed
            rootNavigationViewController?.popToRootViewControllerAnimated(false)

            switch shortcutType
            {
                case .Compose:
                    rootViewController.shouldCompose()
                    break
            }
        }
    }
}

Thanks!

Faustinafaustine answered 26/9, 2015 at 19:36 Comment(5)
You can still look at the app's crash log file after it is killed...Desmonddesmoulins
You get this sorted, I'm having the same issue?Jumbo
@Jumbo no I haven't.Faustinafaustine
I think this post can answer your questions. hope that helps. #32634524Sooth
Same issue here. I've tried all the same code as your example above, but run into the same issue when running from a killed state. The below suggestion does not seem to catch the output when launching from the shortcut.Whomsoever
W
28

I finally got this working. Here's what my AppDelegate.swift file ended up as;

class AppDelegate: UIResponder, UIApplicationDelegate {

// Properties
var window: UIWindow?
var launchedShortcutItem: UIApplicationShortcutItem?

func applicationDidBecomeActive(application: UIApplication) {

    guard let shortcut = launchedShortcutItem else { return }

    handleShortcut(shortcut)

    launchedShortcutItem = nil

}

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    // Override point for customization after application launch.
    var shouldPerformAdditionalDelegateHandling = true

    // If a shortcut was launched, display its information and take the appropriate action
    if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsShortcutItemKey] as? UIApplicationShortcutItem {

        launchedShortcutItem = shortcutItem

        // This will block "performActionForShortcutItem:completionHandler" from being called.
        shouldPerformAdditionalDelegateHandling = false

    }

    return shouldPerformAdditionalDelegateHandling
}


func handleShortcut( shortcutItem:UIApplicationShortcutItem ) -> Bool {

    // Construct an alert using the details of the shortcut used to open the application.
    let alertController = UIAlertController(title: "Shortcut Handled", message: "\"\(shortcutItem.localizedTitle)\"", preferredStyle: .Alert)
    let okAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
    alertController.addAction(okAction)

    // Display an alert indicating the shortcut selected from the home screen.
    window!.rootViewController?.presentViewController(alertController, animated: true, completion: nil)

    return handled

}

func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {

    completionHandler(handleShortcut(shortcutItem))

}

Much of this was taken from Apple's sample code for UIApplicationShortcuts, and while I'm having my app launch an alert to prove that it is recognizing the proper shortcut was chosen, this could be adapted to your code to pop the view controller.

I think the func applicationDidBecomeActive was the critical part that I was missing, and removing the self.handleShortCut(shortcutItem) from didFinishLaunchingWithOptions (otherwise it was calling handleShortCut twice, it seemed).

Whomsoever answered 22/10, 2015 at 14:11 Comment(3)
That's awesome will test soon.Faustinafaustine
what is that "handled" value that you return?Bellybutton
From Apple example, func handleShortcut always return true, so probably "handled" is trueDacia
B
65
  1. In Xcode, open Product -> Schemes -> Edit Schemes
  2. In your Run Scheme, change the Launch setting to 'Wait for executable to be launched'

Now, if you turn on debugging and run your app, Xcode will wait for you to launch your app from the home screen so you are able to test launching it using a 3D Touch Shortcut Item.

See Screenshot in Xcode of the Setting

Brickle answered 12/10, 2015 at 21:55 Comment(4)
Thank you so much! This allowed me to test quick action from a terminated state. +1Chancellorsville
How do I get to print things to the console?Bornu
Helal olsun amk. ADAMSIN!Bothy
This is super useful! Just make sure to run (cmd+R) in Xcode first, then start the App.Observe
W
28

I finally got this working. Here's what my AppDelegate.swift file ended up as;

class AppDelegate: UIResponder, UIApplicationDelegate {

// Properties
var window: UIWindow?
var launchedShortcutItem: UIApplicationShortcutItem?

func applicationDidBecomeActive(application: UIApplication) {

    guard let shortcut = launchedShortcutItem else { return }

    handleShortcut(shortcut)

    launchedShortcutItem = nil

}

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    // Override point for customization after application launch.
    var shouldPerformAdditionalDelegateHandling = true

    // If a shortcut was launched, display its information and take the appropriate action
    if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsShortcutItemKey] as? UIApplicationShortcutItem {

        launchedShortcutItem = shortcutItem

        // This will block "performActionForShortcutItem:completionHandler" from being called.
        shouldPerformAdditionalDelegateHandling = false

    }

    return shouldPerformAdditionalDelegateHandling
}


func handleShortcut( shortcutItem:UIApplicationShortcutItem ) -> Bool {

    // Construct an alert using the details of the shortcut used to open the application.
    let alertController = UIAlertController(title: "Shortcut Handled", message: "\"\(shortcutItem.localizedTitle)\"", preferredStyle: .Alert)
    let okAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
    alertController.addAction(okAction)

    // Display an alert indicating the shortcut selected from the home screen.
    window!.rootViewController?.presentViewController(alertController, animated: true, completion: nil)

    return handled

}

func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {

    completionHandler(handleShortcut(shortcutItem))

}

Much of this was taken from Apple's sample code for UIApplicationShortcuts, and while I'm having my app launch an alert to prove that it is recognizing the proper shortcut was chosen, this could be adapted to your code to pop the view controller.

I think the func applicationDidBecomeActive was the critical part that I was missing, and removing the self.handleShortCut(shortcutItem) from didFinishLaunchingWithOptions (otherwise it was calling handleShortCut twice, it seemed).

Whomsoever answered 22/10, 2015 at 14:11 Comment(3)
That's awesome will test soon.Faustinafaustine
what is that "handled" value that you return?Bellybutton
From Apple example, func handleShortcut always return true, so probably "handled" is trueDacia
D
3

For Swift 4.2

   func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    var isLaunchedFromQuickAction = false
    if let shortcutItem = launchOptions?[UIApplication.LaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem {
        isLaunchedFromQuickAction = true
        handleQuickAction(shortcutItem: shortcutItem)
    }

    return isLaunchedFromQuickAction
}
Dudley answered 5/2, 2019 at 13:11 Comment(2)
@OmarNShamali Wc :-)Dudley
I know this is an old post but do you have any idea why launchOptions?[UIApplication.LaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem is evaluating to nil even when the app is called by a quickaction?Chinook
J
1

I tried all the above, and it didn't solve the problem than I tried handling the shortcut after delay in handleShortcut method:

self.performSelector("action1", withObject: self, afterDelay: 0.5)

and added a method for every action, and it worked like a charm

Joint answered 22/12, 2015 at 16:59 Comment(0)
S
1

Replace your didfinishlaunching method with this one.

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {

  if let shortcutItem =
       launchOptions?[UIApplicationLaunchOptionsShortcutItemKey]
       as? UIApplicationShortcutItem {

    handleShortcut(shortcutItem)
    return false
  }
  return true
}
Section answered 5/2, 2018 at 11:26 Comment(0)
C
0

XCode 11.6, Swift 5

We can attach a process at runtime. XCode will wait until the process is started and will get attached to it when an App is launched manually.

XCode -> Debug -> Attach to process by PID or Name -> ("Enter the name of an app in the pop-up")

Directions:

  1. Make sure an application is freshly installed on a device or a simulator.
  2. Kill the application.
  3. In XCode attach the name of the process as mentioned above.
  4. Open the application through the desired shortcut

P.S: If you are using SceneDelegate a shortcutItem can be found in

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
       switch connectionOptions.shortcutItem?.localizedTitle {
       case "Search":
       break
       case "DoSomething":
       break
       default:
       break
       } 
    }

Happy Debugging :)

Debug -> Process name

Name of a target

Cathartic answered 6/1, 2021 at 9:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.