Introducting To Siri Shortcuts

在最新的iOS 12系统中,苹果在Siri中加入了一项新的特性-Shortcuts,这项特性允许应用程序暴露一些APP的关键功能给Siri。有了Shortcuts,可以:

  • 在Siri提供的建议中不仅可以打开APP,还可以打开APP内部的一些功能

  • 会将用户行为习惯与第三方应用关联,在合适的时机锁屏状态下给用户提供合理化的建议和提醒

  • 在Shortcuts APP中用户可以自定义一条语音,在对Siri发出语音指令时,Siri会执行预先设定好的一系列操作。

使用Shortcuts

如何给自己的APP创建Shortcuts呢?有两种创建Shortcuts的方式,其一是使用NSUserActivity,其二是使用intents

NSUserActivity

如果我们只想要通过Shortcuts打开APP的某些内容或者是在spotlight索引的内容中增加Shortcuts,那么可以简单地通过NSUserActivity实现

  • 在info.plist里添加useractivity的type
<key>NSUserActivityTypes</key> 
<array>
<string>com.myapp.name.my-activity-type</string> 
</array>
复制代码
  • donate shortcuts
        NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:@"Bobin.SiriShortCut"];
        [userActivity setEligibleForSearch:YES];
        [userActivity setEligibleForPrediction:YES];
        userActivity.title = [NSString stringWithFormat:@"购买%ld杯%@",model.productNum,model.productName];
        userActivity.suggestedInvocationPhrase = @"下单";
        userActivity.delegate = self;
        self.userActivity = userActivity;
复制代码
  • handle shortcuts

我们可以在app delegate中处理shortcuts

-(BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler 
{
    if([userActivity.activityType isEqual: @"Bobin.SiriShortCut"])
    {
        self.wkWebViewController = [[WKWebViewController alloc] init];
        self.wkWebViewController.loadUrl = userActivity.userInfo[@"url"];
        UINavigationController *pushNavigationController = [[UINavigationController alloc] initWithRootViewController:self.wkWebViewController];
        self.wkWebViewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:self action:@selector(dismissPushController)];
        [(UINavigationController *)self.window.rootViewController presentViewController:pushNavigationController animated:YES completion:nil];
    }
}
复制代码

intents

使用intent实现shortcuts可以做到更加深度定制,实现更复杂的功能,例如无需打开APP使用应用的一些功能。

  • 创建自定义intent文件

我们可以在xcode里通过File -> New File, 然后选择 “SiriKit Intent Definition File.”创建自定义的intent文件,如下图

图中category表示intent的类别,编辑器会根据我们创建的这个文件自动生成对应的intent类以及intent处理协议

@interface PayIntent : INIntent

@property (readwrite, copy, nullable, nonatomic) NSString *productName;
@property (readwrite, copy, nullable, nonatomic) NSNumber *quantity;

@end

// 处理协议
@protocol PayIntentHandling <NSObject>
@required
- (void)handleShopping:(PayIntent *)intent completion:(void (^)(PayIntentResponse *response))completion NS_SWIFT_NAME(handle(intent:completion:));

@optional
- (void)confirmShopping:(PayIntent *)intent completion:(void (^)(PayIntentResponse *response))completion NS_SWIFT_NAME(confirm(intent:completion:));

@end

复制代码
  • donate shortcuts

我们通过前面的intent类创建对应的intent类对象,然后通过INInteraction类的donate方法将动作写入shortcuts

        self.payIntent = [[PayIntent alloc] init];
        self.payIntent.productName = model.productName;
        self.payIntent.quantity = [NSNumber numberWithInteger:model.productNum];
        
        self.interaction = [[INInteraction alloc] initWithIntent:self.payIntent response:nil];
        [self.interaction donateInteractionWithCompletion:^(NSError * _Nullable error) {
            if(error)
            {
                NSLog(@"%@",error);
            }
            else
            {
                NSLog(@"donate success");
            }
        }];
复制代码
  • handle shortcuts

同样,我们可以在app delegate回调里处理shortcuts

