iOS 9:介绍搜索API

介绍

在WWDC 2015上,Apple正式发布了iOS 9 。 除了许多新功能和改进之外,此更新还使开发人员有机会通过Spotlight搜索使应用程序的内容更易于发现和访问。 iOS 9中提供的新API允许您索引应用程序中的任何内容或界面状态,从而使用户可以通过Spotlight访问它。 这些新的搜索API的三个组件是:

  • NSUserActivity类,用于查看已查看的应用程序内容
  • Core Spotlight框架,该框架适用于任何应用程序内容
  • 网络标记,设计用于具有在网站上镜像的内容的应用程序

在本教程中,我将向您展示如何在自己的应用程序中使用NSUserActivity类和Core Spotlight框架。

先决条件

本教程要求您在OS X 10.10或更高版本上运行Xcode 7。 要跟我一起学习,还需要从GitHub下载入门项目。

1.使用NSUserActivity

在本教程的第一部分中,我将向您展示如何通过NSUserActivity类为应用程序的内容编制索引。 该API与去年在iOS 8中引入的Handoff功能相同,可处理保存和还原应用程序的当前状态。

如果您以前从未使用过NSUserActivity ,那么建议您先阅读我的教程 ,其中介绍Handoff和NSUserActivity的基础知识,然后再继续学习。

在编写任何代码之前,请打开starter项目并在iOS Simulator或测试设备上运行该应用程序。 在此阶段,您将看到该应用程序仅显示四个电视节目的列表以及每个节目的详细信息页面。

显示清单
查看详细

首先,打开启动程序项目并导航到DetailViewController.swift 。 用以下实现替换DetailViewController类的configureView方法:

func configureView() {
    // Update the user interface for the detail item.
    if self.nameLabel != nil && self.detailItem != nil {
        self.nameLabel.text = detailItem.name
        self.genreLabel.text = detailItem.genre
        
        let dateFormatter = NSDateFormatter()
        dateFormatter.timeStyle = .ShortStyle
        self.timeLabel.text = dateFormatter.stringFromDate(detailItem.time)
        
        let activity = NSUserActivity(activityType: "com.tutsplus.iOS-9-Search.displayShow")
        activity.userInfo = ["name": detailItem.name, "genre": detailItem.genre, "time": detailItem.time]
        activity.title = detailItem.name
        var keywords = detailItem.name.componentsSeparatedByString(" ")
        keywords.append(detailItem.genre)
        activity.keywords = Set(keywords)
        activity.eligibleForHandoff = false
        activity.eligibleForSearch = true
        //activity.eligibleForPublicIndexing = true
        //activity.expirationDate = NSDate()

        activity.becomeCurrent()
    }
}

在视图控制器中配置标签的代码未更改,但让我们逐步介绍用户活动代码:

  1. 您使用唯一标识符com.tutsplus.iOS-9-Search.displayShow创建一个新的NSUserActivity对象。 入门项目已配置为使用此标识符,因此请确保保留该标识符不变。
  2. 然后,您将userInfo字典分配给用户活动。 稍后将使用它来还原应用程序的状态。
  3. 您为活动的title属性提供一个字符串值。 这就是Spotlight搜索结果中显示的内容。
  4. 为了确保不仅可以通过标题来搜索内容,还可以提供一组关键字。 在上面的代码片段中,关键字集包括节目名称的每个单词及其类型。
  5. 接下来,设置NSUserActivity对象的许多属性,以告诉操作系统您希望将此用户活动用于什么。 在本教程中,我们仅查看API的搜索组件,因此我们禁用Handoff并启用search
  6. 最后,您可以在用户活动上调用becomeCurrent方法,此时该方法会自动添加到设备的搜索结果索引中。

在上面的实现中,您可能注意到注释中的两行。 尽管在本教程中我们将不使用这些属性,但是了解每个属性的用途很重要。

  • 通过上述实现,仅在打开应用程序后,才为每个单独的节目创建用户活动和搜索结果。 当您使用户活动eligibleForPublicIndexing ,Apple开始从用户的搜索结果监视此特定活动的使用和交互。 如果搜索结果吸引了许多用户,Apple会将用户活动提升为自己的云索引 。 一旦用户活动进入该云索引,安装了应用程序的任何人都可以搜索该活动,无论他们是否打开了该特定内容。 仅对于应用程序的所有用户均可访问的活动,才应将此属性设置为true
  • 用户活动也可以具有可选的expirationDate 。 设置此属性后,您的用户活动只会显示在指定日期之前的搜索结果中。

既然您知道如何创建一个能够在Spotlight中显示搜索结果的NSUserActivity ,您就可以对其进行测试了。 构建并运行您的应用程序,并在您的应用程序中打开一些节目。 完成此操作后,返回主屏幕(在iOS Simulator中按Command-Shift-H键 )并向下滑动或滚动到最左侧的屏幕以调出搜索视图。

