通過Intents創(chuàng)建捷徑
intents的方式實(shí)現(xiàn)捷徑度帮,可以做更深一步的定制曙强,甚至無需打開APP使用應(yīng)用的一些功能
首先創(chuàng)建Intents.intentdefinition文件
通過File -> New File, 然后選擇 “SiriKit Intent Definition File.”創(chuàng)建自定義的intent文件莉恼,步驟如下圖:
創(chuàng)建好的intent文件如下:
每一個intent都對應(yīng)一個response如下圖:
創(chuàng)建完成后囚枪,編譯Intents.intentdefinition關(guān)聯(lián)的target xcode會自動生成對應(yīng)的類文件发笔,但是在工程中找不到類文件缸榛,可以通過如下方法查看:
編譯后xcode自動生成的類文件如下:
類文件包含QuickOrderCoffeeIntent類實(shí)現(xiàn)以及 QuickOrderCoffeeIntentHandling協(xié)議和 QuickOrderCoffeeIntentResponse類等所需要的內(nèi)容吝羞。
下面就可以在工程中直接 #import "QuickOrderCoffeeIntent.h"使用。
這里我們想要在用戶再點(diǎn)擊來一單的時候内颗,創(chuàng)建快捷下單的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如果沒有關(guān)聯(lián)到主工程的target钧排,要先進(jìn)行關(guān)聯(lián)
自定義intent的內(nèi)容到此就結(jié)束了,下面需要結(jié)合Intent Extension 和Intent UI Extension深度定制捷徑均澳。
添加Intents Extension 和Intents Extension UI
通過target添加Siri擴(kuò)展 new -> target 如下圖:
這里新建名為QuickOrder的target 同時勾選 UI Extentsion如下圖
這時就會同時創(chuàng)建Siri Extentsion 和 Siri ExtentSion UI 兩個target如下圖:
接下來需要修改Extentsion 和Extentsion UI 目錄下的info.plist 將之前自定義的type注冊進(jìn)去卖氨,如下圖
下面來看一下創(chuàng)建的Extentsion 和Extentsion UI
IntentHandler 類,導(dǎo)入自定義的Intent 遵循協(xié)議
#import "QuickOrderCoffeeIntent.h"
NS_ASSUME_NONNULL_BEGIN
@interface QuickOrderIntentHandler : INExtension<QuickOrderCoffeeIntentHandling>
@end
NS_ASSUME_NONNULL_END
實(shí)現(xiàn)如下兩個方法
- (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)
- 確認(rèn)(Confirm)
-
處理(Handle)
shortcut 沒有了Siri解析的過程会烙,會直接進(jìn)行 confirm 和 handle
這里對應(yīng)confirmQuickOrderCoffee 和 handleQuickOrderCoffee
confirm階段
預(yù)訂咖啡首先確認(rèn)登錄狀態(tài),如果沒有登錄 可以拋出自定義未登錄的code QuickOrderCoffeeIntentResponseCodeFaiureUnLogin 提供給UI層做相關(guān)處理你可以根據(jù)程序所處的狀態(tài)碼筒捺,渲染對應(yīng)的UI柏腻,如果是未登錄可以打開APP進(jìn)行登錄(QuickOrderCoffeeIntentResponseCodeFailureRequiringAppLaunch)
在進(jìn)行庫存的判斷 如果沒有庫存 拋出 QuickOrderCoffeeIntentResponseCodeFailureOutOfStock
一系列檢查之后,下單的條件滿足了 我們可以返回 QuickOrderCoffeeIntentResponseCodeReady
handle階段
可以進(jìn)行下單的請求系吭,處理完成后五嫂,如果下單成功,可以回調(diào) QuickOrderCoffeeIntentResponseCodeSuccess
以上就是下單的大概流程
IntentViewController 類 作為自定義UI的視圖控制器肯尺,可以根據(jù)下單的步驟沃缘,做相關(guān)的UI渲染。這里創(chuàng)建了兩種狀態(tài)的視圖则吟,分別顯示商品信息槐臀,和預(yù)訂結(jié)果
// 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];
//設(shè)置寬高
[[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];
//設(shè)置寬高
[[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]);
}
}
}
以上方法 根據(jù) IntentHandler類中返回的狀態(tài)code,做對應(yīng)的UI渲染
code 如果是系統(tǒng)自動創(chuàng)建的氓仲,會和 interaction.intentHandlingStatus 相互對應(yīng)水慨。如果是自定義的code,他們的 intentHandlingStatus 都對應(yīng)INIntentHandlingStatusSuccess
可以參考如下代碼做相關(guān)處理
if ([interaction.intentResponse isKindOfClass:[QuickOrderCoffeeIntentResponse class]]) {
QuickOrderCoffeeIntentResponse *quickOrderResponse = (QuickOrderCoffeeIntentResponse *)interaction.intentResponse;
if (quickOrderResponse.code == QuickOrderCoffeeIntentResponseCodeFaiureUnLogin) {
///MARK:未登錄操作
} else if (quickOrderResponse.code == QuickOrderCoffeeIntentResponseCodeFailureOutOfStock) {
///MARK:沒有庫存
}
}
核心的功能到這里就算完成了敬扛∥鳎回到最開始的需求,我們希望在用戶點(diǎn)擊再來一單的時候啥箭,生成快捷下單的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) {
}];
}
}
我們還可以引導(dǎo)用戶將快捷下單的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到這里就算完成了谍珊。