如何为你的 App 增加系统搜索索引

322 阅读4分钟

前言

不知道大家平时会不会用系统的 Spotlight 来搜索某个应用,也就是在桌面上下拉出现的搜索框,我们可以添加一些关键字来索引到我们的 App,方便用户找到,比如搜索“穿搭”这个词,就会出现淘宝和小红书等应用,实际上淘宝和小红书内置了大量的关键词来索引他们的 App。

其实这个功能在 iOS 9 就已经出了,只是大家平时可能不会注意到,今天就来聊聊如何为你的 App 添加 Spotlight 索引。

Core Spotlight

向系统搜索添加索引主要用到的框架是 Core Spotlight,支持通过添加关键词来使 App 内容可被用户搜索到。

Core Spotlight API 设置之后只会在用户单台设备上生效,也就是说其内容不会与用户的其他设备共享或在设备 iCloud 之间同步。

按照官方的说法,Core Spotlight 支持设置几千个(甚至更多),但是用户搜索某个关键词会不会出现在搜索结果中完全由系统决定。

代码部分

比如我的 App 名字叫 iOS 新知,我希望当用户搜索“iOS 开发、swift 编程、swiftUI、iOS 学习”等关键词时,出现我的应用,看下代码实现部分。

首先在你的项目中导入 CoreSpotlight

然后在需要添加索引的地方写入以下代码:

let id = "com.iOSNew.app.search-index"
let domain = "com.iOSNew.app.domain"
let activityType = "com.iOSNew.app.search_id"
let itemSet: CSSearchableItemAttributeSet
if #available(iOS 14.0, *), let type = UTType(activityType) {
    itemSet = CSSearchableItemAttributeSet(contentType: type)
} else {
    itemSet = CSSearchableItemAttributeSet(itemContentType: activityType)
}

itemSet.title = "iOS 新知"
itemSet.contentDescription = "这是描述部分,填写你需要的描述"
itemSet.contactKeywords = ["iOS 开发", "swift编程", "swiftUI", "iOS 学习"]
if let url = URL(string: "iosnew://") {
    itemSet.url = url
}
let item = CSSearchableItem(uniqueIdentifier: id, domainIdentifier: domain, attributeSet: itemSet)
CSSearchableIndex.default().indexSearchableItems([item]) { error in
    if let error {
        print("写入索引出错了 error is : \(error)")
    } else {
        print("写入索引成功")
    }
}

id 是这个搜索索引的唯一标识,后续如果有对这个索引操作的需求会用到,比如删除索引。

domain 是域标识,方便把相似的索引项目分组。

contactKeywords 是关键词,字符串数组,如果你愿意,可以写很多个。

这段代码可以在任意时机写入,比如在 App 启动的时候。最后看一下写入之后的效果,尝试在系统搜索中输入你的关键字:

默认情况下,通过这种方式写入的搜索索引有效期只有一个月,如果想设置有效期可以修改 expirationDate 属性,比如我设置为 distantFuture,表示永远不过期。

let item = CSSearchableItem(uniqueIdentifier: id, domainIdentifier: domain, attributeSet: itemSet)
item.expirationDate = .distantFuture

另外系统还提供了删除索引的办法:

删除所有索引:

CSSearchableIndex.default().deleteAllSearchableItems() { error in
    if let error {
        print("索引删除失败 error is: \(error)")
    } else {
        print("索引删除成功!")
    }
}

根据某个 id 删除索引:

CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: [id]) { error in
    if let error {
        print("\(id) 索引删除失败 error is: \(error)")
    } else {
        print("\(id) 索引删除成功!")
    }
}

根据某个 domain 删除索引:

CSSearchableIndex.default().deleteSearchableItems(withDomainIdentifiers: [domain]) { error in
    if let error {
        print("\(domain) 索引删除失败 error is: \(error)")
    } else {
        print("\(domain) 索引删除成功!")
    }
}

监听从索引中打开 App 的行为

当用户搜索到我们的项目并点击结果,这将启动我们的 App 并传入被点击的索引信息,然后会调用 AppDelegate 中的 application(_:continue:restorationHandler:) 方法,我们可以在这个方法中捕获到相关的事件和一些携带进来的信息,以做下一步操作使用,比如跳转到某个页面:

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    if userActivity.activityType == CSSearchableItemActionType {
        
        let userInfo = userActivity.userInfo
        let id = userInfo?["kCSSearchableItemActivityIdentifier"] as? String
        let kw = userInfo?["kCSSearchQueryString"] as? String
        
        print("用户点击索引进来:id is : \(id), 关键词:\(kw)")
    }
    return true
}

能走到这个回调方法的不仅仅是索引,比如 Universal Link 也会走到,所以这里加了一个判断,类型为 CSSearchableItemActionType 才做处理,之后我们从携带的 userInfo 中获取到对应的 id 和关键字等信息,以进行下一步操作。

目前为止,一个系统索引就被加好了,用户能够方便的打开你的应用,但是请注意,Apple 官方文档表示,iOS 将自动监控用户与你的搜索结果交互的频率,如果数据索引不当,或者用户根本不会通过某个索引点进你的 App,那么你的结果可能会停止出现

点击下方公众号卡片,关注我,每天分享一个关于 iOS 的新知识

本文同步自微信公众号 “iOS新知”,每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!