iOS Siri Shortcuts 快捷指令添加(Flutter)

最近公司的項目中需要加入Siri 快捷方式的功能掏颊,引入過程中遇到很多問題特此記錄。

需求

在系統(tǒng)應用“快捷指令”中添加指令驱负,無須打開原App即可調(diào)用運行功能坑质。


Flutter 部分

我的是Flutter工程,native同學可以直接跳過這部分哈

主要是使用methodChannel做通信轉發(fā)事件,安卓和iOS需要各自聲明洼滚。
以下文為例:

  Future<Map> methodChannelGainShortcutsList() async {
    ///聲明通信頻道
    const MethodChannel methodChannel =
        MethodChannel('com.xxxx.xxx.xxxxxx/runner');
    ///聲明事件
    Map result = await methodChannel.invokeMethod('gainXXXXXX');
    return result;
  }

iOS需要在AppDelegate中添加:

  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
      //meth
      let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
      let channel = FlutterMethodChannel(name: "com.xxxx.xxx.xxxxxx/runner", binaryMessenger: controller.binaryMessenger)
      channel.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
          if call.method == "gainXXXXXX" {
              ///dosthing
              result(["key":""]);//return內(nèi)容根據(jù)自己需求來
          }
          else {
              result(FlutterMethodNotImplemented)
          }
      }
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

iOS部分

接下來開始Siri Shortcuts的項目配置重窟,第一步是添加Siri Kit Intent的配置文件。
右下角加號->File



找到SiriKit Intent陆盘,Next


右下角加號,新增一個 Intent

創(chuàng)建后是這個樣子,會自動生成一個Response
Parameter里可以做很多文章危号,可以引用多種類型,自建Enum等等

Command+B build一下素邪,intent會自動生成對應的類文件外莲。

//
// IntentIntent.swift
//
// This file was automatically generated and should not be edited.
//

#if canImport(Intents)

import Intents

@available(iOS 12.0, macOS 11.0, watchOS 5.0, *) @available(tvOS, unavailable)
@objc(IntentIntent)
public class IntentIntent: INIntent {

}

@available(iOS 12.0, macOS 11.0, watchOS 5.0, *) @available(tvOS, unavailable)
@objc(IntentIntentHandling)
public protocol IntentIntentHandling: NSObjectProtocol {

