iOS12 SiriKit新特性 shortcuts(一)(Objective-C版本)


iOS12 的SiriKit添加了新特性shortcuts,相當於玩電腦時用戶設置快捷鍵一個道理,比如我設置ctrl+f10為打開記事本,設置成功后,我每次直接按ctrl+f10都可以快速打開記事本。

shortcuts這次有兩種用法,第一種為設置快捷語(shortcut,下同)后,通過Siri直接回到應用,在回到應用時可以獲取設置快捷語時所攜帶數據,可依據該數據或不依據該數據自動進行下一步操作。

第二種用法為設置擴展頁面,不進入app以完成應用的簡單操作功能,如:發信息/下單等。

今天先簡單介紹一下第二種用法,先看一下效果,如下圖:

 新建個SIngle View APP,命名:GotoSiri,語言為:Objective-C

再在File->New->Target->Intents Extension ,記得勾選include UI Extension,后期需要顯示擴展頁面。命名:Ticket,創建完成后需點擊兩次Activate。

工程目錄中出現如下兩個文件夾:

接下來需要創建intents.intentdefinition文件,看名字像自定義意圖,其實很雞肋。

New File->SiriKit Intent Definition File

 

新添加一個名為Test的Intent,創建好后運行一次程序,再點擊Test,在下圖標注區會看到剛才設置好的意圖文件名TestIntent,點擊右側箭頭會進入TestIntent.h頭文件中,后期用這個自定義的TestIntent意圖時需要引入的頭文件。

 

在ViewController.m文件中,引入“TestIntent.h”和<Intents/Intents.h>兩個頭文件。

#import "ViewController.h"
#import "TestIntent.h"
#import <Intents/Intents.h>

@interface ViewController ()<TestIntentHandling, INUIAddVoiceShortcutViewControllerDelegate>

@property(nonatomic,strong) INUIAddVoiceShortcutViewController *customShortCutViewController;

@property(nonatomic,strong) TestIntent *testIntent;
@property(nonatomic,strong) TestIntentResponse *testIntentResponse;

@property(nonatomic,strong) INInteraction *interaction;

@property(nonatomic,strong) INShortcut *shortcut;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    self.title = @"SiriTest";
    if (@available(iOS 10.0, *)) {
        
        [INPreferences requestSiriAuthorization:^(INSiriAuthorizationStatus status) {
            switch (status) {
                case INSiriAuthorizationStatusNotDetermined:
                    NSLog(@"用戶尚未對該應用程序作出選擇。");
                    break;
                case INSiriAuthorizationStatusRestricted:
                    NSLog(@"此應用程序無權使用Siri服務");
                    break;
                case INSiriAuthorizationStatusDenied:
                    NSLog(@"用戶已明確拒絕此應用程序的授權");
                    break;
                case INSiriAuthorizationStatusAuthorized:
                    NSLog(@"用戶可以使用此應用程序的授權");
                    break;
                default:
                    break;
            }
            
        }];
    }

    
    UIButton *_addSiriBtn = [[UIButton alloc] initWithFrame:CGRectMake(30, 151, 200, 50)];
    [_addSiriBtn setTitle:@"Add to Siri(Intent)" forState:UIControlStateNormal];
    [_addSiriBtn setTitleColor:UIColor.blueColor forState:UIControlStateNormal];
    [_addSiriBtn addTarget:self action:@selector(buildShortcutInCurrentViewController) forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:_addSiriBtn];
}

-(void)buildShortcutInCurrentViewController
{
    self.testIntent = [[TestIntent alloc] init];
    self.testIntent.ticket = @"深圳灣體育館王力宏演唱會";
    self.testIntent.number = [NSNumber numberWithInteger:2];
    self.testIntent.suggestedInvocationPhrase = @"買票";
    
    self.interaction = [[INInteraction alloc] initWithIntent:self.testIntent response:nil];
    [self.interaction donateInteractionWithCompletion:^(NSError * _Nullable error) {
        if(error)
        {
            NSLog(@"%@",error);
        }
        else
        {
            NSLog(@"donate success");
        }
    }];
    
    INShortcut *shortCut = [[INShortcut alloc] initWithIntent:self.testIntent];
    self.customShortCutViewController = [[INUIAddVoiceShortcutViewController alloc] initWithShortcut:shortCut];
    self.customShortCutViewController.delegate = self;
    [self presentViewController:self.customShortCutViewController animated:YES completion:nil];
}

