Apple Siri接入开发 (一)

随着iOS10.0发布脚步的临近,作为开发者,相信很多人也和我一样,可以提前体验一些新系统的新功能,也更关注新版iOS系统带来的技术开发方面的新特性。

对新事物,尤其是软件开发新技术的好奇心驱使我最近尝试了一些iOS10.0推出的新特性的开发,其中就包括本次iOS系统更新开发的SiriKit接入。下面,我就详细讲述一下SiriKit接入的相关开发过程及注意事项,个人见解,如有错误,欢迎大家交流指正。

关于SiriKit

SiriKit是Apple历经4年时间,不断打磨优化,第一次开发给开发者的一份关于Siri功能的礼物。利用SiriKit,第三方开发者可以像一些系统应用一样,通过语音完成第三方应用希望完成的一些功能,比如用户可以直接通过语音直接告诉Siri打车、锻炼、寻找美食、寻找相册中的照片、甚至付给朋友AA的账单费用,以及控制家里智能家居等。

概念概览

  • Domain - 被苹果划分的不同业务领域,每个领域中可以执行不同的任务
  • Intent - 领域中的任务或意图指令

实现机制

和Android的语音接入Service类似,SiriKit中,将不同的类型的需求统一汇总为若干个Domain,然后在每个Domain中再次细分为不同的Intent。系统通过语音识别获取到的Domain信息以及Intent信息,下发到已注册的Domain中进行处理,然后用户解析处理不同的Intent,来实现自定义的操作。

SiriKit的接入方式和Watch OS的接入有相似之处,都是以Extension形式存在,该Extension会声明本应用所能处理的Domain内容及Intent种类,告知Siri该应用所能处理的功能范畴.这样,即便你的应用当前并没有打开或在后台运行,通过Siri也可以唤醒你的应用,处理相关逻辑。

Domains

  • VoIP Calling - 语音通信相关,如微信、Facebook Messager、Line等;
  • Payments - 适用于支付类应用,如PayPal、支付宝等;
  • Photo - 与图库相关应用,如Instagram等;
  • Workouts - 运动健康类应用,如Strava、NikeRun、野兽骑行等;
  • Ride booking - 适用于出行类应用,如Uber、滴滴打车等;
  • CarPlay(automotive vendors only)- 车载及自动驾驶相关,尚不明晰
  • Restarurant reservations(Requires addtional support from Apple) - 酒店服务类,具体需求上不明晰

Intents

  • VoIP Calling
    • Start an audio call -开始语音通话
    • Start a video call - 开始视频通话
    • Search the user’s call history -搜寻通话历史
  • Messaging
    • Send a message
    • Search for messages
    • Set attributes on a message
  • Photos
    • Search for photos
    • Play a photo slideshow
  • Payments
    • Send a payment to another user
    • Request a payment from another user
  • Workouts
    • Start a workout
    • Pause a workout
    • Resume a workout
    • End a workout
    • Cancel a workout
  • Ride Booking
    • Get a list of available rides (Maps only)
    • Book a ride
    • Get the status of a booked ride
  • CarPlay
    • Change the audio source
    • Change the climate control settings
    • Change the defroster settings
    • Saving vehicle settings to a profile
    • Restoring vehicle settings from a profile
    • Change the seat temperature
    • Change the radio station
  • Restaurant Reservations
    • Get the user’s current restaurant reservations
    • Get information about the user to associate with a booking.
    • Get default values to use when requesting reservation times.
    • Get the reservation times that are currently available.
    • Book a reservation for the user.

注意,经过开发实践,每种Domain及Intents都有固定或相似的语法形式,为增加识别度,可以参考官网说明,按照说明中自然语言语法形式唤起相应的Siri功能,例如:”用XXX开始跑步“ 要比仅仅说 “XXX开始跑步”能更好的识别出应用XXX。

由于Siri所使用的识别技术及语言模型是在云端训练并完成数据解析,可能还有些不完善。在我们刚开始开发时,就遇到了这样的问题,中文普通话的有些Intent会有支持不完整的情况,导致语音识别不出来,无法完成语义解析,相关回调方法不被调用等问题,如有大家也遇到了类似问题,建议使用英文进行测试。

对于此问题,也已经向Apple Siri开发团队反应,相关训练任务已经在进行中,很惊喜的是,在之后的开发中,有些之前不支持的Intent语义识别也已经可以使用了。

