让App在iOS12中支持Siri Shortcuts(捷径)功能 和 “设置和捷径App内未列出自己App的Shortcut” 的解决办法

最近发现的问题 “设置和捷径App内未列出自己App的Shortcut” 的解决办法在文章末尾或者我的github博客
网上的shortcuts介绍都没有提及这一点,导致了一个疏忽,甚至以为是自动添加的。

文章转自自己github博客
后续更新可能不会及时同步到,欢迎大家来我的github博客查看指教。
同时github屏蔽了baidu爬虫,我的github博客无法通过百度搜索到,很尴尬,不想搭CDN不想搭Coding,暂时没有更好解决办法。

背景介绍

WWDC 2018 苹果更新了Siri使其支持Shortcuts功能,中文名“捷径”。支持用户通过自定义把一系列操作合并到一个Shortcut内。苹果官方应用提供了一些接口供Shortcut调用,如Map应用的“获取行程时间”,“显示路线”等。如果我们的应用需要支持,需要自己在App中开放可以被Shortcuts访问的接口。同时苹果正在大力推广这个Siri新功能,支持软件可在苹果App Store榜单“用 Siri,走捷径”中列出,有一定推广作用。该功能也有利于增加用户粘度和活跃人数。

Apple提供了官方关于Shortcuts的demo,但是在苹果大力推广Swift的浪潮下,demo的语言也是Swift版的,无奈公司现在还在使用Objc,下面介绍下Objc下的接入过程。

创建Custom Intent

在项目中通过“New File...”创建一个Intents.intentdefinition文件。这个文件用来定义自定义intent类型。

让App在iOS12中支持Siri Shortcuts(捷径)功能 和 “设置和捷径App内未列出自己App的Shortcut” 的解决办法_第1张图片
SiriKitIntentDefinitionFile.png

让App在iOS12中支持Siri Shortcuts(捷径)功能 和 “设置和捷径App内未列出自己App的Shortcut” 的解决办法_第2张图片
CustomIntents.png

同时会自动在项目的Info.plist文件中添加NSUserActivityTypes

InfoPlist.png

添加Frameworks

在项目的Build Phases中的Link Binary With Libraries中添加Intents.frameworkIntentsUI.framework

让App在iOS12中支持Siri Shortcuts(捷径)功能 和 “设置和捷径App内未列出自己App的Shortcut” 的解决办法_第3张图片
Frameworks.png

添加Shortcut按钮

在项目中需要调用添加Shortcut按钮的.m文件中,

增加import

#import 
#import 
#import "HWTakePhotoIntent.h"   //上方“设置Custom Intents”图中右边箭头指的“Class Name”

添加Delegate


添加Property

@property (nonatomic, strong) HWTakePhotoIntent API_AVAILABLE(ios(12.0)) *intent;
@property (nonatomic, strong) INUIAddVoiceShortcutButton API_AVAILABLE(ios(12.0)) *shortcutButton;

添加shortcutButton按钮

if (@available(iOS 12.0, *)) {
    _shortcutButton = [[INUIAddVoiceShortcutButton alloc] initWithStyle:INUIAddVoiceShortcutButtonStyleWhiteOutline];
    _shortcutButton.shortcut = [[INShortcut alloc] initWithIntent:self.intent];
    _shortcutButton.translatesAutoresizingMaskIntoConstraints = false;
    _shortcutButton.delegate = self;
    [self.view addSubview:_shortcutButton];
}

设置intent属性

- (HWTakePhotoIntent *)intent API_AVAILABLE(ios(12.0)){
    if (!_intent) {
        _intent = [[HWTakePhotoIntent alloc] init];
        _intent.suggestedInvocationPhrase = @"开始改作业";   //在Siri语音设置时显示的建议设置唤起文字
    }
    return _intent;
}

设置对应delegate方法

#pragma mark - INUIAddVoiceShortcutButtonDelegate
- (void)presentAddVoiceShortcutViewController:(INUIAddVoiceShortcutViewController *)addVoiceShortcutViewController forAddVoiceShortcutButton:(INUIAddVoiceShortcutButton *)addVoiceShortcutButton API_AVAILABLE(ios(12.0)){
    addVoiceShortcutViewController.delegate = self;
    [self presentViewController:addVoiceShortcutViewController animated:YES completion:nil];
}

