需求来源:
      我的iwatch上安全的楼兰宝盒,平时虽然可以用语音来打开这个app,但是打开后主界面上的按钮操作实在是蛋疼,这不仅仅是这个app的问题,iwatch操作只是面实在是小,用手指望点击很容易误按,本来想启动车了,有时却会按了开锁窗。于是想到用语音来控制 ,但是Siri只能打开主程序,无法和应用程序中功能进行交互,把这个意见提给楼兰宝盒的开发者,回复是暂时实现不了。于是我抽空对SiriKit做了一番测试。

测试过程:
     关于基本SiriKit的介绍,网上有太多的介绍,www.cocoachina.com上和developer.apple.com都可以搜索到,基本原理的生命周期等不用再介绍了。在我的调试过程中可以证实,很多文章都是浅尝辄止,或者拿别人的文章改来的,有的文章中引用的代码竟然一段是objectc,一段是swift,关键点几乎没有说清楚的。
     我直接写测试过程,关键点我会详细说明我测试的过程。
     环境:mac os 10.12.4 Beta 4/xcode 8.3 beta4/iphone7/IOS 10.3 beta 4
     因为不同版本的swift语法和类库不兼容,很多已经不存在方法需要自己用其它方法代替。

一.新建一个single view application,在info中把localiztion改成china。(很多文章中提示要改很多info.plist文件,其实默认的设置已经支持。)

在Capabilites中把Siri权限打开:

在主视图中加一个label,内容随意。编译,在真机上运行,使这个初始的app部署到真机上(希望你看到主视图上的Label内容能完全显示)。

点击TARGET左下角的+弹出新的TARGET选择窗口,选中IntentsExtension

给它起个名字同时选中IntentsUI Extension,完成。同时把localiztion都设成China

现在进入编码阶段,按照文档介绍,IntentsExtension只支持6种场景,但是实际上,只要其中的SendMessage协议,就可以完成各种功能,你把要输入的内容放在消息体中,然后在应用中解析消息体,什么样的参数完成不了呢?比如我想解决的问题就是打开车助理这个应用然后接受“启动”,“停止”,“开门窗”,“锁门窗”这些命令,你只要判断消息体中的内容对应到调用应用中的各个功能就行了。
      另外SendMessage协议的recipients参数还可以帮助你准确校验命令目标,也就是说你可以确认当前Siri的交互是发给你这个应用中存在的联系人的。
      关于INVocabulary关键词,为了帮助siri准确识别,把关键词放在INVocabulary中是一个好方法,特别是发送目标。为了准确判断Siri是否识别出发送目标,你应该起一个通讯录中不存在的并且发音识别度高的关键词放在INVocabulary止境中,如我为车助理这个应用内置了两个消息接受者:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        //内置联系人
        let orderSet = NSMutableOrderedSet()
        orderSet.add("助理小妹")
        orderSet.add("助理小哥")
        INVocabulary.shared().setVocabularyStrings(orderSet, of:.contactName)
        
        //请求Siri的访问权限
        INPreferences.requestSiriAuthorization{
            authorizationStatus in
            switch authorizationStatus {
            case .authorized:
                print("Authorized")
            default:
                print("Not Authorized") //弹出窗口提醒用户去 设置->Siri->允许的程序->打开车助理的对Siri权限
            }
        }
        return true
    }

编译重新运行主程序。
   对于其它事件是否要处理要看每个应用的需求,我这个应用就是要接受Siri发给应用的内容,所以在IntentsExtension说可以发送了吗?你说发送。
SiriIntentsUIExtension就会调用handle方法,你在获取语音捕获的内容就在这里处理,Apple建议是,因为你的
IntentsExtension的中调用的功能绝大多数在主程序中同样会调用,所以建议你把这段逻辑代码写在EmbeddedFramework中,当然这是代码组织的问题,在测试阶段我们不太关注。
所以我们直接在handle中实现:
    func handle(sendMessage intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
        // Implement your application logic to send a message here.
        var dict:[String:String] = Dictionary()
        if let rs = intent.recipients, rs.count > 0{
            let person = rs[0]
            dict["name"] = person.displayName
        }
        if let text = intent.content,!text.isEmpty{
            dict["message"] = text
        }
        
        let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
        userActivity.userInfo = dict
        userActivity.becomeCurrent()
        print("向\(dict["name"]!)发消息:\(dict["message"]!)")
        if (dict["message"]!.range(of: "测试失败") != nil) { // 利用userActivity与主程序交互数据
            let response = INSendMessageIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
            completion(response)
        }else{
            let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity)
            completion(response)
        }
    }

