iOS9之前普通的App应用只能够搜索应用名称,通过搜索到的应用来打开对应的应用。而其他的内容搜索功能只能够由苹果提供的系统应用使用,如邮件、短信等。iOS9提供的搜索三剑客为:
- NSUserActivity,从iOS8开始提供用于记录App状态,在iOS9及之后,不设计隐私内容,默认是可以被手机本地搜索
- CoreSpotlight,第三方app可以通过CSSearchableItem对象将待索引的用户内容持久化到本地,供本地搜索
- web markup,允许应用在其网站上做一些markup的标记,在spotlight中进行检索
本文着重介绍CoreSpotlight的使用,另外两个使用起来相对复杂一点,在后续blog里面会再介绍。特别强调,CoreSpotlight必须是在Xcode7,iOS9上使用,若使用的不是Xcode7请自行更新Xcode,:)
1、导入framework
工程 -> Build Phases -> Link Binary With Libraries,搜索CoreSpotlight
2、引用CoreSpotlight包
在需要使用的类文件中加入
Swift写法:
import CoreSpotlight
Object-C写法:
#import <CoreSpotlight/CoreSpotlight.h>
3、将待索引的数据保存至CoreSpotlight
Swift写法:
@available(iOS 9, *) //标明该方法只适用于iOS9及以后的系统
func saveCoreSpotlightItems() {
let domain: String = "com.xxx.searchAPIs"
CSSearchableIndex.defaultSearchableIndex().deleteSearchableItemsWithDomainIdentifiers([domain]) { (error) -> Void in
} //删除已有索引,便于增加新的索引,如果此处的索引是永久不变的,可以将此处改为是否已经添加过,避免重复添加
if let filepath: String = NSBundle.mainBundle().pathForResource("Spotlight", ofType: "plist") {//此例子是从plist文件读取信息
let items: NSArray? = NSArray(contentsOfFile: filepath)
if items != nil && items!.count > 0 {
var searchableItems: Array<CSSearchableItem> = Array()
for var i: Int = 0; i < items!.count; i++ {
let item: NSDictionary = items![i] as! NSDictionary
let title: String? = item.objectForKey("title") as? String
let content: String? = item.objectForKey("content") as? String
let attributeSet: CSSearchableItemAttributeSet = CSSearchableItemAttributeSet(itemContentType: "search")
attributeSet.title = title
attributeSet.contentDescription = content
attributeSet.thumbnailData = UIImagePNGRepresentation(UIImage(named: "spot")!)
let searchItem: CSSearchableItem = CSSearchableItem(uniqueIdentifier: "healthtool", domainIdentifier: domain, attributeSet: attributeSet)
searchableItems.append(searchItem)
}
CSSearchableIndex.defaultSearchableIndex().indexSearchableItems(searchableItems, completionHandler: { (error) -> Void in
})
}
}
}
Object-C写法:
- (void)saveCoreSpotlightItems {
<span style="white-space:pre"> </span>#if __IPHONE_OS_VERSION_MAX_ALLOWED >= _IPHONE90_
<span style="white-space:pre"> </span>NSString *domain = @"com.tijianzhuanjia.kangjian.SearchAPIs";
<span style="white-space:pre"> </span>[[CSSearchableIndex defaultSearchableIndex] deleteSearchableItemsWithDomainIdentifiers:[NSArray arrayWithObject:domain] completionHandler:^(NSError * _Nullable error) {
}];
<span style="white-space:pre"> </span> <span style="white-space:pre"> </span>NSString *filepath = [[NSBundle mainBundle] pathForResource:@"Spotlight" ofType:@"plist"];
<span style="white-space:pre"> </span>if (filepath != nil && filepath.length > 0) {
<span style="white-space:pre"> </span> <span style="white-space:pre"> </span>NSMutableArray *searchableItems = [NSMutableArray array];
<span style="white-space:pre"> </span> NSArray *items = [NSArray arrayWithContentsOfFile:filepath];
<span style="white-space:pre"> </span> for (NSDictionary *item in items) {
<span style="white-space:pre"> </span> NSString *title = [item objectForKey:@"title"];
<span style="white-space:pre"> </span> NSString *content = [item objectForKey:@"content"];
<span style="white-space:pre"> </span> CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:@"search"];
<span style="white-space:pre"> </span> attributeSet.title = title;
<span style="white-space:pre"> </span> attributeSet.contentDescription = content;
<span style="white-space:pre"> </span> attributeSet.thumbnailData = UIImagePNGRepresentation([UIImage imageNamed:@"spot"]);
<span style="white-space:pre"> </span> CSSearchableItem *searchItem = [[CSSearchableItem alloc] initWithUniqueIdentifier:@"kangjian" domainIdentifier:domain attributeSet:attributeSet];
<span style="white-space:pre"> </span> [searchableItems addObject:searchItem];
<span style="white-space:pre"> </span> }
<span style="white-space:pre"> </span>if (searchableItems.count != 0) {
<span style="white-space:pre"> </span> [[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:searchableItems completionHandler:^(NSError * _Nullable error) {
}];
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>#endif
<span style="white-space:pre"> </span>}
title,contentDescription和thumbnilData字段说明,参见下图
title和contentDescription已经写在图中了,thumbnilData就是图中红色圈中的图片文件内容
4、使用saveCoreSpotlightItems方法注册
我一般喜欢把这种东西放在didFinishLaunching的方法里面,你也可以放在任何可以执行到的地方,且放在线程中执行,最小化影响主线程
Swift写法:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> Void in
if #available(iOS 9, *) {
weakSelf?.saveCoreSpotlightItems()
}
}
Object-C写法:
[NSThread detachNewThreadSelector:@selector(saveCoreSpotlightItems) toTarget:self withObject:nil]; //也可以使用GCD的写法,偷懒没有写
5、利用Spotlight直接跳转至对应的界面
至上面第四步,我们也只能像之前Spotlight搜索功能一样,只能跳转至App的首页即rootViewController,要想利用Spotlight搜索出来的项,点击直接进入指定的界面,我们还需要做额外的工作。那就是实现AppDelegate中iOS8及以后才出现的方法continueUserActivity
此处作为测试,仅直接跳转至登录界面,各位完全可以按照自己的想法,跳转至任何controller
@available(iOS 8, *)
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
let identifier: String? = userActivity.userInfo?["kCSSearchableItemActivityIdentifier"] as? String
if identifier == "healthtool" {
let currentController: UIViewController = self.getCurrentViewController()
let controller: LoginViewController = LoginViewController(nibName: "LoginViewController", bundle: nil)
currentController.navigationController?.pushViewController(controller, animated: true)
}
return true
}