Как заставить CoreSpotlight индексировать приложение Mac?
Я не могу понять, как заставить мое приложение macOS индексироваться с помощью CoreSpotlight.
import SwiftUI
import CoreSpotlight
@main
struct TestSpotlightApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: NSObject, NSApplicationDelegate {
var searchableItems = [CSSearchableItem]()
func addSearchableTerms() {
let itemSet = CSSearchableItemAttributeSet(contentType: .content)
let timerTitle = "10 min timer"
let identifier = "com.myapp.timers.10min"
itemSet.title = timerTitle
itemSet.contentDescription = timerTitle
itemSet.keywords = ["timer", "minute", "10", "ten"]
itemSet.identifier = identifier
itemSet.duration = NSNumber(integerLiteral: 10 * 60)
let searchableItem = CSSearchableItem(uniqueIdentifier:identifier, domainIdentifier: "timers", attributeSet: itemSet)
searchableItems.append(searchableItem)
// TODO: Add more timers programmatically
CSSearchableIndex.default().indexSearchableItems(searchableItems) { (error) in
if let error = error {
// handle failure
print(error)
} else {
print("Indexed: \(self.searchableItems)")
}
}
}
func applicationDidFinishLaunching(_ notification: Notification) {
addSearchableTerms()
}
}
Использованная литература:
Хорошо, если я установлю let itemSet = CSSearchableItemAttributeSet(contentType: .text) и добавлю itemSet.textContent = "10 minute timer", я увижу, что он появится как документ. Но я хочу, чтобы оно отображалось как приложение, чтобы я мог открыть глубокую ссылку на результат таймера.





Я понял, как заставить это работать, установив CSSearchableItemAttributeSet(contentType:) на что-то другое. Кажется, оба .application и .text работают. Спасибо @ATV
import Cocoa
import CoreSpotlight
@main
class AppDelegate: NSObject, NSApplicationDelegate {
var searchableItems: [String : CSSearchableItem] = [:]
func addSearchTerm(identifier: String, title: String, duration: Int, keywords: [String]) {
let itemSet = CSSearchableItemAttributeSet(contentType: .application) // or use .text
itemSet.title = title
itemSet.contentDescription = title
itemSet.keywords = keywords
itemSet.identifier = identifier
// itemSet.textContent = title
itemSet.duration = NSNumber(integerLiteral: duration)
let searchableItem = CSSearchableItem(uniqueIdentifier:identifier, domainIdentifier: "timers", attributeSet: itemSet)
searchableItems[identifier] = searchableItem
}
func addSearchableTerms() {
addSearchTerm(identifier: "com.paulsolt.SpotlightTimer.10min", title: "10 minute timer", duration: 10 * 60, keywords: ["min"])
addSearchTerm(identifier: "com.paulsolt.SpotlightTimer.3min", title: "3 minute timer", duration: 3 * 60, keywords: ["min"])
addSearchTerm(identifier: "com.paulsolt.SpotlightTimer.4min", title: "4 minute timer", duration: 4 * 60, keywords: ["min"])
// TODO: Add more timers programmatically
CSSearchableIndex.default().indexSearchableItems(Array(searchableItems.values)) { (error) in
if let error = error {
// handle failure
print(error)
} else {
print("Indexed: \(self.searchableItems)")
}
}
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
addSearchableTerms()
}
func application(_ application: NSApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any NSUserActivityRestoring]) -> Void) -> Bool {
if userActivity.activityType == CSSearchableItemActionType,
let identifier = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String {
handleSearchableItem(withIdentifier: identifier)
return true
}
return false
}
func handleSearchableItem(withIdentifier identifier: String) {
if let item = searchableItems[identifier],
let duration = item.attributeSet.duration?.intValue {
self.startTimer(duration: duration)
} else {
print("Duration not found in attributes")
}
}
func startTimer(duration: Int) {
// Your code to start the timer with the specified duration
print("Starting timer for \(duration) seconds")
}
}
Элемент будет ниже в списке в разделе «Другое» или «Документы», и только при взаимодействии он будет продвигаться по службе.
Мне интересно, имеет ли смысл вместо этого использовать NSUserActivity, но мне не удалось заставить это работать.
Хотя это работает, мне не нравится такое поведение. Было бы неплохо получить что-то вроде того, как Apple предоставляет результаты калькулятора, чтобы их можно было отображать как лучший результат. Я не знаю, возможно ли это. Я думаю, что глобальное сочетание клавиш может быть лучше, чем поиск Spotlight.
Клавиши
plistнеобходимы, когда вы используетеNSUserActivityдля поиска Spotlight. Проверьте свойcontentType, который вы передаете,.content— это общий тип, возможно, вы хотите использовать более конкретные типы. И вы всегда можете перестроить индекс Spotlight, чтобы убедиться, что он актуален.