Guidance Implementing IndexedEntity and CSSearchableItemAttributeSet

I am working to add Spotlight indexing for my app entities as discussed in WWDC24's video "What's New in App Intents".

That video goes over the IndexedEntity protocol and the integration with Spotlight via CSSearchableItemAttributeSet.

What I'm seeing though does not match the video. In the video, the presenter goes through the sort of progressive approach you can take to getting this data into Spotlight starting with the basics and then expanding to include more support depending on how much the developer wants to do.

What I'm seeing is that if you conform to IndexedEntity, your entities will appear in Spotlight using the name derived from

public var displayRepresentation: DisplayRepresentation

So, that works. Name appears... BUT the next part of the video goes into how to expand your implementation with more metadata for Spotlight via CSSearchableItemAttributeSet. The issue I'm seeing is that once that's implemented, the items disappear from Spotlight, almost like that implementation is overriding the base implementation in a way that no longer functions.

My expectation is that an item with custom attributes would use them in Spotlight as appropriate, not disappear from search, i.e. what's shown in the video should work.

I've got a sample project here:

https://hanchor.s3.amazonaws.com/misc/IndexingTest.zip

To reproduce with the sample:

  1. Build and run. Indexing is setup in the init() method so it will just run.
  2. Go to Spotlight and search for 'Huntersblau', a string included in the content set. At this point you should see a result - good!
  3. Stop the app and go back and uncomment the var attributeSet: CSSearchableItemAttributeSet implementation in IndexingTestApp.swift. This will provide custom attributes to Spotlight.

Repeat steps 1 and 2 - you'll see now, it no longer appears in the search results - when CSSearchableItemAttributeSet is implemented, the item drops out of Spotlight.

Answered by Hunter in 815606022

After spending some time talking with DTS and reviewing the updated App Intent sample code located here https://developer.apple.com/documentation/appintents/acceleratingappinteractionswithappintents, I've got my answer.

The sample provides one way to integrate Spotlight, by indexing a separate model and associating the app entity. What I discovered was that if you want to implement IndexedEntity, you can indeed provide an extended attribute set, you just need to start with the existing one, not create your own. Pretty simple:

extension HotelEntity: IndexedEntity {
    var attributeSet: CSSearchableItemAttributeSet {
        let existingAttributes = defaultAttributeSet // this is the key
        
        existingAttributes.displayName = "\(name) displayName"
        existingAttributes.title = "\(name) title"
        existingAttributes.domainIdentifier = "\(name) domainIdentifier"
        existingAttributes.identifier = "\(name) identifier"
        existingAttributes.contentDescription = "\(name) contentDescription"
        existingAttributes.namedLocation = "\(name) namedLocation"

        return existingAttributes
    }
}

With that, it's all working!

Related follow-up question for this integration with Spotlight:

Do I need to implement both CSSearchableItem's new associateAppEntity AND also a custom implementation of attributeSet in my IndexedEntity conformance? It seems duplicative but I can't tell from the video if you're supposed to do both or just one or the other.

Accepted Answer

After spending some time talking with DTS and reviewing the updated App Intent sample code located here https://developer.apple.com/documentation/appintents/acceleratingappinteractionswithappintents, I've got my answer.

The sample provides one way to integrate Spotlight, by indexing a separate model and associating the app entity. What I discovered was that if you want to implement IndexedEntity, you can indeed provide an extended attribute set, you just need to start with the existing one, not create your own. Pretty simple:

extension HotelEntity: IndexedEntity {
    var attributeSet: CSSearchableItemAttributeSet {
        let existingAttributes = defaultAttributeSet // this is the key
        
        existingAttributes.displayName = "\(name) displayName"
        existingAttributes.title = "\(name) title"
        existingAttributes.domainIdentifier = "\(name) domainIdentifier"
        existingAttributes.identifier = "\(name) identifier"
        existingAttributes.contentDescription = "\(name) contentDescription"
        existingAttributes.namedLocation = "\(name) namedLocation"

        return existingAttributes
    }
}

With that, it's all working!

Guidance Implementing IndexedEntity and CSSearchableItemAttributeSet
 
 
Q