关于iOS9的CoreSpotlight

摘要

最近在做项目的时候,刚好有一个需求是要用到iOS9所支持的一个新特性—-CoreSpotlight 来实现,所以简单记录一下CoreSpotlight 的使用方法啦啦啦~~

什么是 Spotlight

可能大家的 iPhone 或者 iPad 在更新了iOS9 之后就会发现,在主屏幕下滑,或者最左边屏幕最右滑时,可以对整个手机里的内容进行搜索。像下面这样:

iOS9 中支持为 app 中的内容做索引以支持 spotlight 搜索,并且这些索引是存在本地设备中的,不会同步到icoloud中,更换了设备就没有了

那我们需要在我们的代码里边做怎么样的支持才能让我们的 app 像微博、知乎一样支持 spotlight 对我们的内容进行搜索呢?

Spotlight 使用

使用前提

framework的导入

使用 Spotlight 的前提是要在项目里面导入以下两个库:

头文件的导入

1
2
#import <CoreSpotlight/CoreSpotlight.h>
#import <MobileCoreServices/MobileCoreServices.h>

前面也说过,Spotlight 只支持 iOS9以上版本,所以如果要适配 iOS9 以下的版本,记得一定要做好版本的判断语句,不管是在导入头文件的时候还是调用API的时候。如下:

1
2
3
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000

//code...

#endif

使用

用豆瓣电影列表为例子,demo 可让我们在 Spotlight 里面根据电影的 分类 来搜索到我们对应的电影~

定义内容类

1
2
3
4
5
6
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeImage];

attributeSet.title = temp[@"tittle"]; // 标题
attributeSet.keywords = [temp[@"category"] componentsSeparatedByString:@"/"]; // 关键字,NSArray格式
attributeSet.contentDescription = temp[@"description"]; // 描述
attributeSet.thumbnailData = UIImagePNGRepresentation([UIImage imageNamed:temp[@"image"]]); // 图标, NSData格式

CSSearchableItemAttributeSet 是一个提供给 Spotlight 搜索的内容类,我们可以设置它的各种属性,用户通过 Spotlight 搜索得到的内容样式就是由它控制的;temp 是定义了一部movie基本信息的 NSDictionary.

内容类添加到索引(可供搜索类)

想供 Spotlight 搜索得到我们的数据模型,还需要将内容类添加到可供搜索的类 CSSearchableItem 。如下:

1
CSSearchableItem *item = [[CSSearchableItem alloc] initWithUniqueIdentifier:[NSString stringWithFormat:@"%d",i] domainIdentifier:@"Zen3.CoreSpotlightDemo" attributeSet:attributeSet];

其中,

UniqueIdentifier:(nullable NSString *) 是唯一标识识别是这个索引数据的,可以理解为标识符,后面可以用于判断用户点击 Spotlight 的搜索结果,是从哪一个电影索引跳入 appDemo 的。

domainIdentifier:(nullable NSString *) 是确定这个索引数据是属于哪个“范围”的,这个范围可以用来区别不同 app 的索引数据,也可以用于区别同一个app里面不同模块的索引数据。

attributeSet:(CSSearchableItemAttributeSet *) 就是我们刚刚上面定义的。

封装索引为数组并添加

将可供搜索类 CSSearchableItem 全部添加到一个数组(NSMutableArray)里面。
将包含所有索引(可供搜索类)的数组,通过以下方法提交:

1
2
3
4
5
6
[[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:seachableItems completionHandler:^(NSError * error) {
if (error) {
NSLog(@"indexSearchableItems Error:%@",error.localizedDescription);

}
}];

完成了以上几步,你就可以通过 keyword 来搜索到你的 内容类了。那如果你想点击不同搜索结果,比如电影,进入app里面会跳转到不同的页面,你还需要做下面的事情。

不同索引不同跳转

搜索得到结果后页面的跳转实现,主要是在 AppDelegate.m 里定义的:

1
2
3
4
5
6
7
8
9
10
11
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
NSString* idetifier = userActivity.userInfo[@"kCSSearchableItemActivityIdentifier"]; //获取传入的索引数据的唯一标识

MovieDetailPage* detailPage = [[MovieDetailPage alloc] init];
detailPage.numberOfMovie = [idetifier intValue];
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
[navigationController pushViewController: detailPage animated:true];

return YES;
}

删除索引条目

关于删除索引,上文也有提起过,我们上面所做的添加提交索引操作都是在设备本地的,所以删除也是如此,有以下三种方法:

1
- (void)deleteSearchableItemsWithIdentifiers:(NSArray<NSString *> *)identifiers completionHandler:(void (^ __nullable)(NSError * __nullable error))completionHandler; 

-(void)deleteSearchableItemsWithDomainIdentifiers:(NSArray<NSString *> *)domainIdentifiers completionHandler:(void (^ __nullable)(NSError * __nullable error))completionHandler;

- (void)deleteAllSearchableItemsWithCompletionHandler:(void (^ __nullable)(NSError * __nullable error))completionHandler;

分别是根据identifier来删除,根据domain来删除以及删除所有的索引。

维护好app里面所定义提交的索引是开发者的职责,对于已经失效,或者弃用的索引,一定要及时删除,避免造成不好的用户体验。

暂时还有没有找到关于索引更新的API,知道的童鞋可以赐教一下~所以我目前对索引的更新就是使用删除旧的,添加新的的方式。

一点我遇到的坑

如果用虚拟机进行调试的话,如果遇到 indexSearchableItems 提交没有报错却搜索不到,可以重启一下虚拟机;如果更改了domainIdentifier或者UniqueIdentifier的传入值,而log出来的结果还是一样,可以尝试先删除所有之后,再次重启虚拟机试一试。

我的demo

附上我的demo地址:lzcuriosity/CoreSpotlightDemo

最后

今晚写完这篇博客,我就要出现在召唤师峡谷了啦~~哈哈哈~希望今晚能一直连胜!我准备祭出我的神级机器人了!再见~