开发流程

上面简述了SiriKit的一些背景知识及实现机制,下面简单介绍一下我在接入SiriKit时使用的开发流程.

开发环境

  • MacbookPro. OSX EI Capitan 10.11.6
  • xCode 8.0 beta6(8S201h)
  • iPhone6 iOS10.0 beta6
  • iTerms2, git, etc.

支持类型

对于向现有iOS应用中加入对Siri的支持有两种形式,一种是Intents Extension,另一种是Intents UI Extension,前者没有UI界面,类似一个后台逻辑处理服务,这项Extension是必选的。

而Siri UI Extensions是可选内容,用于展示一些确认信息等操作。经负责该功能的Apple SiriKit工程师确认,UI Siri Extensions的声明周期比较短,部分应用可根据实际需要采用,但Workout类应用目前试用范围较宅,本例中未采用。

接入步骤

本次接入SiriKit开发中,采用Workout类应用,此处Workout并不是Apple WatchOS 3.0中新增的Workout App, 而是指一类运动锻炼相关应用,例如,Strava, Nike Run一类。由于Apple SiriKit中限制了7类不同的Domain,如果需要接入其他类别的应用,如天气,支付等,可以参考官方接入指南进行相关开发。

Step1. 打开应用的Siri Capability

在Xcode8中,选中应用Target,选择Capability标签,打开Siri Capability打开,如图所示:


201702072461357c303f4ab644135ea06285a.png

打开该属性后,工程文件的Entitlements文件会增加如下内容:


201702071729357c303f4ab644135ea06285b.png

Step2: 创建支持Siri的Intents Extension

首先选中App工程,为该App添加对Siri的Intents Extension支持的Target,如图:


201702075782857c303f4ab644135ea062857.png

选择Intents Extension


201702076878357c303f4ab644135ea062858.png

命名并选择是否UI Extension,可根据自我业务需求确定,本例中,对UI Extension不进行支持。


20170207372957c303f4ab644135ea062859.png

创建完成后,Siri Intents Extension的target会显示在Target列表中。

Step3: 定义所支持的Intent

该步骤相当于告诉Siri及iOS系统,本应用中所支持的Domain和Intents都有哪些,这样iOS系统及Siri就知道你的应用可以处理哪些请求,不能处理哪些请求。
打开Siri Intents Extension工程中的Info.plist文件,选中NSExtension,修改所支持的Intent类型,具体类型字符串可以查询开发文档,添加后的内容如下:


201702076763357c30921ab644133ed0638de.png

IntentsRestrictedWhileLocked是可选项,用来控制锁屏状态下,对不同命令的响应行为。

Step4:添加对主应用Siri权限支持

在主应用Info.plist文件中添加NSSiriUsageDescription Key,该key用来标记应用与Extension所沟通的数据类型,用于告知用户,你的应用为何要支持Siri的描述信息,比如Workout类应用,我可以这么写:“健身锻炼的信息会发送到Siri,更快捷的记录健身数据”

仅仅添加NSSiriUsageDescription这个Key到Info.plist文件中是不够的,当应用第一次启动时,我们需要用户打开应用的Siri支持权限,默认情况下,这个权限是关闭的,所以,需要我们通过调用INPreferences的类方法equestSiriAuthorization: 来通知用户打开Siri权限支持。

Step5. 添加逻辑

OK,到此为止,我们已经把所有接入Siri Intents Extension的前期准备工作都已经完成,现在我们要进入正题,实现相应的逻辑处理代码编写工作。
修改IntentHandling.swift文件,根据需要,修改所需要实现的协议内容:

class  IntentHandler:INExtension,INStartWorkoutIntentHandling,INPauseWorkoutIntentHandling,INResumeWorkoutIntentHandling,INEndWorkoutIntentHandling{
    ...
}

OK,到此为止,我们已经把所有接入Siri Intents Extension的前期准备工作都已经完成,现在我们要进入正题,实现相应的逻辑处理代码编写工作。
修改IntentHandling.swift文件,根据需要,修改所需要实现的协议内容:

class IntentHandler:INExtension,INStartWorkoutIntentHandling
    ,INPauseWorkoutIntentHandling,INResumeWorkoutIntentHandling
    ,INEndWorkoutIntentHandling{
    ...
}