-(void)addVoiceShortcutViewControllerDidCancel:(INUIAddVoiceShortcutViewController *)controller
{
    [controller dismissViewControllerAnimated:YES completion:nil];
}

-(void)addVoiceShortcutViewController:(INUIAddVoiceShortcutViewController *)controller didFinishWithVoiceShortcut:(INVoiceShortcut *)voiceShortcut error:(NSError *)error
{
    [controller dismissViewControllerAnimated:YES completion:nil];
}

- (void)handleTest:(nonnull TestIntent *)intent completion:(nonnull void (^)(TestIntentResponse * _Nonnull))completion {
    NSString *ticket = intent.ticket;
    self.testIntentResponse = [TestIntentResponse successIntentResponseWithTicket:ticket];
    completion(self.testIntentResponse);
}

-(void)confirmTest:(nonnull TestIntent *)intent completion:(nonnull void (^)(TestIntentResponse * _Nonnull))completion
{
    NSString *ticket = intent.ticket;
    self.testIntentResponse = [TestIntentResponse successIntentResponseWithTicket:ticket];
    completion(self.testIntentResponse);
}


@end

千萬別忘記修改三個Info.plist文件

GotoSiri中的info.plist,

 

 

Ticket中的info.plist,

 

 

 TicketUI中的info.plist,

在IntentHandler.m文件中:

#import "IntentHandler.h"
#import "TestIntent.h"

@interface IntentHandler ()<TestIntentHandling>

@end

@implementation IntentHandler

- (id)handlerForIntent:(INIntent *)intent {
    // This is the default implementation.  If you want different objects to handle different intents,
    // you can override this and return the handler you want for that particular intent.
    return self;
}

- (void)handleTest:(TestIntent *)intent completion:(void (^)(TestIntentResponse * _Nonnull))completion {
    if(intent.number == 0)
    {
        completion([TestIntentResponse failureIntentResponseWithTicket:intent.ticket]);
    }
    completion([TestIntentResponse successIntentResponseWithTicket:intent.ticket]);
}

-(void)confirmTest:(TestIntent *)intent completion:(void (^)(TestIntentResponse * _Nonnull))completion
{
    completion([[TestIntentResponse alloc] initWithCode:TestIntentResponseCodeReady userActivity:nil]);
}


@end

在TicketUI的MainInterface.storyboard中畫個簡單界面

 

IntentViewController.m中:

#import "IntentViewController.h"
#import <Intents/Intents.h>
#import "TestIntent.h"

// As an example, this extension's Info.plist has been configured to handle interactions for INSendMessageIntent.
// You will want to replace this or add other intents as appropriate.
// The intents whose interactions you wish to handle must be declared in the extension's Info.plist.

// You can test this example integration by saying things to Siri like:
// "Send a message using <myApp>"

@interface IntentViewController ()
@property (weak, nonatomic) IBOutlet UILabel *testlabel;

@end

@implementation IntentViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

#pragma mark - INUIHostedViewControlling

// 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.
    
    TestIntent *intent = (TestIntent *)interaction.intent;
    self.testlabel.text = [NSString stringWithFormat:@"購買%@張%@門票",intent.number,intent.ticket];
    
    if (completion) {
        completion(YES, parameters, [self desiredSize]);
    }
    
    if(interaction.intentHandlingStatus == INIntentHandlingStatusSuccess)
    {
        self.testlabel.text = @"###123###";
    }
}

- (CGSize)desiredSize {
    CGSize customSize = [self extensionContext].hostedViewMaximumAllowedSize;
    customSize.height = 200.0;
    return customSize;
}

@end

 

運行程序, 即可查看效果,此為原著,轉發請標明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM