之前把SiriKit的文档啃完了,然后找了很久也没找到完成度比较高的Demo。之前手头上比较忙就先搁置了,最近有时间可以继续了。索性自己摸石头过河,一步步试着实现。
要说SiriKit当然要先了解App Extension了,本篇先介绍一下App Extension。
App Extension
App Extension
顾名思义其是对App的扩展,自iOS8开始新增的特性。之前常见有Today(Widget)
、Custom Keyboard
、Share
,iOS9和10之后陆续又增加了不少,如最近比较热的iMessage
、Sticker
、Content Blocker
、Call Directory
以及本次要分享的SiriKit
。
特点与区别
App Extension
App Extension
在工程中以一个target存在,有自己的info.plist
,有自己的配置项,也有自己的bundle id
(如:主App的为com.company.xAppName
,那么AppExtension
通常为com.company.xAppName.xExtensionName
)。它的bundle也是独立的,bundle后缀为.appex
。
Containing App
我们的主App就是但是Containing App
了,实际上App Extension
并不是一个独立的App,它不能独立安装与卸载,他是随着主App的安装而安装、卸载而卸载的。而且提交AppStore的时候主App必须要实现一些功能。
Host App
调用Extions的App就是Host App
,比如Intent Extension
的Host App
是Siri
。
App Extension
是与Host App
进行通讯,App Extension
与Containing App
通过openUrl:
进行通讯,而Host App
与Containing App
之间就没有任何关系了,大致关系如下图:
生命周期
它的生命周期与主App也不同,App Extension
是随着用户触发了而创建和启动,用户取消操作或者离开后一段时间他会被系统自动杀死。
数据与代码共享
毕竟App Extension
与Containing App
并不是一体的,所以数据和代码上的共享是有些需要注意的。
数据共享
开启App Group
首先你需要给需要数据共享的target开启App Group并设置Group Id(只有开发者账号可以进行),注意共享数据的target的group id要勾选一样的。
如下图,我的主App target和Intent Extension的Target开启并设置了GroupId(没有group id需要先点+号增加一个)
NSUserDefaults方式共享
使用NSUserDefaults
的初始化方法initWithSuiteName:
来获取共享的NSUserDefaults
对象,再进行操作
1 | NSString *groupId = @"你取的App Group的Id"; |
NSFileManager方式共享
使用NSFileManager
对象的containerURLForSecurityApplicationGroupIdentifier:
方法,然后获取共享目录路径,再进行操作,如:
1 | NSString *groupId = @"你取的App Group的Id"; |
使用数据库
使用SQLite、CoreData等数据库进行共享,但是数据库文件还是得靠NSFileManager
来读取
主App与Extension各种路径
在主App和Extension中分别打印groupPath、bundlePath和sandyPath,可以发现,它们的groupPath是一样的,bunldePath和sandyPath都不同
1 | //---主App打印 |
代码和图片资源共享
使用Framework
将两边都会用到的代码,打成Framework,然后引入
使用CocoaPods
制作私有CocoaPods库,进行引入。Podfile注意给Intent或者IntentUI的target也加上需要的。如:
勾选target membership
对已有的一些要共用的类在右侧勾选,新建类的时候也考虑是否要勾选。
坑点
报错UserDefaults无法读写
1
2
3
4handle status: 02016-12-15 15:04:17.414706 SendMessageIntentUI[13492:1016495] [User Defaults] Failed to read values in
CFPrefsPlistSource<0x1700e9a00> (Domain: group.com.maihaoche.SiriKitTest,
User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null)):
Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd出现这个错误一般处理:
- group id配置是否错误
- 初始化NSUserDefaults方法错误
使用[[NSUserDefaults alloc] initWithSuiteName:@"xxxx"]
而非[[NSUserDefaults standardUserDefaults] initWithSuiteName:@"xxxx"]
- 以上两种均无错的时候,卸载App,clean工程,重新run。但不一定有效。😂
有些属性/方法会标注
NS_EXTENSION_UNAVAILABLE
以表明App Extension
无法使用