修改所需要实现的不同场景下的逻辑回调部分,调用所在iOS App的相关业务逻辑,满足产品需求,例如

开始锻炼

/*!
@briefhandlingmethod
@abstractExecutethetaskrepresentedbytheINStartWorkoutIntentthat
    'spassedin
@discussionThismethodiscalledtoactuallyexecutetheintent
    .Theappmustreturnaresponseforthisintent.
@paramstartWorkoutIntentTheinputintent
@paramcompletionTheresponsehandlingblocktakesaINStartWorkoutIn
    tentResponsecontainingthedetailsoftheresultofhavingexecutedthe
    intent
@seeINStartWorkoutIntentResponse
*/
public func handle(startWorkoutintent:INStartWorkoutIntent,completion
    :@escaping(INStartWorkoutIntentResponse)->Swift.Void){
    print("HereisStartworkoutcalledbySiri");
}

暂停锻炼

//MARK:-INPauseWorkoutIntentHandling
/*!
@briefhandlingmethod
@abstractExecutethetaskrepresentedbytheINPauseWorkoutIntentthat
    'spassedin
@discussionThismethodiscalledtoactuallyexecutetheintent
    .Theappmustreturnaresponseforthisintent.
@parampauseWorkoutIntentTheinputintent
@paramcompletionTheresponsehandlingblocktakesaINPauseWorkoutIn
    tentResponsecontainingthedetailsoftheresultofhavingexecutedthe
    intent
@seeINPauseWorkoutIntentResponse
*/
public func handle(pauseWorkoutintent:INPauseWorkoutIntent,completion
    :@escaping(INPauseWorkoutIntentResponse)->Swift.Void){
    print("HereisPauseworkoutcalledbySiri");
}

恢复锻炼

//MARK:-INResumeWorkoutIntentHandling
/*!
@briefhandlingmethod
@abstractExecutethetaskrepresentedbytheINResumeWorkoutIntenttha
    t'spassedin
@discussionThismethodiscalledtoactuallyexecutetheintent
    .Theappmustreturnaresponseforthisintent.
@paramresumeWorkoutIntentTheinputintent
@paramcompletionTheresponsehandlingblocktakesaINResumeWorkoutI
    ntentResponsecontainingthedetailsoftheresultofhavingexecutedth
    eintent
@seeINResumeWorkoutIntentResponse
*/
public func handle(resumeWorkoutintent:INResumeWorkoutIntent
    ,completion:@escaping(INResumeWorkoutIntentResponse)->Swift.Void){
    print("HereisResumeworkoutcalledbySiri");
}

结束锻炼

//MARK:-INEndWorkoutIntentHandling
/*!
@briefhandlingmethod
@abstractExecutethetaskrepresentedbytheINEndWorkoutIntentthat's
    passedin
@discussionThismethodiscalledtoactuallyexecutetheintent
    .Theappmustreturnaresponseforthisintent.
@paramendWorkoutIntentTheinputintent
@paramcompletionTheresponsehandlingblocktakesaINEndWorkoutInte
    ntResponsecontainingthedetailsoftheresultofhavingexecutedthei
    ntent
@seeINEndWorkoutIntentResponse
*/
public func handle(endWorkoutintent:INEndWorkoutIntent,completion
    :@escaping(INEndWorkoutIntentResponse)->Swift.Void){
    print("HereisEndworkoutcalledbySiri");
}

总结

以上就完成了所有接入SiriKit的工作,剩余的应用就是测试成果,此处有一些技巧,

  • 技巧一:由于SiriKit首次发布,有些语言支持尚不完善,建议使用英文进行测试,这样可以避开一些Intent在不同语言中支持不完整的问题。
  • 技巧二:iPhone6s及以后设备已经支持了通过“Hey, Siri”语音唤醒的特性,所以用iPhone6s可以方便的不用按住Home就可进行测试,很方便,对于iPhone6 & iPhone6P,插入数据线,连接电脑,也可以通过“Hey, Siri”唤醒,直接进行相应业务需求测试。

以上就是接入SiriKit的背景知识点以及基本流程,在接入过程中,与Apple SiriKit开发团队接触过程中,发现了若干问题,也收获了许多知识,在后续文章中,我会单独抽出一篇来与大家分享。文章中间如有错误之处,欢迎大家批评指正,共同成长。

Enjoy your Siri trip.

2017年2月

参考文献

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容