0

Hi and thanks in advance.

I have an application i wrote that uses the new UIApplicationShortcut's on the home screen using 3D touch. The shortcuts work once the app is app, but if the app is closed out the shortcuts do not work on the home screen.

When the application is closed the shortcuts launch the app, but the shortcuts do not work, only the application launches.

here is the two methods I use for the shortcuts.

- (void)setupViewControllers {
    // setup the navigation stack

    CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
    if (iOSDeviceScreenSize.height == 480)
    {
        _navigationController = (UINavigationController *)self.window.rootViewController;

        // iPhone 5 and iPod Touch 5th generation: 4 inch screen
        // Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone4
        UIStoryboard *iPhone4Storyboard = [UIStoryboard storyboardWithName:@"Main4s" bundle:nil];

        UIViewController *initialViewController = [iPhone4Storyboard instantiateInitialViewController];
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

        self.window.rootViewController  = initialViewController;

        self.myViewController = (ViewController *)_navigationController.topViewController;
        self.myViewController.managedObjectContext = self.managedObjectContext;

        [self.window makeKeyAndVisible];
    }

    if (iOSDeviceScreenSize.height == 568)
    {
        _navigationController = (UINavigationController *)self.window.rootViewController;

        // iPhone 5 and iPod Touch 5th generation: 4 inch screen
        // Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone4
        UIStoryboard *iPhone4Storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

        UIViewController *initialViewController = [iPhone4Storyboard instantiateInitialViewController];
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

        self.window.rootViewController  = initialViewController;

        self.myViewController = (ViewController *)_navigationController.topViewController;
        self.myViewController.managedObjectContext = self.managedObjectContext;

        [self.window makeKeyAndVisible];
    }

    if (self.myViewController){NSLog(@"myViewController is not nil, setupViewControllers");}
    else
    {
        NSLog(@"myViewController is nil, setupViewControllers");//breakpoint inserted here...
    }
}

- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler {

    [self setupViewControllers];

    // react to shortcut item selections
    NSLog(@"A shortcut item was pressed. It was %@.", shortcutItem.localizedTitle);
    if([shortcutItem.localizedTitle isEqualToString:@"Scan Tag"])
    {
        [self.myViewController toggleScanningTapped:nil];
    }
    if([shortcutItem.localizedTitle isEqualToString:@"Enter Tag"])
    {
        [self.myViewController manualEntry];
    }
    if([shortcutItem.localizedTitle isEqualToString:@"Search for a Tag"]){
        [self.myViewController SearchSwitch];
        [self.myViewController toggleScanningTapped:nil];
    }
    if([shortcutItem.localizedTitle isEqualToString:@"Just Scan & Copy"]){
        [self.myViewController justCopy];
    }

    if (self.myViewController){NSLog(@"myViewController is not nil, performActionForShortcutItem");}
    else
    {
        NSLog(@"myViewController is nil, performActionForShortcutItem");
    }
}


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.

    [self setupViewControllers];

    NSURL *url = (NSURL *)[launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];
    if (url != nil && [url isFileURL]) {
        [self.myViewController handleOpenURL:url];
    }

    if (self.myViewController){NSLog(@"myViewController is not nil, didFinishLaunchingWithOptions");}
    else{NSLog(@"myViewController is nil, didFinishLaunchingWithOptions");}

    return YES;
}

here is the plist entries...

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <dict>
        <key>UIApplicationShortcutItemType</key>
        <string>com.PALIANTech.SUNYScanner.static1</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>Scan Tag</string>
        <key>UIApplicationShortcutItemSubtitle</key>
        <string>Add tag to DB</string>
        <key>UIApplicationShortcutItemIconFile</key>
        <string>barcode.png</string>
    </dict>
    <dict>
        <key>UIApplicationShortcutItemType</key>
        <string>com.PALIANTech.SUNYScanner.static2</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>Enter Tag</string>
        <key>UIApplicationShortcutItemSubtitle</key>
        <string>Manually add tag to DB</string>
        <key>UIApplicationShortcutItemIconFile</key>
        <string>ManualEntry.png</string>
    </dict>
    <dict>
        <key>UIApplicationShortcutItemType</key>
        <string>com.PALIANTech.SUNYScanner.static3</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>Search for a Tag</string>
        <key>UIApplicationShortcutItemSubtitle</key>
        <string>Scan a tag to search for</string>
        <key>UIApplicationShortcutItemIconFile</key>
        <string>search.png</string>
    </dict>
</array>
</plist>

Any help or suggestions would be greatly appreciated.

OscarTheGrouch
  • 2,374
  • 4
  • 28
  • 39

