让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类型。

SiriKitIntentDefinitionFile.png

CustomIntents.png

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

InfoPlist.png

添加Frameworks

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

Frameworks.png

添加Shortcut按钮

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

增加import

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

添加Delegate

<INUIAddVoiceShortcutButtonDelegate,
INUIAddVoiceShortcutViewControllerDelegate,
INUIEditVoiceShortcutViewControllerDelegate>

添加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<id<UIUserActivityRestoring>> * _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

iOS12SiriKnownIssues.png

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

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

当然苹果为我们提供了INVoiceShortcutCenter- (void)getAllVoiceShortcutsWithCompletion:(void(^)(NSArray<INVoiceShortcut *> * _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<INVoiceShortcut *> * _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,或者在捷径应用中找到。如下图:

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建议。

设置中的界面如下

SettingMenuWithShortcuts.PNG

点击捷径进入后如下

SettingMenuWithShortcutsContent.PNG

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

总结

Siri Shortcut大功告成

References:

iOS12 Siri Shortcuts初探

Human Interface Guidelines - SiriKit

Documentation - SiriKit

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343