shortcuts只支持 iOS12+,而且功能也不是很强大,但是从设计思路层面看还是会往更智能开放的方面走。

下面我要做关于sirikit的三个小功能,shortcuts会放在第三个,但是这三个小功能也是目前sirikit所支持的一切, 分别是给某人发送消息,付款、shortcuts 的自定义事件

##开始准备工作 (1)所有的前提是工程需要支持siri,所以登录开发者账号,找到目标AppId,编辑,然后打开以下两个权限: Screen Shot 2018-12-24 at 7.38.45 PM.png App Groups 是保证extension中的数据和主程序中的数据互通。

Screen Shot 2018-12-24 at 7.38.54 PM.png

继续在开发者中心新建一个App Group,格式为group.xxxxx.extension,随心而定。

在主工程的info.plist中添加Privacy - Siri Usage Description,跟麦克风等其它功能一样,提示用户需要siri权限

(2)回到Xcode,新建一个siri的extension,就叫TestSiriService(步骤如下): Screen Shot 2018-12-24 at 7.26.12 PM.png Screen Shot 2018-12-24 at 7.26.24 PM.png

点击next按钮后生成SiriService文件夹,文件夹内容应该如下: Screen Shot 2018-12-24 at 7.31.11 PM.png (3)选中工程的target->Capabilities,打开下面的Siri tab和App Groups,AppGroup选择你自己刚才创建的GroupId。 Screen Shot 2018-12-24 at 7.35.28 PM.png 切换到SiriService target->Capabilities,同样打开App Groups,并选择你自己刚才创建的GroupId。这样主工程和extension都在一个group中,数据才可以互通。 ##一、使用siri发消息 (1)在siriService中的info.plist中添加如下图的字段,功能是类似全选,告诉app要使用发送消息的功能,这个是sirikit自带的默认字段 Screen Shot 2018-12-24 at 8.02.27 PM.png

(2)建立SiriTool文件,target勾选主工程和extension,保证两个位置都能使用,这个类我用于实现siriService功能的工具类

SiriTool.h
@interface SiriTool : NSObject
+ (void)sendMessage:(NSString *)message;
@end
+ (void)sendMessage:(NSString *)message {
    // 这个位置一定要用initWithSuiteName,这个方法与stand的区别就是可以在不同target相同的group中互通数据,如果使用stand,数据是不会互通的
    //  suiteName一定要是你自己申请的GroupID
    NSUserDefaults *userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.xxxxxx.extension"];
    [userDefault setValue:message forKey:@"message"];
    [userDefault synchronize];
}

(3)在ViewController中添加显示message的label:

[self.messageLabel setText:[SiriTool message]];

(4)在extension中新建SendMessageIntentHandler

SendMessageIntentHandler.h
#import <Foundation/Foundation.h>
#import <Intents/Intents.h>
NS_ASSUME_NONNULL_BEGIN

@interface SendMessageIntentHandler : INExtension

@end

NS_ASSUME_NONNULL_END
SendMessageIntentHandler.m
#import "SendMessageIntentHandler.h"
#import "ViewController.h"
#import "SiriTool.h"
#import <Intents/Intents.h>
@interface SendMessageIntentHandler()<INSendMessageIntentHandling>

@end
@implementation SendMessageIntentHandler
// 用于解析处理接收到的数据
- (void)resolveRecipientsForSendMessage:(INSendMessageIntent *)intent completion:(void (^)(NSArray<INSendMessageRecipientResolutionResult *> * _Nonnull))completion {
    NSArray<INPerson *> *recipients = intent.recipients;

    if (recipients.count == 0) {
        completion(@[[INSendMessageRecipientResolutionResult needsValue]]);
        return;
    }
    NSMutableArray<INSendMessageRecipientResolutionResult *> *resolutionResults = [NSMutableArray array];
    for (INPerson *recipient in recipients) {
        NSString *recipientName = recipient.displayName;
        if ([recipientName isEqualToString:@"小明"]) {
            [resolutionResults addObject:[INSendMessageRecipientResolutionResult successWithResolvedPerson:recipient]];
            completion(resolutionResults);
            return;
        }
    }
    
    [resolutionResults addObject:[INSendMessageRecipientResolutionResult unsupported]];
    completion(resolutionResults);
}
// 用于确认动作
- (void)confirmSendMessage:(INSendMessageIntent *)intent completion:(void (^)(INSendMessageIntentResponse * _Nonnull))completion {
    [SiriTool sendMessage:intent.content];
    NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass([INSendMessageIntent class])];
    INSendMessageIntentResponse *response = [[INSendMessageIntentResponse alloc] initWithCode:INSendMessageIntentResponseCodeReady userActivity:userActivity];
    completion(response);
}
// 发送或者取消发送回执
- (void)handleSendMessage:(INSendMessageIntent *)intent completion:(void (^)(INSendMessageIntentResponse * _Nonnull))completion {
    
    NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass([INSendMessageIntent class])];
    INSendMessageIntentResponse *response = [[INSendMessageIntentResponse alloc] initWithCode:INSendMessageIntentResponseCodeSuccess userActivity:userActivity];
    completion(response);
}
@end

