3D Touch Home Shortcuts In Obj-C
Asked Answered
A

5

25

All of my apps are currently written in Obj-C. The link https://developer.apple.com/library/content/samplecode/ApplicationShortcuts/Introduction/Intro.html#//apple_ref/doc/uid/TP40016545 for the sample code of implementing Home Screen Shortcuts with 3D Touch is completely compiled in Swift. Anyone come across documentation for Obj-C, so I don't have to go through my AppDelegate and translate it all?

UPDATE:

After adding in all the shortcuts in Info.plist, I added in the AppDelegate.m:

- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler {
    UINavigationController *nav = (UINavigationController *) self.tabBarController.selectedViewController;

    NSLog(@"%@", shortcutItem.type);
    if ([shortcutItem.type isEqualToString:@"com.316apps.iPrayed.addPrayerRequest"]) {
        Requests *gonow = [[Requests alloc] init];

        [nav pushViewController:gonow animated:YES];

    }
    if ([shortcutItem.type isEqualToString:@"com.316apps.iPrayed.addPrayer"]) {

      PrayerStats *controller = [[PrayerStats alloc] init];
        [nav pushViewController:controller animated:YES];

    }

    if ([shortcutItem.type isEqualToString:@"com.316apps.iPrayed.addFast"]) {

      FastStats *controller1 = [[FastStats alloc] init];
        [nav pushViewController:controller1 animated:YES];

    }

    if ([shortcutItem.type isEqualToString:@"com.316apps.iPrayed.addStudy"]) {

      StudyStats *controller2 = [[StudyStats alloc] init];
        [nav pushViewController:controller2 animated:YES];

    }
   }

This allows it to work, without putting any other methods in, or adding anything to didFinishLaunchingWithOptions.

Angieangil answered 17/9, 2015 at 15:16 Comment(0)
G
25

There are two states from where the user can open the app through Quick Actions.

TL;DR You are always doing the same thing regardless of the state in which the app is when the quick action is done, that's why you only need to override application:performActionForShortcutItem:completionHandler: So if you wanted to do different things, then you would want to handle them in the two places, if not then just the overridden is enough.

  • One is if the app is killed or not running in background where we get the shortcut info on launch.

  • The other is if the app is running in background where we get the shortcut info on the new app delegate method.

To handle these Quick Action shortcuts when in background you need to override this method on App Delegate:

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

And for not running in background (killed) on your

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

or

-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions

you should check if the app was launched by a Quick Action:

UIApplicationShortcutItem *shortcutItem = [launchOptions objectForKey:UIApplicationLaunchOptionsShortcutItemKey];

(Link to related Apple Documentation) Quote from the Official Apple Docs

It’s your responsibility to ensure the system calls this method conditionally, depending on whether or not one of your app launch methods (application:willFinishLaunchingWithOptions: or application:didFinishLaunchingWithOptions:) has already handled a quick action invocation. The system calls a launch method (before calling this method) when a user selects a quick action for your app and your app launches instead of activating.

The requested quick action might employ code paths different than those used otherwise when your app launches. For example, say your app normally launches to display view A, but your app was launched in response to a quick action that needs view B. To handle such cases, check, on launch, whether your app is being launched via a quick action. Perform this check in your application:willFinishLaunchingWithOptions: or application:didFinishLaunchingWithOptions: method by checking for the UIApplicationLaunchOptionsShortcutItemKey launch option key. The UIApplicationShortcutItem object is available as the value of the launch option key.

If you find that your app was indeed launched using a quick action, perform the requested quick action within the launch method and return a value of NO from that method. When you return a value of NO, the system does not call the application:performActionForShortcutItem:completionHandler: method.