开始输入您打开的节目之一的标题,您将看到它显示在搜索结果中,如下所示。

开始输入其中一部节目的标题

或者,输入您打开的节目之一的类型。 由于您已为用户活动分配了关键字,因此这也将导致该节目在搜索结果中列出。

输入其中一场演出的类型

您的应用程序的内容已由操作系统正确索引,结果显示在Spotlight中。 但是,当您点击搜索结果时,您的应用程序不会将用户带到相应的搜索结果。 它仅启动应用程序。

幸运的是,与Handoff一样 ,您可以使用NSUserActivity类在应用程序中还原正确的状态。 为了完成这项工作,我们需要实现两种方法。

如下所示,在AppDelegate类中实现application(_:continueUserActivity:restorationHandler:)方法。

func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
    let splitController = self.window?.rootViewController as! UISplitViewController
    let navigationController = splitController.viewControllers.first as! UINavigationController
    navigationController.topViewController?.restoreUserActivityState(userActivity)
    return true
}

接下来,在MasterViewController类中实现restoreUserActivityState(_:)方法。

override func restoreUserActivityState(activity: NSUserActivity) {
    if let name = activity.userInfo?["name"] as? String,
        let genre = activity.userInfo?["genre"] as? String,
        let time = activity.userInfo?["time"] as? NSDate {
        let show = Show(name: name, genre: genre, time: time)
        self.showToRestore = show
        
        self.performSegueWithIdentifier("showDetail", sender: self)
    }
    else {
        let alert = UIAlertController(title: "Error", message: "Error retrieving information from userInfo:\n\(activity.userInfo)", preferredStyle: .Alert)
        alert.addAction(UIAlertAction(title: "Dismiss", style: .Cancel, handler: nil))
        
        self.presentViewController(alert, animated: true, completion: nil)
    }
}

在撰写本文时,最新版本的Xcode 7(Beta 3)包含一个问题,正在还原的用户活动的userInfo属性可以为空。 这就是为什么我要处理任何错误并显示由操作系统返回的userInfo警报的原因。

再次构建并运行您的应用,然后搜索节目。 当您在搜索结果中点击一个节目时,该应用程序应将您直接带到详细信息视图控制器,并显示您所点击节目的当前信息。

应用程序已正确还原

2.使用Core Spotlight框架

iOS 9中提供的另一组API可以使您的内容可供用户搜索,这是Core Spotlight框架。 该框架采用数据库风格的设计,可让您提供有关要搜索的内容的更多信息。

在使用Core Spotlight框架之前,我们需要将项目与框架链接。 在“ 项目浏览器”中 ,选择项目并打开顶部的“ 构建阶段”选项卡。 接下来,展开“ 使用库链接二进制文件”部分,然后单击加号按钮。 在出现的菜单中,搜索CoreSpotlight并将您的项目链接到框架。 对MobileCoreServices框架重复这些步骤。

添加CoreSpotlight框架

接下来,要确保我们的应用提供的搜索结果来自Core Spotlight,请从测试设备或iOS模拟器中删除您的应用,并在DetailViewController类中注释掉以下行:

activity.becomeCurrent()

最后,打开MasterViewController.swift并在Show结构定义之前添加以下行:

import CoreSpotlight
import MobileCoreServices

接下来,将以下代码添加到MasterViewController类的viewDidLoad方法中:

var searchableItems: [CSSearchableItem] = []
for show in objects {
    let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String)
    
    attributeSet.title = show.name
    
    let dateFormatter = NSDateFormatter()
    dateFormatter.timeStyle = .ShortStyle
    
    attributeSet.contentDescription = show.genre + "\n" + dateFormatter.stringFromDate(show.time)
    
    var keywords = show.name.componentsSeparatedByString(" ")
    keywords.append(show.genre)
    attributeSet.keywords = keywords
    
    let item = CSSearchableItem(uniqueIdentifier: show.name, domainIdentifier: "tv-shows", attributeSet: attributeSet)
    searchableItems.append(item)
}

CSSearchableIndex.defaultSearchableIndex().indexSearchableItems(searchableItems) { (error) -> Void in
    if error != nil {
        print(error?.localizedDescription)
    }
    else {
        // Items were indexed successfully
    }
}

在测试此代码之前,让我们遍历for循环的每个步骤。

  1. 您创建一个CSSearchableItemAttributeSet对象,并传递该项目的内容类型 。 例如,如果搜索结果链接到照片,则将传入kUTTypeImage常量。
  2. 您将节目的名称分配给属性集的title属性。 就像NSUserActivity ,该标题将出现在搜索结果的顶部。
  3. 接下来,创建一个描述性字符串,并将其分配给可搜索属性集的contentDescription属性。 该字符串将显示在Spotlight中结果标题的下方。
  4. 与使用NSUserActivity一样,您可以在搜索结果中创建一组关键字。
  5. 最后,您创建一个CSSearchableItem ,它具有唯一的项目标识符,将项目分组在一起的唯一的域标识符以及属性集。 与NSUserActivity不同,后者从搜索结果返回用户活动,当用户选择搜索结果时,用于CSSearchableItem的唯一标识符是从操作系统接收到的唯一信息。 您需要使用这些标识符将您的应用还原到正确的状态。

