美文网首页iOS开发之常用技术点Android精选Swifty Coding
iOS 12 新特性 Sirishortcut(捷径)调研(二)

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

作者: Boothlee | 来源:发表于2018-11-08 10:43 被阅读114次

    通过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

    相关文章

      网友评论

        本文标题:iOS 12 新特性 Sirishortcut(捷径)调研(二)

        本文链接:https://www.haomeiwen.com/subject/khebtqtx.html