Godroon answered 24/9, 2015 at 23:18 Comment(13)
Am I missing something? When I put in that last line of code in didFinishLaunching, I get unused item shortcutItem. Do I need to put that in elsewhere?Angieangil
well, are you using shortcutItem after setting it?Ulcerous
@Ulcerous no, because I didn't write this answer, someone else did, was just curious why it was in there. Just adding the performActionForShortcutItem code allowed me to perform the shortcuts I had added in info, and since Nicolas didn't have that anywhere else in his answer, was curious why it was needed.Angieangil
It's needed if you have more than one shortcut and want to handle it in any sort of customized way. Say, for example, one of your shortcuts is for Favorites- you would want to launch the app directly to your Favorites tab. This could be done by checking the type property on shortcutItem and switching your active tab bar view controller upon launch (in this example).Ulcerous
For further clarification, you need to handle shortcuts in two different ways: one if your app is in the background (application:performActionForShortcutItem) and one if your app is terminated (application:didFinishLaunchingWithOptions). In the former handler, a reference to the shortcutItem is provided to the delegate. In the latter, it is a part of the launchOptions dictionary. The SO answer here is providing a way to get a reference to the shortcut item but not how to use it (which is entirely based on your app's needs).Ulcerous
Exactly, there are two states from where the user can open the app through Quick Actions. One is if the app is killed or not running in background where we get the shortcut info on didFinishLaunchingWithOptions and the other is if the app is running in background where we get the shortcut info on application: performActionForShortcutItem:completionHandler: i'll update the answer to clarify this.Godroon
I added in the application: performActionForShortcutItem:completionHandler: method to my appDelegate implementation file, with if ([shortcutItem.type isEqualToString:@"com.316apps.iPrayed.addPrayer"]) { for all the different shortcuts I have. It works when the app is in the background, and when the app is completely shut down, without anything put in the didFinishLaunching or willFinishLaunching or any thing like that.Angieangil
See the updated OP...doesn't seem there is a need for a lot of this code, after all?Angieangil
@Angieangil see the updated answer with a quote from apple docs, it is not necessary if you don't want to handle different flows.Godroon
I've tried every different scenario, and it ALWAYS works perfect with just the performAction handlerAngieangil
I guess just because I'm instantiating a nav controller regardless of which view is currently active, and then pushing to a specific controller is the reason?Angieangil
@Angieangil You are always doing the same thing regardless of the state in which the app is when the quick action is done. So if yo wanted to do different things, then you would want to handle them in these two places, if not then just the overridden is enough. I've added a proper answer to your question.Godroon
UIApplicationShortcutItem is iOS 9 only: NS_CLASS_AVAILABLE_IOS(9_0) __TVOS_PROHIBITED @interface UIMutableApplicationShortcutItem : UIApplicationShortcutItemAlbacore
P
4

Implement below 3 simple steps:

Step 1 : Write below method in AppDelegate class to Configure dynamic shortcut items.

NOTE : You can configure shortcut items in info.plist if you want it static. (Refer Apple documentation.)

/**
 *  @brief config dynamic shortcutItems
 *  @discussion after first launch, users can see dynamic shortcutItems
 */
- (void)configDynamicShortcutItems {
    // config image shortcut items
    // if you want to use custom image in app bundles, use iconWithTemplateImageName method
    UIApplicationShortcutIcon *shortcutSearchIcon = [UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypeSearch];
    UIApplicationShortcutIcon *shortcutFavoriteIcon = [UIApplicationShortcutIcon iconWithType:UIApplicationShortcutIconTypeFavorite];

    UIApplicationShortcutItem *shortcutSearch = [[UIApplicationShortcutItem alloc]
                                                 initWithType:@"com.sarangbang.QuickAction.Search"
                                                 localizedTitle:@"Search"
                                                 localizedSubtitle:nil
                                                 icon:shortcutSearchIcon
                                                 userInfo:nil];

    UIApplicationShortcutItem *shortcutFavorite = [[UIApplicationShortcutItem alloc]
                                                 initWithType:@"com.sarangbang.QuickAction.Favorite"
                                                 localizedTitle:@"Favorite"
                                                 localizedSubtitle:nil
                                                 icon:shortcutFavoriteIcon
                                                 userInfo:nil];


    // add all items to an array
    NSArray *items = @[shortcutSearch, shortcutFavorite];

    // add the array to our app
    [UIApplication sharedApplication].shortcutItems = items;
}

Step 2 : In AppDelegate class application didFinishLaunchingWithOptions method write below code.

    // UIApplicationShortcutItem is available in iOS 9 or later.
        if([[UIApplicationShortcutItem class] respondsToSelector:@selector(new)]){

            [self configDynamicShortcutItems];

            // If a shortcut was launched, display its information and take the appropriate action
            UIApplicationShortcutItem *shortcutItem = [launchOptions objectForKeyedSubscript:UIApplicationLaunchOptionsShortcutItemKey];

            if(shortcutItem)
            {
                // When the app launch at first time, this block can not called.
                //App launch process with quick actions
                [self handleShortCutItem:shortcutItem];
            }else{
                // normal app launch process without quick action
            }

        }

Step 3 : Write below delegate method and completion handler in AppDelegate class.

/*
 Called when the user activates your application by selecting a shortcut on the home screen, except when
 application(_:,willFinishLaunchingWithOptions:) or application(_:didFinishLaunchingWithOptions) returns `false`.
 You should handle the shortcut in those callbacks and return `false` if possible. In that case, this
 callback is used if your application is already launched in the background.
 */

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

    BOOL handledShortCutItem = [self handleShortCutItem:shortcutItem];

    completionHandler(handledShortCutItem);
}


/**
 *  @brief handle shortcut item depend on its type
 *
 *  @param shortcutItem shortcutItem  selected shortcut item with quick action.
 *
 *  @return return BOOL description
 */
- (BOOL)handleShortCutItem : (UIApplicationShortcutItem *)shortcutItem{

    BOOL handled = NO;

    NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;

    NSString *shortcutSearch = [NSString stringWithFormat:@"%@.Search", bundleId];
    NSString *shortcutFavorite = [NSString stringWithFormat:@"%@.Favorite", bundleId];

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];


    if ([shortcutItem.type isEqualToString:shortcutSearch]) {
        handled = YES;

        SecondViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"secondVC"];

        self.window.rootViewController = vc;

        [self.window makeKeyAndVisible];

    }

    else if ([shortcutItem.type isEqualToString:shortcutFavorite]) {
        handled = YES;

        ThirdViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"thirdVC"];

        self.window.rootViewController = vc;

        [self.window makeKeyAndVisible];
    }


    return handled;
}
Perplexity answered 30/6, 2017 at 6:37 Comment(0)
A
3

