iOS 12 新特性 Sirishortcut(捷径)调研(二)

通过Intents创建捷径

intents的方式实现捷径,可以做更深一步的定制,甚至无需打开APP使用应用的一些功能

首先创建Intents.intentdefinition文件

通过File -> New File, 然后选择 “SiriKit Intent Definition File.”创建自定义的intent文件,步骤如下图:

Sirishortcut_new_intent.jpg

创建好的intent文件如下:

Sirishortcut_intent_content.jpg

每一个intent都对应一个response如下图:

Sirishortcut_response_content.jpg

创建完成后,编译Intents.intentdefinition关联的target xcode会自动生成对应的类文件,但是在工程中找不到类文件,可以通过如下方法查看:

Sirishortcut_look_info.jpg

编译后xcode自动生成的类文件如下:


Sirishortcut_Intent_class_info.jpg

类文件包含QuickOrderCoffeeIntent类实现以及 QuickOrderCoffeeIntentHandling协议和 QuickOrderCoffeeIntentResponse类等所需要的内容。

下面就可以在工程中直接 #import "QuickOrderCoffeeIntent.h"使用。
这里我们想要在用户再点击来一单的时候,创建快捷下单的shortcut

- (void)donateInteraction {
    if (@available(iOS 12.0, *)) {
        QuickOrderCoffeeIntent *quickOrderIntent = [[QuickOrderCoffeeIntent alloc] init];
        quickOrderIntent.name = @"CafeAmericano";
        quickOrderIntent.kind = @"Americano";
        INInteraction *interaction = [[INInteraction alloc] initWithIntent:quickOrderIntent response:nil];
        [interaction donateInteractionWithCompletion:^(NSError * _Nullable error) {
            
        }];
    }
}

自定义的Intent如果没有关联到主工程的target,要先进行关联
自定义intent的内容到此就结束了,下面需要结合Intent Extension 和Intent UI Extension深度定制捷径。

添加Intents Extension 和Intents Extension UI

通过target添加Siri扩展 new -> target 如下图:

Sirishortcut_new_target.jpg

这里新建名为QuickOrder的target 同时勾选 UI Extentsion如下图

Sirishortcut_new_ui_target.jpg

这时就会同时创建Siri Extentsion 和 Siri ExtentSion UI 两个target如下图:

Sirishortcut_target_list.jpg

接下来需要修改Extentsion 和Extentsion UI 目录下的info.plist 将之前自定义的type注册进去,如下图

Sirishortcut_infoPlist_type_string.jpg

下面来看一下创建的Extentsion 和Extentsion UI
IntentHandler 类,导入自定义的Intent 遵循协议

#import "QuickOrderCoffeeIntent.h"
NS_ASSUME_NONNULL_BEGIN

@interface QuickOrderIntentHandler : INExtension<QuickOrderCoffeeIntentHandling>

@end

NS_ASSUME_NONNULL_END

实现如下两个方法

- (void)confirmQuickOrderCoffee:(QuickOrderCoffeeIntent *)intent completion:(void (^)(QuickOrderCoffeeIntentResponse *response))completion NS_SWIFT_NAME(confirm(intent:completion:)) {
    NSLog(@"%s",__func__);
    if (!isLogin) {//如果没有登录 则返回之前定义的code QuickOrderCoffeeIntentResponseCodeFaiureUnLogin
        QuickOrderCoffeeIntentResponse *unLoginResponse = [[QuickOrderCoffeeIntentResponse alloc] initWithCode:QuickOrderCoffeeIntentResponseCodeFaiureUnLogin userActivity:nil];
        completion(unLoginResponse);
    } else {
        if (haveProduct) {//如果有库存  返回ready
            QuickOrderCoffeeIntentResponse *readyResponse = [[QuickOrderCoffeeIntentResponse alloc] initWithCode:QuickOrderCoffeeIntentResponseCodeReady userActivity:nil];
            completion(readyResponse);
        } else { //抛出没有库存的code返回
            QuickOrderCoffeeIntentResponse *outOfResponse = [[QuickOrderCoffeeIntentResponse alloc] initWithCode:QuickOrderCoffeeIntentResponseCodeFailureOutOfStock userActivity:nil];
            completion(outOfResponse);
        }
    }
    QuickOrderCoffeeIntentResponse *defaultResponse = [[QuickOrderCoffeeIntentResponse alloc] initWithCode:QuickOrderCoffeeIntentResponseCodeFailure userActivity:nil];
    completion(defaultResponse);
}

- (void)handleQuickOrderCoffee:(nonnull QuickOrderCoffeeIntent *)intent completion:(nonnull void (^)(QuickOrderCoffeeIntentResponse * _Nonnull))completion {
    NSLog(@"%s",__func__);
    QuickOrderCoffeeIntentResponse *quickOrderresonse = [[QuickOrderCoffeeIntentResponse alloc] initWithCode:QuickOrderCoffeeIntentResponseCodeSuccess userActivity:nil];
    completion(quickOrderresonse);
}

下面讲解一下上述代码做了什么
Intent处理程序涉及三个步骤:

  • 解析(Resolve)
  • 确认(Confirm)
  • 处理(Handle)
    shortcut 没有了Siri解析的过程,会直接进行 confirm 和 handle
    这里对应confirmQuickOrderCoffeehandleQuickOrderCoffee

