2

I am very new to the iOS Application development and I have been following tutorials to build my career . So starting with I am trying to Implement Static Quick Actions in Objective C as per client project . I was able to add the keys and got the options while pressing the icon . But when I press the Quick Actions nothing happens and it just launches the Application. I have researched a lot and I tried but in vain. Below is the Appdelegate code which I have written:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    BOOL shouldPerformAdditionalDelegateHandling = YES;
    
    
    // Check API availiability
    // UIApplicationShortcutItem is available in iOS 9 or later.
    if([[UIApplicationShortcutItem class] respondsToSelector:@selector(new)]){
        NSLog(@"HERE");
        //  [self configDynamicShortcutItems];
        
        // If a shortcut was launched, display its information and take the appropriate action
        UIApplicationShortcutItem *shortcutItem = [launchOptions objectForKeyedSubscript:UIApplicationLaunchOptionsShortcutItemKey];
        
        if(shortcutItem)
        {
            NSLog(@"shortcut launch");
            // When the app launch at first time, this block can not called.
            
            [self handleShortCutItem:shortcutItem];
            
            // This will block "performActionForShortcutItem:completionHandler" from being called.
            shouldPerformAdditionalDelegateHandling = NO;
            
            
        }else{
            NSLog(@"normal launch");
            // normal app launch process without quick action
            
            // [self launchWithoutQuickAction];
            
        }
        
    }else{
        
        // Less than iOS9 or later
        
        //  [self launchWithoutQuickAction];
        
    }
    
    
    return shouldPerformAdditionalDelegateHandling;
}


- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler{
    NSLog(@"performActionForShortcutItem");
    
    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;
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    
    
    if ([shortcutItem.type isEqualToString:@"PlayMusic"]) {
        handled = YES;
        NSLog(@"Play");
        
        secondview *vc = [storyboard instantiateViewControllerWithIdentifier:@"second"];
        
        self.window.rootViewController = vc;
        
        [self.window makeKeyAndVisible];
        
    }
    
    else if ([shortcutItem.type isEqualToString:@"StopMusic"]) {
        handled = YES;
        NSLog(@"Stop");
        //        ThirdViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"thirdVC"];
        //
        //        self.window.rootViewController = vc;
        
        [self.window makeKeyAndVisible];
    }
    
    
    return handled;
}

However I can see the Quick Action items when I deep press the home icon but on clicking that no action happens. I check the key in info.plist and its the same . Quick Actions

Below is the info.plist for adding Static Actions

<key>UIApplicationShortcutItems</key>
<array>
    <dict>
        <key>UIApplicationShortcutItemIconType</key>
        <string>UIApplicationShortcutIconTypePlay</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>Play</string>
        <key>UIApplicationShortcutItemSubtitle</key>
        <string>Start playback</string>
        <key>UIApplicationShortcutItemType</key>
        <string>PlayMusic</string>
    </dict>
    <dict>
        <key>UIApplicationShortcutItemIconType</key>
        <string>UIApplicationShortcutIconTypePlay</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>STOP</string>
        <key>UIApplicationShortcutItemSubtitle</key>
        <string>Stop playback</string>
        <key>UIApplicationShortcutItemType</key>
        <string>StopMusic</string>
    </dict>

Can some one please help where I am doing wrong?

user16780334
  • 422
  • 5
  • 20

2 Answers2

3

since iOS(13.0, *) AppDelegate handles its own UIWindow via SceneDelegate's and so the method

@implementation AppDelegate

