iOS9推出后,为了顺应时代,给自己项目加了个Spotlight搜索功能,下面是使用过程中的一点记录
在iOS9中提供了新的APIs,允许你去索引APP里面的内容或者界面状态,通过Spotlight来快速显示APP中的内容。 这些新的搜索APIs的三大组件为:
- NSUserActivity (iOS8 出现的类,提供handoff功能支持)
- Core Spotlight (新库,提供Spotlight索引APP内容的功能)
- web markup(鬼知道什么东西,看名字不像APP开发用的)
1、NSUserActivity
最开始NSUserActivity是iOS8的新特性:HandOff功能所使用的API,用于保存和复原APP的状态。由于项目对HandOff并没啥友好性,所以去年也没有太多的研究,顺道学习一下。
学习链接
简单的说,使用NSUserActivity主要有以下几点:
- unique identifier(唯一的标识符,通过此标识符,可以链接不同设备的同一APP,也是能实现HandOff功能的基础)
<key>NSUserActivityTypes</key>
<array>
<string>com.xxx.iOS-9-Search.displayShow</string>
</array>
- 保存一个UserActivity
NSUserActivity * activity = [[NSUserActivity alloc] initWithActivityType:@"com.xxx.iOS-9-Search.displayShow"];
activity.title = @"test";
activity.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:item.name, @"name", item.id, @"id", nil];
[activity becomeCurrent];
- 恢复restore
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
- update UserActivity
[activity addUserInfoEntriesFromDictionary:dic];
上面4点是NSUserActivity使用过程中需要用到的主要情景。实例化的NSUserActivity对象,可以通过属性retain住,根据情况调用update方法,更新userActivity的userInfo(dictionary)
-
其他
eligibleForHandoff,eligibleForSearch:两个属性,区分HandOff和SpotLight。expirationDate:当这个属性被设置时,你的user activity 只会在设置的时期之前才会展示在搜索结果里。
2、Core Spotlight
当然,先导入最新的库CoreSpotlight.framework
使用起来非常简单,通常在获取网络数据返回后,讲获得数据item,添加到searchIndex中。
NSMutableArray *items = [NSMutableArray array];
for (likeItem *item in self.Model.likeItems) {
CSSearchableItemAttributeSet * attrSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:@"text"];
NSString *title = item.forumName;
[attrSet setTitle:title];
NSString *desc = [NSString stringWithFormat:@"bar"];
[attrSet setContentDescription:desc];
CSSearchableItem *item = [[CSSearchableItem alloc] initWithUniqueIdentifier:item.uniqueIdentifier domainIdentifier:@"like items" attributeSet:attrSet];
[items addObject:item];
}
[[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:items completionHandler:^(NSError * _Nullable error) {
}];
添加完搜索索引以后,与userActivity相同,通过spotLight搜索到的内容,点击需要跳转到我们自己的app中,并能够跳转到对应的界面。
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
UITabBarController *tabBarController = (UITabBarController *)[self getTabBarController];
UIViewController *vc = [tabBarController viewControllerAtIndex:0];
[vc restoreUserActivityState:userActivity];
return YES;
}
3、NSUserActivity与Spotlight相结合
在iOS9中NSUserActivity类的新增特性就是contentAttributeSet属性。这个属性允许你赋予一个CSSearchableItemAttributeSet, 正如你先前创建的那个。这个属性集合(attribute set)允许NSUserActivity对象的搜索结果可以展示如同 Core Spotlight搜索结果那样的相同数量的详细信息。
但是,在尝试两者结合时,遇到了一些问题,首先,activity中构造的userInfo字典不能够搜索完了restore,userInfo中只包涵一个key:(妈蛋,为啥上不了图)
kCSSearchableItemActivityIdentifier
这个key从哪来的呢?
CSSearchableItem *item = [[CSSearchableItem alloc] initWithUniqueIdentifier:item.uniqueIdentifier domainIdentifier:@"like items" attributeSet:attrSet];
就是这句话,kCSSearchableItemActivityIdentifier的Value就是CSSearchableItem初始化时,传入的参数uniqueIdentifier
再看下文档里怎么说:
// When opening a document from Spotlight, the application's application:willContinueUserActivityWithType:
// method will get called with CSSearchableItemActionType, followed by application:continueUserActivity:restorationHandler: with an NSUserActivity where the userInfo dictionary has a single key value pair where CSSearchableItemActivityIdentifier is the key and the value is the uniqueIdentifier used when creating the item.
CORESPOTLIGHT_EXPORT NSString * const CSSearchableItemActionType CS_AVAILABLE(NA, 9_0);
CORESPOTLIGHT_EXPORT NSString * const CSSearchableItemActivityIdentifier CS_AVAILABLE(NA, 9_0);
CS_CLASS_AVAILABLE(NA, 9_0)
@interface CSSearchableItem : NSObject <NSSecureCoding, NSCopying>
- (instancetype)initWithUniqueIdentifier:(nullable NSString *)uniqueIdentifier //Can be null, one will be generated
domainIdentifier:(nullable NSString *)domainIdentifier
attributeSet:(CSSearchableItemAttributeSet *)attributeSet;
// Should be unique to your application group.
// REQUIRED since this is the way you will refer to the item to update the index / delete it from the index
// Starts with an UUID for ease of use, but you can replace it with an UID of your own before the item is first indexed if you wish.
@property (copy) NSString *uniqueIdentifier;
英文不好也能看懂,关键的方法:
application:willContinueUserActivityWithType:
会自动生成一个NSUserActivity对象,该对象的userInfo中只有一个Key,也就是上面看到的那个key。而对应的value就是在初始化CSSearchableItem时,传入的参数,相对于你的app,它必须是唯一的,同时,你可以传一个nil,但是,app会自动给你生成一个唯一的,作为restore时的唯一标识。
由此可见可以在CSSearchableItem初始化时,控制传入的参数,达到自己目的。比如,在我的项目中,我希望可以搜索两种信息,简单的说就是希望可以判断搜索内容的类型,并根据该类型跳转到对应ViewController,我是用的方法就是通过传入的uniqueIdentifier来做判断,进而根据其他参数初始化ViewController,跳转到该vc。
这样做挺low的,但是确实实现了我的需求,想来苹果不会搞出这么low的方法,先这样,等下篇文章(2)中,在对实现这个小需求中遇到的问题做进一步的探索,对NSUserActivity与Spotlight的结合问题再搞搞,搞清楚点,特别是那个userinfo字典,到底啥机制,好像初始化了没啥卵用哦,就为了多点信息?