-(BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler 
{
    PayIntent *intent = (PayIntent *)userActivity.interaction.intent;
        if(intent)
        {
            self.mainViewController = [[MainViewController alloc] init];
            UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.mainViewController];
            self.window.rootViewController = navigationController;

            self.shoppingViewController = [[ShoppingViewController alloc] init];
            //跳转并根据Intent内容来更新购物车内容
            [self.mainViewController.navigationController pushViewController:self.shoppingViewController animated:YES];
        }
}
复制代码

如果我们希望做到不打开app的情况下就执行一些app的功能,我们需要创建相应的intent extension,如果我们想要定制打开shortcuts的页面,在创建intent extension的时候可以一并选择创建intent UI extension

创建了intent extension之后,xcode会自动生成intentHandle类来处理我们之前定义的shortcuts

@interface IntentHandler () <PayIntentHandling>

@end
@implementation IntentHandler
-(void)handleShopping:(nonnull PayIntent *)intent completion:(nonnull void (^)(PayIntentResponse * _Nonnull))completion
{
    if(intent.quantity == 0)
    {
        completion([PayIntentResponse failureIntentResponseWithProductName:intent.productName]);
    }
    completion([PayIntentResponse successIntentResponseWithProductName:intent.productName]);
}

-(void)confirmShopping:(PayIntent *)intent completion:(void (^)(PayIntentResponse *response))completion NS_SWIFT_NAME(confirm(intent:completion:))
{
    completion([[PayIntentResponse alloc] initWithCode:PayIntentResponseCodeReady userActivity:nil]);
}

@end
复制代码

如果我们创建了intent UI extension,xcode还会自动生成IntentViewController类,这个类用来展示点击shortcuts后弹出的自定义UI界面

- (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 (completion) {
        completion(YES, parameters, [self desiredSize]);
    }
    
    if(interaction.intentHandlingStatus == INIntentHandlingStatusSuccess)
    {
        self.alertLabel.text = @"下单成功";
    }
}
复制代码

如此我们便实现了不用打开app,后台执行shortcuts的功能。

苹果建议,即便我们创建了intent extension来处理shortcuts,我们还是应该在app delegate回调里添加对shortcuts的处理

删除shortcuts

苹果提供了方便的API允许我们删除创建的shortcuts

  • 对于NSUseractivity实现的shortcuts
        NSUserActivityPersistentIdentifier identifier = @"persistentIdentifier";
        userActivity.persistentIdentifier = identifier;
        // 删除指定shortcut
        [NSUserActivity deleteSavedUserActivitiesWithPersistentIdentifiers:identifier completionHandler:^() {
            
        }];
        // 删除所有shortcuts
        [NSUserActivity deleteAllSavedUserActivitiesWithCompletionHandler:^() {
            
        }];
复制代码
  • 对于intent实现的shortcuts
        self.interaction = [[INInteraction alloc] initWithIntent:self.payIntent response:nil];
        self.interaction.identifier = @"identifier";
        self.interaction.groupIdentifier  = @"groupIdentifier";
        
        [INInteraction deleteInteractionsWithIdentifiers:self.interaction.identifier completion:nil];
        
        [INInteraction deleteInteractionsWithGroupIdentifier:self.interaction.groupIdentifier completion:nil];
        
        [INInteraction deleteAllInteractionsWithCompletion:nil];
复制代码

如何让Siri提供最优化建议

首先,Siri是怎样提供建议的呢?

  • 对于NSUseractivity实现的shortcuts

useractivity提供了一个属性requiredUserInfoKeys,它描述了最少的必要的用户信息以供Siri分析。

  • 对于intent实现的shortcuts

我们在定义intent文件的时候可以设置多种不同的参数组合,例如

Siri在收到用户的订单的时候,会基于上面的组合将其分解,以分析其中的规律

关于如何做到一个好的donation,苹果提供了一些建议:

  • 动作尽可能具有重复性
  • 所有的donation应当具有一致性
  • 不要包含具体的时间信息
  • 每种用户动作只需donate一次
  • 参数尽可能不要潜在依赖关系

猜你喜欢

转载自juejin.im/post/5b6fe8aae51d45666276146e