本文翻译自 shinobicontrols iOS9 Day-by-Day :: Day 1 :: Search APIs
在iOS9之前,你只能在Spotlight中通过名称来找到应用。随着iOS9新的搜索API的公布,Apple现在允许开发者来选择应用中想要索引的内容,还有结果在Spotlight中展示的方式,以及当用户点击一个结果时发生什么。
NSUserActivity API是在iOS8中为Handoff引入的,而在iOS9中则允许搜索activity。你现在可以为这些activity提供元数据,这意味着Spotlight就可以索引它们。它的工作方式和浏览网页时的历史记录类似。用户可以在Spotlight中快速打开最近的activity。
Web Markup允许那些在网站上镜像展示内容的应用在Spotlight中索引内容。用户无需安装应用,也能在Spotlight中展示结果。Apple的索引器会在你的网站上查找特定的markup。然后这会在Safari和Spotlight中展示给用户。
即使你的应用没有安装,也能显示搜索结果,这能增加给潜在用户曝光你的应用的机会。你的应用中公开给搜索API的深度连接会保存在Apple的云端索引中。关于Web Markup更多的信息,参见Apple的文档 Use Web Markup to Make App Content Searchable 。
CoreSpotlight是iOS9的新框架,能让你索引你的应用中的任何内容。NSUserActivity可以用来保存用户的历史,使用它你就可以索引任何你想要的数据。CoreSpotlight主要提供了在用户设备上对CoreSpotlight索引的底层访问。
NSUserActivity 和 WebMarkup API使用起来相对简单,而CoreSpotlight则有一点复杂。为了展示CoreSpotlight API是如何使用的,我们会 创建一个简单的应用来展示朋友的列表,当你点击他们的名字时会展示一个头像。你可以在GitHub( Swift 或 Objective-C )上找到代码,跟着我们一起来试试吧。
应用有一个简单的storyboard, FriendTableViewController
展示了朋友名字的列表, FriendViewController
展示了每个朋友的详情。
朋友的全部信息都保存在类 Datasource
中。在这里我们会创建model并保存朋友的信息,同时也会在这里处理保存信息到CoreSpotlight 索引里的逻辑。
首先,我们重写类 Datasource
的 init()
方法,在这我们创建并保存一个放 Persion
对象的数组。你可能会从数据库或者服务器来加载此类数据,但我们只是展示,创建一些假数据就可以了。
override init () { let becky = Person() becky.name = "Becky" becky.id = "1" becky.image = UIImage(named: "becky")! ... people = [becky, ben, jane, pete, ray, tom] }
在数据都存进 people
数组里之后, Datasource
就可以使用了。
数据准备好之后, FriendTableViewController
可以创建一个 Datasource
的实例,用于table view的cell的展示。
let datasource = Datasource()
在 cellForRowAtIndexPath
方法中, 可以像下面这样在cell中展示内容:
let person = datasource.people[indexPath.row] cell?.textLabel?.text = person.name
现在假数据已经有了,我们可以使用iOS9的新API将它们保存到Core Spotlight中。回到类 Datasource
,我们定义了一个 savePeopleToIndex
方法。 FriendTableViewController
可以在view加载完成后调用这个方法。
在这个方法中,我们遍历了 people
数组中的每个人,为每个人创建了一个 CSSearchableItem
,并把这些item保存到一个叫 searchableItems
的临时数组里。
let attributeSet = CSSearchableItemAttributeSet(itemContentType: "image" as String) attributeSet.title = person.name attributeSet.contentDescription = "This is an entry all about the interesting person called (person.name)" attributeSet.thumbnailData = UIImagePNGRepresentation(person.image) let item = CSSearchableItem(uniqueIdentifier: person.id, domainIdentifier: "com.ios9daybyday.SearchAPIs.people", attributeSet: attributeSet) searchableItems.append(item)
最后一步是在默认的 CSSearchableIndex
上调用 indexSearchableItems
。这实际上就是将item保存到 CoreSpotlight 中,这样用户在搜索的时候就能展示结果了。
CSSearchableIndex.defaultSearchableIndex().indexSearchableItems(searchableItems, completionHandler: { error -> Void in if error != nil { print(error?.localizedDescription) } })
当你运行应用时,这些数据就会保存了。当你在Spotlight中搜索时,你的朋友的信息就会出现。
现在用户能在Spotlight上看到你的结果啦,很可能他们也会点击结果。但是点击时会发生什么呢?就目前来说,点击结果只会打开你的应用的主界面。如果你希望展示用户点击的朋友,那还需要一点额外的工作。当应用是用这种方式打开时,我们可以通过AppDelegate中UIApplicationDelegate方法来指定应用的行为。
下面是这个方法的完整实现:
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool { // Find the ID from the user info let friendID = userActivity.userInfo?["kCSSearchableItemActivityIdentifier"] as! String // Find the root table view controller and make it show the friend with this ID let navigationController = (window?.rootViewController as! UINavigationController) navigationController.popToRootViewControllerAnimated(false) let friendTableViewController = navigationController.viewControllers.first as! FriendTableViewController friendTableViewController.showFriend(friendID) return true }
你能看到,我们之前用 indexSearchableItems
方法保存到CoreSpotlight中的信息,现在可以在 userActivity.userInfo
字典中获取。 在本例中,我们只关心friend ID,它在索引中是保存在item的 kCSSearchableItemActivityIdentifier
下的。
在我们从 userInfo
字典中提取出所需的信息后,我们找到应用的navigation controller,pop to root(不使用动画,这样用户就不会注意到),然后 friendTableViewController
调用 showFriend
方法。关注这个方法如何工作的细节就不讲了,主要就是用给定的ID在数据源中找到对应的friend,然后在navigation controller的栈上push一个新的view controller。 这些就是全部了。现在当用户在Spotlight中点击一个结果时,他们就能看到下面这样的:
x
现在你能看到,在你的应用的左上角会有一个“Back to Search”的选项。点击它,用户就可以直接返回最开始的搜索界面。用户也可以点击通常的返回按钮在应用中跳转。
在上面的例子中,我们看到了将你的应用的数据整合到 CoreSpotlight
索引中是多简单,通过这种方法让用户打开你的应用是多强大,对用户查找特定信息来说是多方便。
但是我们还没有讲到如何从索引中删除数据。你应该尽量保持你的应用的索引数据是最新的,这很重要。关于如何在CoreSpotlight中删除旧的实体,可以看看 deleteSearchableItemsWithIdentifiers
、 deleteSearchableItemsWithDomainIdentifiers
和 deleteAllSearchableItemsWithCompletionHandler
方法。
可能看起来在Spotlight和Safari中尽可能多地出现是个不错的主意,但是在将索引填满你的信息之前最好还是仔细考虑一下。在iOS生态系统中表现良好,不仅对于保持用户开心很重要,同时Apple也会注意到。Apple在保护相关内容上显然投资不少,搜索结果的出现率会被追踪,垃圾信息会被移到搜索结果的最下面。
关于新的搜索API的更多信息,我推荐观看WWDC session 709, Introducing Search APIs . 你可能对 NSUserActivity Class Reference 和 documentation for CoreSpotlight 也感兴趣。别忘了,如果你想试试本文里讲到的内容,可以在GitHub( Swift 或 Objective-C )上找到代码。