1 Answers1

2

The reason is that when your app starts freshly self.myViewController is still nil at the time when you check your short cut items in performActionForShortcutItem and didFinishLaunchingWithOptions. So nothing happens.

To fix this you would have to instantiate myViewController and add it to the navigation stack when the app is opened via a shortcut.

EDIT

Here is a (stripped down) version that works:

AppDelegate

@interface AppDelegate ()
@property ViewController *viewController;
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    [self setupViewControllers];

    return YES;
}

- (void)setupViewControllers {
    self.viewController = [[ViewController alloc] init];
    self.viewController.view.backgroundColor = [UIColor lightGrayColor];
    self.viewController.label.text = @"Normal Launch";
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];

    self.window.rootViewController  = navigationController;
    [self.window makeKeyAndVisible];
}

- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler {
    [self setupViewControllers];

    if([shortcutItem.localizedTitle isEqualToString:@"Scan Tag"]) {
        self.viewController.label.text = @"Shortcut: Scan Tag";
    }
    if([shortcutItem.localizedTitle isEqualToString:@"Enter Tag"]) {
        self.viewController.label.text = @"Shortcut: Enter Tag";
    }
    if([shortcutItem.localizedTitle isEqualToString:@"Search for a Tag"]) {
        self.viewController.label.text = @"Shortcut: Search Tag";
    }
    if([shortcutItem.localizedTitle isEqualToString:@"Just Scan & Copy"]) {
        self.viewController.label.text = @"Shortcut: Scan & Copy Tag";
    }
}

@end

The ViewController class is a plain UIViewController subclass that just has a label for demonstration purposes.

I have tested the shortcuts with an app that was in the background and with the app completely removed from memory. Both worked as intended.

UPDATE

If you are using a ViewController from a storyboard you have to initialize it like this:

- (void)setupViewControllers {
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    self.viewController = (ViewController *)[storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
    ...
}

Don't forget to set the ViewController's identifier in your storyboard:

enter image description here

joern
  • 27,354
  • 7
  • 90
  • 105
  • Thanks for the response. I edited the code to above in hopes to reflect your answer but still haven't gotten it yet. – OscarTheGrouch Oct 13 '15 at 15:12
  • Can you post your changes? – joern Oct 13 '15 at 15:14
  • I think the problem is that `myViewController` is still `nil` in `performActionForShortcutItem:`. When the app is launched via shortcut item it calls `performActionForShortcutItem:` first. My suggestion would be that you remove all the shortcut code from `didFinishLaunchingWithOptions` and move the view controller initialization code to an extra method than you can call from `performActionForShortcutItem:` and `didFinishLaunchingWithOptions` – joern Oct 13 '15 at 16:25
  • thanks for working with me on this. When I move navigation stack code to the setupViewControllers, remove the shortcut code from didFinishLaunchingOptions, and call it from both the didFinishLaunchingWithOptions and the performActionForShortcutItem... the shortcuts do not work when the app is in the background or when the app is not open. – OscarTheGrouch Oct 13 '15 at 18:22
  • Have you set a breakpoint in 'performAction' to see if yourViewController is not nil? – joern Oct 13 '15 at 18:29
  • I changed the code in the post to reflect your answer, I used a breakpoint in the setupViewController method at the very end. The app doesn't crash at the break point when it is in the background or using the shortcuts on the home screen. if (self.myViewController){NSLog(@"myViewController is not nil, setupViewControllers");} else {NSLog(@"myViewController is nil, setupViewControllers");//breakpoint inserted here...} – OscarTheGrouch Oct 13 '15 at 18:44
  • I added a working example to my answer. Please check it out and try to find out where your code is different. – joern Oct 13 '15 at 19:16
  • I created a new project with your code, available here https://dl.dropboxusercontent.com/u/8256776/ASTrial.zip and the color changes on the view controller but the label doesn't change. when removing the [self setupViewControllers]; from performActionForShortcutItem the shortcuts work when the app is in the background but not from a fresh launch. – OscarTheGrouch Oct 14 '15 at 14:08
  • The problem is, that in `setupViewControllers` the `ViewController` is not initialized from the storyboard. So the label is not added to it's view, because that is done in the storyboard. You have to initialize `ViewController` from the storyboard to create the label (see updated answer). Or you add the label to the view in `ViewController.m` – joern Oct 14 '15 at 14:30
  • thank you so much!... it works great now. I upvoted your answer and accepted it. – OscarTheGrouch Oct 14 '15 at 18:32
  • No problem, glad I could help! – joern Oct 14 '15 at 19:38