    @available(*, renamed: "handle(intent:)")
    @objc(handleIntent:completion:)
    func handle(intent: IntentIntent, completion: @escaping (IntentIntentResponse) -> Swift.Void)
后面省略...

需要注意的是,有時Intents編譯緩慢兔朦,或者不同Xcode版本下偷线,會有未編譯的情況出現(xiàn)。
如下圖右側中沽甥,如果Custom Class的右側沒有出現(xiàn)箭頭声邦,則說明文件未編譯成功,需要多編譯嘗試幾次摆舟。

成功時亥曹,如下圖會有小箭頭邓了。
如果希望更改類名,同樣是修改這里Custom Class的值媳瞪,然后編譯骗炉。


接下來在General中添加Targets

搜索intents,并添加

記住勾選Include UI Extension幫你自動創(chuàng)建對應的UITarget材失,點擊Finish

注意
需要將前面創(chuàng)建的Intents.intentdefinition文件在新建的Targets中引入(將紅框內(nèi)勾選中)痕鳍。

這個時候編譯一下,會出現(xiàn)一個編譯循環(huán)問題:
編譯器提示:
Cycle inside Runner; building could produce unreliable results.
應該是在Flutter中才會出現(xiàn)龙巨。是由于編譯順序導致的循環(huán)依賴問題笼呆。

解決方法也很簡單
找到主工程 -> Build Phases ->調(diào)整順序
主要是下圖紅框內(nèi),錯序會出現(xiàn)循環(huán)依賴問題
親測按照本圖內(nèi)順序調(diào)整旨别,即可通過編譯

注意
如果IntentsSupported中沒有對應Intents類名诗赌,siriex會在快捷方式中找不到不到對應的處理函數(shù)。所以要確保類名已添加秸弛,如下圖铭若。

同時,這里會自動生成IntentHandler的類及.h.m文件递览,IntentHandler是所有Intents的處理函數(shù)的入口叼屠。
所以在NSExtensionPrincipalClass中的值也必須保留,更名時必須修改绞铃。

這里的INSendMessageIntent镜雨、INSearchForMessagesIntent、INSetMessageAttributeIntent儿捧,也會自動生成荚坞,如果功能用不上,對應代碼也可以刪除(本例用不到故刪除)

清理干凈后IntentHandler.m文件如下:

//
//  IntentHandler.m
//

#import "IntentHandler.h"
#import "XXHandler.h"
#import "XXXHander.h"

@interface IntentHandler ()

@end

@implementation IntentHandler

- (id)handlerForIntent:(INIntent *)intent {
    if([intent isKindOfClass:XXIntent.class]){
        return [[XXIntentHandler alloc]init];
    }
    if([intent isKindOfClass:XXXIntent.class]){
        return [[XXXIntentHander alloc]init];
    }
    return nil;
}

在handlerForIntent中進行類型分發(fā)

而在對應的XXXIntentHandler中菲盾,則需要重寫handleXXX與confirmXXX兩個函數(shù)颓影,這里方法名是自動生成的。

//
//  XXXIntentHandler.m
//

#import "XXXIntentHandler.h"
#import "XXXIntent.h"

@interface XXXIntentHandler()<XXXIntentHandling>
@end
@implementation XXXIntentHandler

- (void)handleXXX:(XXXIntent *)intent completion:(void (^)(XXXIntentResponse * _Nonnull))completion{
    completion( [[XXXIntentResponse alloc] initWithCode:XXXIntentResponseCodeSuccess
                                                 userActivity:nil]);
}

- (void)confirmXXX:(XXXIntent *)intent completion:(void (^)(XXXIntentResponse * _Nonnull))completion{
    completion([[XXXIntentResponse alloc] initWithCode:XXXIntentResponseCodeSuccess
                                            userActivity:nil]);
}

@end

到此就創(chuàng)建完成了懒鉴,可以進行業(yè)務方面的工作诡挂。
快捷方式的UI交互需要在siriui中自定義。

其他問題

Bundle Identifier
你的主工程和siriex临谱、siriexUI的Bundle Identifier必須符合關聯(lián)遞進關系咆畏。
舉個例子:
主工程: com.org.projectname
siriex: com.org.projectname.siriex
siriexui: com.org.projectname.siriexui

如果是修改了Bundle Identifier或者調(diào)試工程的時候需要用其他Bundle Identifier也需要修改對應是siriex、siriexui的Bundle Identifier吴裤。(App Group同理)

<NSUserActivity> has an interaction attached but it is not handled
在過去的iOS版本中是會有報錯提示旧找,在更高版本中某些情況也會有這個報錯。
在最初通常是由于找不到handlerForIntent對應實現(xiàn)麦牺。
解決方法也很簡單钮蛛,只要在handlerForIntent中return了對應類并實現(xiàn)了handleXXX方法就行鞭缭。

為什么我的Siri Shortcuts 直接打開了應用程序?不在外部執(zhí)行魏颓?
情況一:
在某些情況下岭辣,會造成這個問題,同樣也是游這個NSUserActivity類造成的錯誤甸饱。比如使用了Flutter第三方庫 flutter_siri_shortcutssiri_shortcuts沦童。
這兩個庫提供的方法,是基于以NSUserActivity實現(xiàn)的叹话,所以他們實現(xiàn)的功能是通過siri shortcuts 快速打開應用內(nèi)部實現(xiàn)偷遗,所以使用了這些庫會有這個情況出現(xiàn)。

情況二:
通常在業(yè)務邏輯中我們需要創(chuàng)建INShortcut來

INShortcut *shortcut = [[INShortcut alloc] initWithIntent:intent];
INUIAddVoiceShortcutViewController *voiceShortcutVC = [[INUIAddVoiceShortcutViewController alloc] initWithShortcut:shortcut];
voiceShortcutVC.delegate = self;
[self presentViewController:voiceShortcutVC animated:YES completion:nil];

這里一定要使用initWithIntent方法創(chuàng)建驼壶,如果使用了initWithUserActivity方法創(chuàng)建則會出現(xiàn)這個問題氏豌。
在底層中,Intent热凹、UserActivity應該是繼承關系泵喘,如果intent沒有實現(xiàn)會自動進入UserActivity相關的邏輯。

情況三:
由于快捷指令在數(shù)據(jù)安全般妙、高效纪铺、擴展性強個方面的優(yōu)勢。Apple在Siri方面對于Shortcuts功能也進行了多次迭代與擴展碟渺,導致了Siri Shortcuts也有著不同版本的支持鲜锚。

在Xcode15.3的版本中添加intents會默認Minimum Deployments為最高版本17.4(真是讓人相當無語)

當系統(tǒng)版本低于Minimum Deployments運行該快捷指令時,也會出現(xiàn)直接跳轉的問題止状。

這種情況烹棉,很容易在外部分享的快捷指令中出現(xiàn)攒霹、在老項目新增Intents擴展的過程中出現(xiàn)怯疤、在已有intents擴展但是Xcode升級后出現(xiàn)。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末催束,一起剝皮案震驚了整個濱河市集峦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抠刺,老刑警劉巖塔淤,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異速妖,居然都是意外死亡高蜂,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門罕容,熙熙樓的掌柜王于貴愁眉苦臉地迎上來备恤,“玉大人稿饰,你說我怎么就攤上這事÷恫矗” “怎么了喉镰?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長惭笑。 經(jīng)常有香客問我侣姆,道長,這世上最難降的妖魔是什么沉噩? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任捺宗,我火速辦了婚禮,結果婚禮上屁擅,老公的妹妹穿的比我還像新娘偿凭。我一直安慰自己,他們只是感情好派歌,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布弯囊。 她就那樣靜靜地躺著,像睡著了一般胶果。 火紅的嫁衣襯著肌膚如雪匾嘱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天早抠,我揣著相機與錄音霎烙,去河邊找鬼。 笑死蕊连,一個胖子當著我的面吹牛悬垃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甘苍,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼尝蠕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了载庭?” 一聲冷哼從身側響起看彼,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎囚聚,沒想到半個月后靖榕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡顽铸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年茁计,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谓松。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡星压,死狀恐怖瓶蝴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情租幕,我是刑警寧澤舷手,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站劲绪,受9級特大地震影響男窟,放射性物質發(fā)生泄漏。R本人自食惡果不足惜贾富,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一歉眷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧颤枪,春花似錦汗捡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盗胀,卻和暖如春艘蹋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背票灰。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工女阀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屑迂。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓浸策,卻偏偏與公主長得像,于是被迫代替她去往敵國和親惹盼。 傳聞我的和親對象是個殘疾皇子庸汗,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容