这里有个关键点,如果你仅在INVocabulary中添加了关键词“助手小妹”,在你说“车助理发消息给助手小妹”时,可以帮助Siri准确分析语法结构,但是如果通讯录中没有助手小妹这个联系人,
intent.recipients[0]这个对象中所有字段是空的,在默认的
IntentsUIExtension交互界面上也不会显示To:的内容,如果你不介意接受人,只介意消息内容,可以不要建立一个真实的通讯录,但这样仍然有意义,Siri在分析“车助理发消息给助手小妹”时可以准确地从INVocabulary关键词中找到并知道它是一个宾语而不是内容。你可以在测试时把这个关键词从INVocabulary中去掉,试一下识别率。
   真实的处理过程仅是这一句: 
print("向\(dict["name"]!)发消息:\(dict["message"]!)"),你在调试时如果看到控制台显示这一行,说明它已经正确工作,这和你调用任何启动命令的行为没有区别。
   调试关键点:要调用handle方法,你应该选择IntentsExtension,而不是
IntentsUIExtension,也不是主程序。才能看到print的输出,你要看哪个target的输出就要选择哪
target调试。调试主程序时,主程序在手上打开后,自己调出Siri,调
IntentsExtension和
IntentsUIExtension时,选择连接主程序。

关于
NSUserActivity,很多人不知道SiriKit中
NSUserActivity如何和主程序交互,也没有一篇文章中写到,其实
NSUserActivity的功能和Handoff中一样,只是
IntentsUI如何转到主视图的问题。
上面所有的事件中,只要你告诉
IntentsUIExtension当前处理失败,返回
.failureRequiringAppLaunch这个code,
IntentsUI就会把控制权交给主程序来处理,这时
NSUserActivity就可以用来传递上下文了,上面的例子中,我专门加了一断测试逻辑,只要你发送的内容是“测试失败”,Siri就会让你打开主程序处理:

要在主程序中接受
NSUserActivity上下文,需要在
AppDelegate中增加相应的委托函数:

//Siri发送失败会打开APP处理会调用些方法。
    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
        let alert = UIAlertController();
        alert.title = "Handle userActivity"
        let dict:[String:String] = userActivity.userInfo as! Dictionary
        alert.message = "name: \(dict["name"]!) \r\n message: \(dict["message"]!)"
        alert.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.cancel, handler: nil))

let alertWindow = UIWindow(frame: UIScreen.main.bounds)
        alertWindow.rootViewController = UIViewController()
        alertWindow.windowLevel = UIWindowLevelAlert + 1;
        alertWindow.makeKeyAndVisible()
        alertWindow.rootViewController?.present(alert, animated: true, completion: nil)

return true
    }

我在这里只是把这handle中捕获的内容弹出来了:

其它的调试注意点:我为IntentsUI定制了一个界面,默认的界面是保留IntentsUIExtension中留给你的(用户界面),然后在下面绘制系统默认界面进行交互。很难看,所以我把系统默认隐藏了,只要让
IntentViewController类继承INUIHostedViewSiriProviding并实现

var displaysMessage: Bool {
        return true
    }这个代理方法,就可以隐藏默认系统界面,然后我在用户界面上自己加了控件显示交互内容:


自定义界面的代码:
    // Prepare your view controller for the interaction to handle.
    func configure(with interaction: INInteraction!, context: INUIHostedViewContext, completion: ((CGSize) -> Void)!) {
        // Do configuration here, including preparing views and calculating a desired size for presentation.
        let intent = interaction.intent as! INSendMessageIntent
        name.text = intent.recipients?[0].displayName
        messageText.text = intent.content
        if let completion = completion {
            completion(self.desiredSize)
        }
    }

把交互介面底色改成蓝色,防止在调试时误识别,如果你说“车助理发消息给助手小妹”,“车助理”三个字说早了,Siri只识别了“发消息给助手小妹”,实际上它是发短信给“助手小妹”,这时其实并不是调用你“车助理”主程序内置的Intents,界面就不是你设置的这个。用蓝色可以分清楚它到底是不是在和你的应用在交互。