(5)打开siri extension中自带的IntentHandler类,这个类的功能是处理siri听到声音的回调,为了不使这个类因为功能增加而变得复杂,我把这部分处理功能分发给SendMessageIntentHandler。如下:

- (id)handlerForIntent:(INIntent *)intent {
    if ([intent isKindOfClass:[INSendMessageIntent class]]) {
        return [SendMessageIntentHandler new];
    }
    return nil;
}

(6)开始测试,先正常跑一边程序,以授权siri功能,然后scheme选中SiriService,目标选择siri,run: Screen Shot 2018-12-24 at 8.18.57 PM.png (7)我的工程名,也就是display是"哈哈",我需要跟siri说,“使用哈哈发消息”,“给小明发”,“发送250”,这样发送成功后重新打开程序刷新消息,应该就会出现250

##二、使用siri支付

##三、自定义命令(shortcuts) (1)在主工程中新建siriKit Intent file  custom Intent 中有一个Category,这里有很多动作,但是现在好像没什么用,估计以后会做成根据语音自动识别吧。 (2)在Intent file中新建Intent,命名为EnterRoom,并新建一个参数,叫name,这个是一个变量,你可以在程序中去设置它: image.png (3)之后这个intent会根据你所选的选项,在指定的target中动态生成类,类名为EnterRoomIntent.h这样子: image.png 根据需要,勾选在哪个target中自动生成,或者干脆不勾选target (4)新建EnterRoomIntentHandler,与上面的handle功能一样,处理自定义事件逻辑

@interface EnterRoomIntentHandler : INExtension

@end
#import "EnterRoomIntentHandler.h"
#import "EnterRoomIntent.h"
#import "SiriTool.h"
@interface EnterRoomIntentHandler()<EnterRoomIntentHandling>
@end
@implementation EnterRoomIntentHandler
- (void)handleEnterRoom:(EnterRoomIntent *)intent completion:(void (^)(EnterRoomIntentResponse *response))completion NS_SWIFT_NAME(handle(intent:completion:)) {
    [SiriTool setRoomName:intent.name[0]];
    NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass([EnterRoomIntent class])];
    EnterRoomIntentResponse *response = [[EnterRoomIntentResponse alloc] initWithCode:EnterRoomIntentResponseCodeSuccess userActivity:userActivity];
    completion(response);
}
@end

(5)在ViewController中添加快捷添加语音唤起功能,iOS12中新添加了一个siri Button,为了添加自定义语音。这个自定义语音随便定义,我的是,“进入小明的直播间”

INUIAddVoiceShortcutButton *siriButton = [[INUIAddVoiceShortcutButton alloc] initWithStyle:INUIAddVoiceShortcutButtonStyleBlack];
[siriButton setFrame:CGRectMake(50, 250, 130, 40)];
[self.view addSubview:siriButton];
[siriButton addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
- (void)buttonAction {
    if (@available(iOS 12.0, *)) {
        EnterRoomIntent *intent = [EnterRoomIntent new];
        // 这个name就是intent file中的name变量,可以在EnterRoomIntentHandler中获取
        [intent setName:@"小明"];
        INShortcut *shortcut = [[INShortcut alloc] initWithIntent:intent];
        INUIAddVoiceShortcutViewController *viewController = [[INUIAddVoiceShortcutViewController alloc] initWithShortcut:shortcut];
        [viewController setModalPresentationStyle:UIModalPresentationFormSheet];
        [viewController setDelegate:self];
        [self presentViewController:viewController animated:YES completion:nil];
    } else {
        // Fallback on earlier versions
    }
}

(6)运行程序,“进入小明的直播间”

demo: https://github.com/Alienchang/SiriKit-shortcuts-demo