- (void)presentEditVoiceShortcutViewController:(INUIEditVoiceShortcutViewController *)editVoiceShortcutViewController forAddVoiceShortcutButton:(INUIAddVoiceShortcutButton *)addVoiceShortcutButton API_AVAILABLE(ios(12.0)){
    editVoiceShortcutViewController.delegate = self;
    [self presentViewController:editVoiceShortcutViewController animated:YES completion:nil];
}

#pragma mark - INUIAddVoiceShortcutViewControllerDelegate
- (void)addVoiceShortcutViewController:(INUIAddVoiceShortcutViewController *)controller didFinishWithVoiceShortcut:(INVoiceShortcut *)voiceShortcut error:(NSError *)error
API_AVAILABLE(ios(12.0)){
    [controller dismissViewControllerAnimated:YES completion:nil];
}

- (void)addVoiceShortcutViewControllerDidCancel:(INUIAddVoiceShortcutViewController *)controller API_AVAILABLE(ios(12.0)){
    [controller dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - INUIEditVoiceShortcutViewControllerDelegate
- (void)editVoiceShortcutViewControllerDidCancel:(INUIEditVoiceShortcutViewController *)controller API_AVAILABLE(ios(12.0)){
    [controller dismissViewControllerAnimated:YES completion:nil];
}

- (void)editVoiceShortcutViewController:(INUIEditVoiceShortcutViewController *)controller didUpdateVoiceShortcut:(INVoiceShortcut *)voiceShortcut error:(NSError *)error API_AVAILABLE(ios(12.0)){
    [controller dismissViewControllerAnimated:YES completion:nil];
}

- (void)editVoiceShortcutViewController:(INUIEditVoiceShortcutViewController *)controller didDeleteVoiceShortcutWithIdentifier:(NSUUID *)deletedVoiceShortcutIdentifier API_AVAILABLE(ios(12.0)){
    [controller dismissViewControllerAnimated:YES completion:nil];
}

AppDelegate.m文件中添加方法

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray> * _Nullable))restorationHandler
{
    // activityType 和 Info.plist中的NSUserActivityTypes内容对应
    if ([userActivity.activityType isEqualToString:@"HWTakePhotoIntent"]) {
        [HWNotificationCenter postNotificationName:kNotificationOpenCamera object:nil]; // 通过通知找到对应class处理activity
    }
    return YES;
}

用于在Siri中通过设定语音调起应用时处理Siri的请求。我们的项目中是打开摄像头拍照批改作业。

iOS12 Siri Known Issues

让App在iOS12中支持Siri Shortcuts(捷径)功能 和 “设置和捷径App内未列出自己App的Shortcut” 的解决办法_第4张图片
iOS12SiriKnownIssues.png

如上图红框所示,iOS12发布后已知问题之一是系统的INUIAddVoiceShortcutButton只支持默认的标题“Add to Siri”和“Added to Siri”,没有做本地化支持。此外按钮的样式也很死,无法自由自在的自定义,所以灰溜溜的只能自己来写自定义按钮了。

需求一:判断是否添加过该shortcut来区别跳转INUIAddVoiceShortcutViewController还是INUIEditVoiceShortcutViewController

当然苹果为我们提供了INVoiceShortcutCenter- (void)getAllVoiceShortcutsWithCompletion:(void(^)(NSArray * _Nullable voiceShortcuts, NSError * _Nullable error))completionHandler;方法来获得所有添加的Shortcuts或者- (void)getVoiceShortcutWithIdentifier:(NSUUID *)identifier completion:(void(^)(INVoiceShortcut * _Nullable voiceShortcut, NSError * _Nullable error))completionHandler NS_SWIFT_NAME(getVoiceShortcut(with:completion:));通过identifier查找对应的Shortcut。

我在项目中的按钮点击事件代码如下:

