How do you get CoreSpotlight to index a Mac app?
I cannot figure out how to get my macOS App to index with 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()
}
}
References:
I figured out how to get it work by setting the CSSearchableItemAttributeSet(contentType:)
to something else. Both .application
or .text
seem to work. Thanks @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")
}
}
The item will be lower in the list under Other or Documents, and only by interacting does it seem to get promoted.
I'm wondering if it makes more sense to use a NSUserActivity
instead, but I haven't been able to get that to work.