confirm阶段
预订咖啡首先确认登录状态,如果没有登录 可以抛出自定义未登录的code QuickOrderCoffeeIntentResponseCodeFaiureUnLogin 提供给UI层做相关处理你可以根据程序所处的状态码,渲染对应的UI,如果是未登录可以打开APP进行登录(QuickOrderCoffeeIntentResponseCodeFailureRequiringAppLaunch)
在进行库存的判断 如果没有库存 抛出 QuickOrderCoffeeIntentResponseCodeFailureOutOfStock
一系列检查之后,下单的条件满足了 我们可以返回 QuickOrderCoffeeIntentResponseCodeReady
handle阶段
可以进行下单的请求,处理完成后,如果下单成功,可以回调 QuickOrderCoffeeIntentResponseCodeSuccess
以上就是下单的大概流程

IntentViewController 类 作为自定义UI的视图控制器,可以根据下单的步骤,做相关的UI渲染。这里创建了两种状态的视图,分别显示商品信息,和预订结果

Sirishortcut_UI_Class@2x.jpg
// Prepare your view controller for the interaction to handle.
- (void)configureViewForParameters:(NSSet <INParameter *> *)parameters ofInteraction:(INInteraction *)interaction interactiveBehavior:(INUIInteractiveBehavior)interactiveBehavior context:(INUIHostedViewContext)context completion:(void (^)(BOOL success, NSSet <INParameter *> *configuredParameters, CGSize desiredSize))completion {
    // Do configuration here, including preparing views and calculating a desired size for presentation.
    
    if (interaction.intentHandlingStatus == INIntentHandlingStatusReady) {
        [self.view addSubview:self.quickOrderVC.view];
        [self.quickOrderVC.view setTranslatesAutoresizingMaskIntoConstraints:NO];
        //设置宽高
        [[self.quickOrderVC.view.widthAnchor constraintEqualToAnchor:self.view.widthAnchor] setActive:YES];
         [[self.quickOrderVC.view.heightAnchor constraintEqualToAnchor:self.view.heightAnchor] setActive:YES];
         [[self.quickOrderVC.view.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] setActive:YES];
         [[self.quickOrderVC.view.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:YES];
        
        [self.quickOrderVC didMoveToParentViewController:self];
        if (completion) {
            completion(YES, parameters, [self desiredSize]);
        }
    } else if (interaction.intentHandlingStatus == INIntentHandlingStatusSuccess) {
        [self.view addSubview:self.orderResultVC.view];
        [self.orderResultVC.view setTranslatesAutoresizingMaskIntoConstraints:NO];
        //设置宽高
        [[self.orderResultVC.view.widthAnchor constraintEqualToAnchor:self.view.widthAnchor] setActive:YES];
        [[self.orderResultVC.view.heightAnchor constraintEqualToAnchor:self.view.heightAnchor] setActive:YES];
        [[self.orderResultVC.view.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] setActive:YES];
        [[self.orderResultVC.view.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:YES];
        [self.orderResultVC didMoveToParentViewController:self];
        if (completion) {
            completion(YES, parameters, [self desiredSize]);
        }
    }
    else {
        if (completion) {
            completion(NO, parameters, [self desiredSize]);
        }
    }
}

以上方法 根据 IntentHandler类中返回的状态code,做对应的UI渲染
code 如果是系统自动创建的,会和 interaction.intentHandlingStatus 相互对应。如果是自定义的code,他们的 intentHandlingStatus 都对应INIntentHandlingStatusSuccess
可以参考如下代码做相关处理

    if ([interaction.intentResponse isKindOfClass:[QuickOrderCoffeeIntentResponse class]]) {
        QuickOrderCoffeeIntentResponse *quickOrderResponse = (QuickOrderCoffeeIntentResponse *)interaction.intentResponse;
        if (quickOrderResponse.code == QuickOrderCoffeeIntentResponseCodeFaiureUnLogin) {
            ///MARK:未登录操作
        } else if (quickOrderResponse.code == QuickOrderCoffeeIntentResponseCodeFailureOutOfStock) {
            ///MARK:没有库存
        }
        
    }

核心的功能到这里就算完成了。回到最开始的需求,我们希望在用户点击再来一单的时候,生成快捷下单的shortcut
donate 的代码如下:

- (void)donateInteraction {
    if (@available(iOS 12.0, *)) {
        QuickOrderCoffeeIntent *quickOrderIntent = [[QuickOrderCoffeeIntent alloc] init];
        quickOrderIntent.name = @"CafeAmericano";
        quickOrderIntent.kind = @"Americano";
        INInteraction *interaction = [[INInteraction alloc] initWithIntent:quickOrderIntent response:nil];
        [interaction donateInteractionWithCompletion:^(NSError * _Nullable error) {
            
        }];
    }
}

我们还可以引导用户将快捷下单的shortcut添加到Siri短语

- (void)addShortcutsToSiri {
    if (@available(iOS 12.0, *)) {
        QuickOrderCoffeeIntent *quickOrderIntent = [[QuickOrderCoffeeIntent alloc] init];
        INShortcut *shortcut = [[INShortcut alloc] initWithIntent:quickOrderIntent];

        INUIAddVoiceShortcutViewController *vc = [[INUIAddVoiceShortcutViewController alloc] initWithShortcut:shortcut];
        vc.delegate = self;
        [self presentViewController:vc animated:YES completion:nil];
    }
}

通过Intent的方式定义Sirishortcut到这里就算完成了。

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

推荐阅读更多精彩内容