- (void)shortcutButtonClicked:(UIButton *)sender
{
    if (@available(iOS 12.0, *)) {
        [[INVoiceShortcutCenter sharedCenter] getAllVoiceShortcutsWithCompletion:^(NSArray * _Nullable voiceShortcuts, NSError * _Nullable error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                BOOL tempAddedShortcut = NO;
                for (INVoiceShortcut *voiceShortcut in voiceShortcuts) {
                    if ([voiceShortcut.shortcut.intent isKindOfClass:[HWTakePhotoIntent class]]) {
                        tempAddedShortcut = YES;
                        break;
                    }
                }
                self.addedShortcut = tempAddedShortcut;
                if (self.addedShortcut) {
                    INUIEditVoiceShortcutViewController *editVoiceShortcutViewController = [[INUIEditVoiceShortcutViewController alloc] initWithVoiceShortcut:voiceShortcuts[0]];
                    editVoiceShortcutViewController.delegate = self;
                    [self presentViewController:editVoiceShortcutViewController animated:YES completion:nil];
                } else {
                    INShortcut *shortcut = [[INShortcut alloc] initWithIntent:self.intent];
                    INUIAddVoiceShortcutViewController *addVoiceShortcutViewController = [[INUIAddVoiceShortcutViewController alloc] initWithShortcut:shortcut];
                    addVoiceShortcutViewController.delegate = self;
                    [self presentViewController:addVoiceShortcutViewController animated:YES completion:nil];
                }
            });
        }];
    }
}

需求二:通过INUIAddVoiceShortcutViewControllerINUIEditVoiceShortcutViewController的Delegates更新自定义Shortcut按钮状态

同样也需要用到需求一中提到的判断是否添加过当前Shortcut来更新对应的自定义Shortcut按钮样式。

“设置和捷径App内未列出自己App的Shortcut” 的解决办法

问题描述

按照上文介绍,一步步在自己的App中添加Shortcut功能成功后,我们并不能在系统的设置应用的Siri 与 搜索中看到我们刚刚添加的Shortcut,或者在捷径应用中找到。如下图:

让App在iOS12中支持Siri Shortcuts(捷径)功能 和 “设置和捷径App内未列出自己App的Shortcut” 的解决办法_第5张图片
SettingMenuWithoutShortcuts.PNG

如果我们通过上文中定义的App内的Add to Siri按钮添加用户的Shortcut到Siri成功后,我们依然可以在设置捷径应用中看到。但是如果删除添加的Shortcut,有都会消失。这显然不是我们需要的效果。

预期效果是不管用户是否在App内添加Shortcut到Siri,都应在设置捷径应用中看到。

解决办法

我们需要自己手动更新我们应用的Shortcut Suggestions的内容,这样才能在设置捷径应用中列出。

更新Shortcut Suggestions内容的代码如下。

- (void)addMenuItemShortcuts
{
    if (AVAILABLE(12.0)) {
        HWTakePhotoIntent *intent = [[HWTakePhotoIntent alloc] init];
        intent.suggestedInvocationPhrase = NSLocalizedString(@"SIRI_SHORTCUT_CORRECT_WORK", nil);
        [[INVoiceShortcutCenter sharedCenter] setShortcutSuggestions:@[[[INShortcut alloc] initWithIntent:intent]]];
    }
}

我是在AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions里做了初始化。

更新Shortcut Suggestions内容后,即使不在应用内添加Shortcut到Siri,在设置捷径应用中仍能找到应用提供的Shortcut建议。

设置中的界面如下

让App在iOS12中支持Siri Shortcuts(捷径)功能 和 “设置和捷径App内未列出自己App的Shortcut” 的解决办法_第6张图片
SettingMenuWithShortcuts.PNG

点击捷径进入后如下

让App在iOS12中支持Siri Shortcuts(捷径)功能 和 “设置和捷径App内未列出自己App的Shortcut” 的解决办法_第7张图片
SettingMenuWithShortcutsContent.PNG

如果你需要,也可以在其他需要的时候更新Shortcut Suggestions内容。

总结

Siri Shortcut大功告成

References:

iOS12 Siri Shortcuts初探

Human Interface Guidelines - SiriKit

Documentation - SiriKit

你可能感兴趣的:(让App在iOS12中支持Siri Shortcuts(捷径)功能 和 “设置和捷径App内未列出自己App的Shortcut” 的解决办法)