SiriKit测试全攻略相关推荐

  1. 安卓单元测试全攻略,让代码测试一劳永逸

    本文讲的是 安卓单元测试全攻略,让代码测试一劳永逸, 安卓单元测试,只看这一篇就足够啦.真正的完全解析,真正的从0到1,Junit结合Mockito与Robolectric实现从M到V再到P,Jaco ...

  2. 组策略分发软件全攻略

    组策略分发软件全攻略 在规模比较大的网络环境里面,为了对服务器和客户机上的软件.系统补丁进行集中统一的管理,我们可能会用到SUS.WSUS.SMS等.SUS.WSUS管理系统更新,不在本文讨论,请参考 ...

  3. [RHEL5企业级Linux服务攻略]--第3季 DHCP服务全攻略

    1 DHCP原理  1.1 DHCP概述 DHCP(Dynamic Host Configuration Protocal)就是动态主机配置协议哈,可以自动配置主机的IP地址.子网掩码.网关及DNS等 ...

  4. iSCSI存储技术全攻略

    什么是iSCSI iSCSI(iSCSI = internet Small Computer System Interface )是由IEETF开发的网络存储标准,目的是为了用IP协议将存储设备连接在 ...

  5. Gradle脚本基础全攻略

    转载http://blog.csdn.net/yanbober/article/details/49314255 [工匠若水 http://blog.csdn.net/yanbober 转载请注明出处 ...

  6. [RHEL5企业级Linux服务攻略]--第6季 Vsftpd服务全攻略之常规配置

    1.vsftpd服务软件包 vsftpd-2.0.5-10.el5.i386.rpm:vsftpd主程序包 2.vsftpd相关文档 /etc/vsftpd/vsftpd.conf:vsftpd的核心 ...

  7. [RHEL5企业级Linux服务攻略]--第2季 Samba服务全攻略答疑贴

    回答mlk0416第一个问题: 现在我以joy用户登录samba,如果不用重启系统或注销用户的方法解决多用户切换问题,关闭后重新登录samba还是会以joy帐号登录.现在我们用windows命令提示符 ...

  8. Windows Home Server中文版使用全攻略

      新一代数字家庭中枢<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /& ...

  9. Linux下的文件共享全攻略系列之一:Samba服务器简介与快速配置指南

    目前,研究者们开发了许多网络服务和协议来完成资源共享的功能.对于网络用户和管理员来说,他们希望得到免费和高效的服务,而这种需求的最好选择莫过于当前开源的操作系统Linux下的产品了.本专题从多个应用服 ...

  10. synergy在Windows和Linux下使用全攻略(多台PC共享一套键盘鼠标)

    synergy在Windows和Linux下使用全攻略(多台PC共享一套键盘鼠标) 标签: windowslinuxkeyboard服务器测试 2011-11-26 14:51 6882人阅读 评论( ...

最新文章

  1. python用django连接mysql_三分钟了解Django如何连接Mysql数据库
  2. SSH secure shell 权威指南(转载)
  3. 【论文笔记】CNN for NLP
  4. Github 开源项目(一)websocketd (实战:实时监控服务器内存信息)
  5. x264 struct 学习
  6. 理解C#泛型运作原理
  7. python中的线程之semaphore信号量
  8. rose顺序图转换为协作图_如何用GX Developer编程软件编写SFC顺序功能图?
  9. 继承(引用~析构~virtual)
  10. Unity 之 自定义编辑器布局
  11. 国产WMS仓库管理系统排名
  12. Machine Learning读书会 面试算法讲座 创业活动 算法班 历届汇总
  13. Android名片识别
  14. 某人将1000元存入银行 某公司需用一台设备 某企业为了建一项目 建设期3年,共贷款700万元
  15. 比林志玲cute的katee
  16. 如果通过这次面试我们单位录用了你,但工作一段时间却发现你根本不适合这个职位,你怎么办?
  17. web项目经理手册-项目经理需要铭记在心的话
  18. PMP项目管理—质量情景题
  19. 山外KL26的J-link连接与程序下载
  20. 妈,别再乱买保健品了!

热门文章

  1. iOS跳转到设置和其他APP的那些事
  2. 狂神SpringBoot静态资源文件
  3. KMPlayer如何设置H.264硬解
  4. 国美易卡围绕数据云等科技,国美易卡解决问题
  5. FillRect与FrameRect
  6. 计算机创造奇迹的英语作文,大学英语作文:创造奇迹 Creating Miracle
  7. 推荐一款专家级网站流量分析软件-逆火(Nihuo)
  8. 摘果子问题(聚沙成塔问题)
  9. windows 7系统中单独添加北京时区办法
  10. 牛客练习赛53 (E 老瞎眼 pk 小鲜肉) 线段树+离线