为电视节目创建CSSearchableItem ,您可以使用默认CSSearchableIndex对象上的indexSearchableItems(_:completionHandler:)方法对它们进行索引。

生成并运行您的应用程序,您的所有节目都将被Spotlight索引。 导航到搜索视图并搜索其中一个节目。

CoreSpotlight搜索结果

Spotlight核心搜索结果的处理方法与NSUserActivity中的处理方法相同,但过程略有不同。 从搜索结果中选择CSSearchableItem ,系统会为您创建一个NSUserActivity对象,该对象包含所选项目的唯一标识符。

在您的应用程序委托的application(_:continueUserActivity:restorationHandler:)方法中,可以使用以下实现从Core Spotlight搜索结果中检索所需的信息:

if userActivity.activityType == CSSearchableItemActionType {
    if let identifier = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String {
        
        //  Use identifier to display the correct content for this search result
        
        return true
    }
}

使用Core Spotlight框架为应用程序中的内容编制索引时,一个好的做法是在不再需要它们时也删除它们。 CSSearchableIndex类提供了三种删除可搜索项的方法:

  • deleteAllSearchableItemsWithCompletionHandler(_:)
  • deleteSearchableItemsWithDomainIdentifiers(_:completionHandler:)
  • deleteSearchableItemsWithIdentifiers(_:completionHandler:)

例如,将以下代码添加到MasterViewController类的viewDidLoad方法的末尾:

CSSearchableIndex.defaultSearchableIndex().deleteSearchableItemsWithDomainIdentifiers(["tv-shows"]) { (error) -> Void in
    if error != nil {
        print(error?.localizedDescription)
    }
    else {
        // Items were deleted successfully
    }
}

再次构建和运行您的应用程序。 当您尝试搜索任何节目时,不会返回任何结果,因为它们已从索引中删除。

3.结合NSUserActivity和Core Spotlight

iOS 9中NSUserActivity类的另一个新添加是contentAttributeSet属性。 该属性使您可以分配CSSearchableItemAttributeSet ,就像之前创建的一样。 通过此属性集, NSUserActivity对象的搜索结果可以显示与Core Spotlight搜索结果相同的详细信息。

首先在DetailViewController.swift的顶部添加以下导入:

import CoreSpotlight
import MobileCoreServices

接下来,使用以下实现更新DetailViewController类中的configureView方法:

func configureView() {
    // Update the user interface for the detail item.
    if self.nameLabel != nil && self.detailItem != nil {
        self.nameLabel.text = detailItem.name
        self.genreLabel.text = detailItem.genre
        
        let dateFormatter = NSDateFormatter()
        dateFormatter.timeStyle = .ShortStyle
        self.timeLabel.text = dateFormatter.stringFromDate(detailItem.time)
        
        let activity = NSUserActivity(activityType: "com.tutsplus.iOS-9-Search.displayShow")
        activity.userInfo = ["name": detailItem.name, "genre": detailItem.genre, "time": detailItem.time]
        activity.title = detailItem.name
        var keywords = detailItem.name.componentsSeparatedByString(" ")
        keywords.append(detailItem.genre)
        activity.keywords = Set(keywords)
        activity.eligibleForHandoff = false
        activity.eligibleForSearch = true
        //activity.eligibleForPublicIndexing = true
        //activity.expirationDate = NSDate()
        
        let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String)
        attributeSet.title = detailItem.name
        attributeSet.contentDescription = detailItem.genre + "\n" + dateFormatter.stringFromDate(detailItem.time)

        activity.becomeCurrent()
    }
}

最后一次构建并运行您的应用,然后打开一些节目。 现在搜索节目时,您将看到使用NSUserActivity创建的结果包含与Core Spotlight搜索结果相同的详细程度。

NSUserActivity结果与CoreSpotlight详细信息

结论

在本教程中,您学习了如何使用NSUserActivity类和Core Spotlight框架通过iOS Spotlight访问应用程序的内容。 我还向您展示了如何使用这两个API来索引应用程序中的内容,以及当用户选择搜索结果时如何恢复应用程序的状态。

iOS 9引入的新搜索API非常易于使用,并使应用程序的内容更易于发现,并且对应用程序的用户更易于访问。 与往常一样,如果您有任何意见或问题,请将其保留在下面的评论中。

翻译自: https://code.tutsplus.com/tutorials/ios-9-introducing-search-apis--cms-24375

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值