Spotlight search by keywords setuped in NSUserActivity doesn't work

Hey there! I faced issue in iOS 18 and newer when Spotlight search doesn't show my App in results. In older versions it works. Here is my code:

func configureUserActivitity(with id: String, keywords: [String]) {
	let activity = NSUserActivity(activityType: id)
	activity.contentAttributeSet = self.defaultAttributeSet
	activity.isEligibleForSearch = true
	activity.keywords = Set(keywords)
	activity.becomeCurrent()
	self.userActivity = activity
}

I didn't find any reasons why it doesn't work now. Maybe I should report a bug?

That is how I setup contentAttributeSet:

var defaultAttributeSet: CSSearchableItemAttributeSet {
		let attributes = CSSearchableItemAttributeSet(contentType: .text)
		attributes.title = "MyAppName"
		return attributes
	}

Filing bug reports is always welcome, especially when you see a significant change in behavior from one major iOS version to another. Since we're chatting here, if you file that bug, please post the FB number here for my reference.

I'd like to understand the bigger picture of what you're doing with NSUserActivity — what system features are you using this for? That API typically represents what your app is doing either "right now", or at a single moment in time. Do you intend to only represent your app to Spotlight like that, or are you expecting to have the information you are providing to Spotlight be searchable for an extended period of time hours, days, weeks later? If it's the latter, you might consider some different approaches to adding your content to the Spotlight index. You can learn about those in the following resources:

— Ed Ford,  DTS Engineer

Thanks for your reply! I think that we have miscommunication a bit. I want to see my app in Spotlight search results by entering specific keywords, that I setup in activity.keywords = Set(keywords). But for now I just can find my app by name. I didn't find any changes related to NSUserActivity and iOS 18 (in earlier versions it works ok) so I decided to describe problem here. Posted bug report - FB17023996

So, I've tried to setup feature in another way - using CSSearchableItemAttributeSet and CSSearchableItem. This is my code:

func save(keywords: [String]) {
		guard let bundleId = Bundle.main.bundleIdentifier else { return }

		let items = keywords.map {
			let attributeSet = CSSearchableItemAttributeSet(itemContentType: UTType.plainText.identifier)

			if #available(iOS 18.0, *) {
				attributeSet.title = $0
				attributeSet.displayName = $0
			}
			else {
				attributeSet.title = $0
				attributeSet.displayName = self.appName
			}

			return CSSearchableItem(
				uniqueIdentifier: "\(bundleId).spotlight.\($0)",
				domainIdentifier: "\(bundleId).spotlight",
				attributeSet: attributeSet
			)
		}

		CSSearchableIndex.default().indexSearchableItems(items) { error in
			if let error = error {
				print("Spotlight indexing error: \(error.localizedDescription)")
			}
			else {
				print("Spotlight keywords indexed successfully.")
			}
		}
}

Take a look at the code block `if #available(iOS 18.0, *)`. With this code search is working, but not in the way I need - spotlight search displays a couple variants if they are similar and that is understandable, because I set `attributeSet.displayName = $0` as one of possible keywords. But if I remove block `if #available(iOS 18.0, *) {` and leave just
```swift
func save(keywords: [String]) {
		guard let bundleId = Bundle.main.bundleIdentifier else { return }

		let items = keywords.map {
			let attributeSet = CSSearchableItemAttributeSet(itemContentType: UTType.plainText.identifier)

			attributeSet.title = $0
			attributeSet.displayName = self.appName

			return CSSearchableItem(
				uniqueIdentifier: "\(bundleId).spotlight.\($0)",
				domainIdentifier: "\(bundleId).spotlight",
				attributeSet: attributeSet
			)
		}

		CSSearchableIndex.default().indexSearchableItems(items) { error in
			if let error = error {
				print("Spotlight indexing error: \(error.localizedDescription)")
			}
			else {
				print("Spotlight keywords indexed successfully.")
			}
		}
}

It won't be working on iOS 18.x versions, but will work on versions lower. Any thoughts?

My previous comment has wrong format. I can't change it, so I'll write the new one.

I've tried to setup feature in another way - using CSSearchableItemAttributeSet and CSSearchableItem. This is my code:

func save(keywords: [String]) {
		guard let bundleId = Bundle.main.bundleIdentifier else { return }

		let items = keywords.map {
			let attributeSet = CSSearchableItemAttributeSet(itemContentType: UTType.plainText.identifier)

			if #available(iOS 18.0, *) {
				attributeSet.title = $0
				attributeSet.displayName = $0
			}
			else {
				attributeSet.title = $0
				attributeSet.displayName = self.appName
			}

			return CSSearchableItem(
				uniqueIdentifier: "\(bundleId).spotlight.\($0)",
				domainIdentifier: "\(bundleId).spotlight",
				attributeSet: attributeSet
			)
		}

		CSSearchableIndex.default().indexSearchableItems(items) { error in
			if let error = error {
				print("Spotlight indexing error: \(error.localizedDescription)")
			}
			else {
				print("Spotlight keywords indexed successfully.")
			}
		}
}

Take a look at the code block if #available(iOS 18.0, *). With this code search is working, but not in the way I need - spotlight search displays a couple variants if they are similar and that is understandable, because I set attributeSet.displayName = $0 as one of possible keywords. But if I remove block if #available(iOS 18.0, *) { and leave just

func save(keywords: [String]) {
		guard let bundleId = Bundle.main.bundleIdentifier else { return }

		let items = keywords.map {
			let attributeSet = CSSearchableItemAttributeSet(itemContentType: UTType.plainText.identifier)

			attributeSet.title = $0
			attributeSet.displayName = self.appName

			return CSSearchableItem(
				uniqueIdentifier: "\(bundleId).spotlight.\($0)",
				domainIdentifier: "\(bundleId).spotlight",
				attributeSet: attributeSet
			)
		}

		CSSearchableIndex.default().indexSearchableItems(items) { error in
			if let error = error {
				print("Spotlight indexing error: \(error.localizedDescription)")
			}
			else {
				print("Spotlight keywords indexed successfully.")
			}
		}
	}

It won't be working on iOS 18.x versions, but will work on versions lower. Any thoughts? I'll add information to my FB

attributeSet.title = $0
attributeSet.displayName = self.appName

This detail is interesting. The system will know the entry is associated with your app, so setting a displayName for your app doesn't really represent the content well, that's more for unique items within the app.

Since you're trying to set up keywords for your app to help it appear in Spotlight, perhaps there's a simpler way — kMDItemKeywords in your Info.plist file. Would that achieve your goal? A colleague's thread has the details on that key.

— Ed Ford,  DTS Engineer

Spotlight search by keywords setuped in NSUserActivity doesn't work
 
 
Q