-(void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler
{
    // here shortcut evaluation below ios(13.0)
}

@end

is only invoked on iPhones or iPads with iOS lower Version 13.0

So to make it work in iOS(13.0,*) and above you need to implement it in SceneDelegate with a slightly different name, see below.. (matt was right!)

@implementation SceneDelegate

-(void)windowScene:(UIWindowScene *)windowScene performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler {
    // here shortcut evaluation starting with ios(13.0)
    NSLog(@"shortcutItem=%@ type=%@",shortcutItem.localizedTitle, shortcutItem.type);
}

@end

PS: The Apple Example Code for Quick Actions in swift is bogus when you assume you can use it as is in iOS(13.0,*) because it is written for versions earlier iOS < 13.0

EDIT: as asked, here in full beauty for iOS >= 13.0

@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
@property (strong, nonatomic) UIWindow * window;
@end

and

-(void)windowScene:(UIWindowScene *)windowScene performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler {
    /* //go to Info.plist open as Source Code, paste in your items with folling scheme
    <key>UIApplicationShortcutItems</key>
    <array>
        <dict>
            <key>UIApplicationShortcutItemIconType</key>
            <string>UIApplicationShortcutIconTypePlay</string>
            <key>UIApplicationShortcutItemTitle</key>
            <string>Play</string>
            <key>UIApplicationShortcutItemSubtitle</key>
            <string>Start playback</string>
            <key>UIApplicationShortcutItemType</key>
            <string>$(PRODUCT_BUNDLE_IDENTIFIER).Start</string>
        </dict>
        <dict>
            <key>UIApplicationShortcutItemIconType</key>
            <string>UIApplicationShortcutIconTypePlay</string>
            <key>UIApplicationShortcutItemTitle</key>
            <string>STOP</string>
            <key>UIApplicationShortcutItemSubtitle</key>
            <string>Stop playback</string>
            <key>UIApplicationShortcutItemType</key>
            <string>$(PRODUCT_BUNDLE_IDENTIFIER).Stop</string>
        </dict>
    </array>
     */
    
    // may look complex but this is 100% unique
    // which i would place $(PRODUCT_BUNDLE_IDENTIFIER). in front of types in Info.plist
    NSString *devIdent = [NSString stringWithFormat:@"%@.",NSBundle.mainBundle.bundleIdentifier];
    
    if ([shortcutItem.type isEqualToString:[devIdent stringByAppendingString:@"Start"]]) {
        completionHandler([self windowScene:windowScene byStoryBoardIdentifier:@"startview"]);
        
    } else if ([shortcutItem.type isEqualToString:[devIdent stringByAppendingString:@"Stop"]]) {
        completionHandler([self windowScene:windowScene byStoryBoardIdentifier:@"stopview"]);

    } else {
        NSLog(@"Arrgh! unrecognized shortcut '%@'", shortcutItem.type);
    }
    //completionHandler(YES);
}

-(BOOL)windowScene:(UIWindowScene *)windowScene byStoryBoardIdentifier:(NSString *)identifier {
    // idear is to return NO if build up fails, so we can startup normal if needed.
    UIStoryboard *story = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    if (story!=nil) {
        UIViewController *vc = [story instantiateViewControllerWithIdentifier:identifier];
        if (vc!=nil) {
            if (_window==nil) _window = [[UIWindow alloc] initWithWindowScene:windowScene];
            _window.rootViewController = vc;
            
            // .. OR following code..
            //[_window.rootViewController presentViewController:vc animated:YES completion:^{ }];
            //[_window makeKeyAndVisible];
            
            // should be success here..
            return YES;
        }
    }
    // no success here..
    return NO;
}

You can do also other things than instantiate a ViewController from Storyboard. In example you could switch a property or something similar.

Ol Sen
  • 3,163
  • 2
  • 21
  • 30
  • Thanks a lot .... can you please post the whole code of Static Quick Actions items ? I have posted the full code in question but its not working. – user16780334 Nov 12 '20 at 03:08
  • any vote counts :-) for swift coders [matt's post follows the apple example](https://stackoverflow.com/questions/58479013/do-something-with-quick-action) and [BundleIdentifier in swift here](https://stackoverflow.com/questions/8883102/obtain-bundle-identifier-programmatically) – Ol Sen Nov 12 '20 at 04:56
  • I have upvoted(will only show after my 15 points) and accepted your answer :). can you please tell how to push to the certain view controller from short cut action? – user16780334 Nov 12 '20 at 05:00
  • A GitHub sample project(Quick Actions) with both below iOS 13 and above implementation will be helpful for me – user16780334 Nov 12 '20 at 05:04
  • 1
    thats the out-commented part in the co-method in the post, use that instead and it should present your VC in front. `[_window.rootViewController presentViewController:vc animated:YES completion:^{ }];` instead of `_window.rootViewController = vc;` – Ol Sen Nov 12 '20 at 05:05
  • I guess this is for presenting view controller can you please help me of how to push to that view controller by using navigation controller of the app? – user16780334 Nov 12 '20 at 05:29
  • In react-native project, how to open screens via these quick options? Should I open the URL and handle the deeplinking in my project? If yes, then please let know what will be the code for each options. I am a pure JavaScript developer so I can understand your code little bit. – Chandresh Jun 18 '21 at 13:01
  • well - ask that question and share a link to this post if you want to refer to it with react native knowledge. Can't answer your question in a comment cause its also total unrelated to this question – Ol Sen Jun 18 '21 at 14:11
1

Sorry being too late. Further research about home quick actions showed me the following conclusions after discussing with major developers . The following points which needed to be followed while integrating HomeQuickActions are :

  1. Most Important point for every developer: Home quick actions(short cut items on clicking app icon) are definitely OS and hardware based (supported only from iOS 13). Apple documents. It means before iOS 13 no device will show app short cut items even if they have Haptic Touch / 3D Touch. iOS 13 and above is a mandatory requirement.(Checked in Simulator for all iPhone, need to test in real device with older phones)

Both 3D touch enable and non-3D touch enabled devices support this feature through force-touch or long-press depending on device capabilities if they are capable of running iOS 13 or above.

  1. So for App short cuts to work the iOS devices must be having iOS 13 for sure and the hardware compatibility is also required which means the devices must be having iOS 13 and above for App short cuts to work. For iPhone 5S, iPhone 6 owners: iOS 13 won't be compatible anymore.

  2. Since Apple has replaced 3D Touch hardware with Haptic Touch , the newer iPhones from iPhone XR will have only Haptic Touch . Old devices after SE(1 st generation, iPhone 6 series till iPhone X ) have 3D Touch hardware. Haptic Touch is a software OS dependent which uses finger pressed area and 3D Touch is a hardware dependent which uses a specific sensor between screen.

user16780334
  • 422
  • 5
  • 20
User1075
  • 819
  • 15
  • 36
  • Thanks Fiona for such a important note. :) Yes ofcoure iOS 13 plus is a mandatory requirement for App shortcuts to work. – user16780334 Dec 09 '20 at 10:21