If you look at the sample code provided for apple, you'll see that they suggest that you write a method that handles your shortcut item so that you can handle it in all three places:

  • application: performActionForShortcutItem,
  • application: didFinishLaunchingWithOptions and
  • willFinishLaunchingWithOptions

An example of what I did was:

- (BOOL)handleShortCutItem:(UIApplicationShortcutItem *)shortcutItem {
    BOOL handled = NO;

    if (shortcutItem == nil) {
        return handled;
    }

    if ([shortcutItem.type isEqualToString:kFavoritesQuickAction]) {
        handled = YES;
    } 

    if (handled) {
        // do action here
    }

    return handled;
}

Then you would just call this method in any place where you are getting a shortcut item. This should help you along your way!

Alderman answered 28/9, 2015 at 19:54 Comment(2)
See the updated OP...doesn't seem there is a need for a lot of this code, after all?Angieangil
This is ridiculously late to response here, but this way of handling shortcuts is how Apple suggests to go about handling it. I believe they mention that it is specifically the developer's responsibility for handling the multiple scenarios that could happen which my answer shows. You can also see how they handle it in their sample code: developer.apple.com/library/ios/samplecode/ApplicationShortcuts/…Alderman
E
1

I make an objective-c demo project for home screen quick action.

3D touch home quick action demo : https://github.com/dakeshi/3D_Touch_HomeQuickAction

The Demo project implements the static quick action without Info.plist file to avoid unwanted situations before launching the app at first. You can easily change it to the dynamic quick action.

As mentioned in apple documentation, you can handle quick action in application:didFinishLaunchingWithOptions: method. In that case, you should return NO to block to call application:performActionForShortcutItem:completionHandler: method.

Exchange answered 17/12, 2015 at 7:42 Comment(0)
H
0

It works on both swift 3 and 4 (only on home screen shortcuts)

//Add plist items as show in image and write following method in Appdelegate
//3D Touch Method shortcuts from home screen

func application(_ application: UIApplication, performActionFor shortcutItem:UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {

if shortcutItem.type == "Share" {
    //handle action Share
    let alert = UIAlertController(title: "3D touch Share", message: "Yahoo!!! 3D touch is working👌", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.window?.rootViewController?.present(alert,animated: true,completion: nil)
    completionHandler(true)
   } else if shortcutItem.type == "Logout" {

    //handle action Type02
    let alert = UIAlertController(title: "3D touch Logout", message: "Yahoo!!! 3D touch is working👌", preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
    self.window?.rootViewController?.present(alert,animated: true,completion: nil)
    completionHandler(true)
   } else {
    completionHandler(false)
  }

 }

enter image description here

Hospice answered 16/2, 2018 at 5:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.