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

@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渲染。这里创建了两种状态的视图,分别显示商品信息,和预订结果

// Prepare your view controller for the interaction to handle.
- (void)configureViewForParameters:(NSSet  *)parameters ofInteraction:(INInteraction *)interaction interactiveBehavior:(INUIInteractiveBehavior)interactiveBehavior context:(INUIHostedViewContext)context completion:(void (^)(BOOL success, NSSet  *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

你可能感兴趣的:(iOS 12 新特性 Sirishortcut(捷径)调研(二))