iOS 9 : Search API

Ezra iOS

在 iOS 9 之前,用户只能通过 Spotlight 搜索有限的基本内容,诸如备忘录、短信等,而从 iOS 9 开始,苹果允许用户搜索活动、App 状态、App 内容甚至未安装的 App 信息,也就是这篇博客要介绍的内容—— Search API。

关于其他 iOS 9 的特性与功能,有兴趣的朋友可以参考我博客中的 iOS 9 适配系列。

我们所说的 Search API 共分为三种:

  • NSUserActivity

  • Web Markup

  • CoreSpotlight

本文主要介绍 CoreSpotlight 的基本使用(点击这里直接跳转),另外两种由于比较简单,因此只做基本概念阐述。

NSUserActivity

使用过 Handoff 功能的小伙伴们可能对 NSUserActivity 比较熟悉,因为这在 iOS 8 中专为 Handoff 推出的 API。

而在 iOS 9 中 NSUserActivity 的功能得到了显著提升,简单来说,从 iOS 9 开始用户只要在 Spotlight 中提供元数据(Metadata)即可搜索不同的 Activity(活动)。

Web Markup

Web Markup 是 iOS 9 新推出的功能,它用于在网页中显示 App 内容并编入 Spotlight 索引,也就是说即使用户并没有安装某个 App,iOS 9 也可以在网页上搜索特定标记(Markup)并在 Safari 或 Spotlight 中显示搜索结果。

如果你有兴趣你可以参考官方文档 Use Web Markup to Make App Content Searchable。

CoreSpotlight

从名字就能看出 CoreSpotlight 是一套完整的 Spotlight 框架,它允许开发者将 App 中的任意内容编入索引使得这些内容可以在 Spotlight 相关搜索结果中显示,提供更好的用户体验。

与 NSUserDefault 不同,CoreSpotlight 使用系统的存储空间,它存储的内容称为 CSSearchableItem,我们可以通过 CSSearchableItemAttributeSet 为每个 CSSearchableItem 设置属性。

要使用 CoreSpotlight,首先需要引入 CoreSpotlight.framework (在 Target => Build Phases => Link Binary With Libraries 中添加)并导入头文件:

import CoreSpotlight

接下来创建 CSSearchableItemAttributeSet 和 CSSearchableItem:

let identi = "meniny"

let attrSet = CSSearchableItemAttributeSet(itemContentType: "someType")
attrSet.title = identi
attrSet.contentDescription = "Some Description Here"
attrSet.thumbnailData = UIImageJPEGRepresentation(UIImage(named: "icon_Image")!, 0.5)

let item = CSSearchableItem(uniqueIdentifier: identi, domainIdentifier: "cn.meniny.MXSearchAPIDemo", attributeSet: attrSet)

调用 CSSearchableIndex.defaultSearchableIndex() 的 indexSearchableItems(items: [CSSearchableItem], completionHandler: ((NSError?) -> Void)?) 方法将内容编入索引:

CSSearchableIndex.defaultSearchableIndex().indexSearchableItems([item], completionHandler: { (error) -> Void in
    if error == nil {
        print("saved")
    }
})

最后,当用户点击搜索结果后,系统会自动跳转到我们的应用,因此我们需要在 AppDelegate 中 application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool 方法编写跳转后的相关逻辑:

func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
   let identifier = userActivity.userInfo?["kCSSearchableItemActivityIdentifier"] as? String

   let nav = window?.rootViewController as! UINavigationController
   nav.popToRootViewControllerAnimated(false)

   let newVC = UIViewController()
   newVC.title = identifier
   newVC.view.backgroundColor = UIColor.whiteColor()

   nav.pushViewController(newVC, animated: true)

   return true
}

此外,CoreSpotlight 还提供了三种删除索引的方法,分别是:

  • deleteSearchableItemsWithIdentifiers(identifiers: [String], completionHandler: ((NSError?) -> Void)?),根据 identifiers: [String] 删除

  • deleteSearchableItemsWithDomainIdentifiers(domainIdentifiers: [String], completionHandler: ((NSError?) -> Void)?),根据 domainIdentifiers: [String] 删除

  • deleteAllSearchableItemsWithCompletionHandler(completionHandler: ((NSError?) -> Void)?),删除全部

这三种方法通过单例 CSSearchableIndex.defaultSearchableIndex() 调用即可,十分简单不做赘述。