Showcase app data in Spotlight
System & Services 进阶 20m

在 Spotlight 中展示 App 数据

Showcase app data in Spotlight

2021年6月11日

在 Apple 官方观看视频

一句话判断

Core Spotlight 的索引和搜索能力在 iOS 15 中得到了大幅增强 —— 连续排名(Continuous Ranking)、属性权重配置、搜索建议(Suggestion)和详情视图(Detail View)让 Spotlight 终于能像一个小型的”App 内搜索”入口了。

这场 Session 讲了什么

Session 讲解了 iOS 15 中 Spotlight 搜索集成的重大更新。CSSearchableItem 的新功能包括:

  1. 排名优化(Ranking):新增 rankingSignal 属性,允许开发者指定搜索结果的排名权重。可以根据用户在 app 内的行为(浏览次数、收藏状态、最近使用时间)来影响 Spotlight 中的排序。
  2. 搜索建议(Spotlight Suggestions):用户在 Spotlight 搜索框输入时,可以在建议列表中直接展示 app 的内容。
  3. 详情视图(Detail View):Spotlight 搜索结果点击后,可以展示一个自定义的详情视图,而不只是跳转到 app。
  4. 属性权重(Attribute Weights):为搜索属性设置不同的重要性权重,让标题匹配的排名高于描述匹配。

Session 还讨论了批量索引的最佳实践、索引更新的性能优化、以及如何调试 Spotlight 索引问题。

值得深挖的点

排名信号的持续更新机制。以前 CSSearchableItem 一旦创建,排名就固定了。iOS 15 允许你通过 CSSearchableItemAttributeSetrankingSignal 属性持续更新排名。每次用户在 app 内执行某个操作(如打开一篇文章),你可以重新索引这个 item 并更新 rankingSignal。Spotlight 会在下次搜索时使用最新的排名值。但要注意:更新频率不要超过每分钟一次,否则系统会降频处理你的索引请求。

Spotlight Detail View 的实现。通过 NSUserActivitytargetContentIdentifier 和新的 Spotlight 配置,你可以定义一个内联的详情展示视图。用户在 Spotlight 中看到搜索结果时,长按或 3D Touch 会展示详情预览(类似 Live Text 的预览卡片),不需要打开 app。这个功能对内容类 app(新闻、笔记、菜谱)特别有用。

代码片段

创建带排名信号的 Spotlight 索引

import CoreSpotlight

func indexArticle(_ article: Article) {
    let attributes = CSSearchableItemAttributeSet(contentSetOf: [])
    attributes.title = article.title
    attributes.contentDescription = article.summary
    attributes.thumbnailData = article.thumbnailImageData

    // 设置排名信号:基于文章的浏览量和收藏状态
    let rankingScore = Float(article.viewCount) * 1.0
        + (article.isBookmarked ? 100.0 : 0.0)
        + Float(article.recencyScore)
    attributes.rankingSignal = rankingScore

    // 设置属性权重:标题匹配权重高于描述
    let searchableItem = CSSearchableItem(
        uniqueIdentifier: "article_\(article.id)",
        domainIdentifier: "articles",
        attributeSet: attributes
    )

    CSSearchableIndex.default().indexSearchableItems([searchableItem]) { error in
        if let error = error {
            print("索引失败: \(error)")
        }
    }
}

配置搜索建议

import CoreSpotlight

func donateSearchSuggestion(query: String) {
    // 用户在 app 内搜索时,捐赠搜索建议到 Spotlight
    let attributes = CSSearchableItemAttributeSet(contentSetOf: [])
    attributes.title = "搜索: \(query)"
    attributes.contentDescription = "在 MyApp 中搜索 '\(query)'"

    let item = CSSearchableItem(
        uniqueIdentifier: "search_\(query)",
        domainIdentifier: "suggestions",
        attributeSet: attributes
    )
    // 使用较低的排名信号,让搜索建议排在真实内容之后
    attributes.rankingSignal = 0.1

    CSSearchableIndex.default().indexSearchableItems([item])
}

处理 Spotlight 搜索结果的点击

import CoreSpotlight

// 在 AppDelegate 或 SceneDelegate 中处理
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    if userActivity.activityType == CSSearchableItemActionType {
        // 获取被点击的搜索结果 ID
        if let uniqueIdentifier = userActivity.userInfo?[
            CSSearchableItemActivityIdentifier
        ] as? String {
            // 跳转到对应的内容页面
            navigateToContent(identifier: uniqueIdentifier)
        }
    }
}

最佳实践

  1. 批量索引而不是逐条索引CSSearchableIndexindexSearchableItems 接受数组参数,每次批量提交 100-500 条比逐条索引效率高 10 倍。
  2. 定期清理过期索引。用户删除的内容要在 Spotlight 中同步移除,否则搜索到已删除的内容会严重影响信任度。用 deleteSearchableItems(withDomainIdentifiers:) 清理。
  3. rankingSignal 的数值范围要统一。如果你用 0-100 的范围,所有 item 都在这个范围内。混用不同量级(有些 0-1,有些 0-10000)会导致排名完全不可预测。

还有什么值得关注

  • Spotlight 现在支持展示 app 的 Widget 内容作为搜索结果的预览。
  • CSSearchableIndex 支持 beginBatch() / endBatch() 事务模式,确保批量操作的原子性。
  • 可以用 csquery 命令行工具在 macOS 上调试 Spotlight 索引查询。
WWDC 2021