iosios9spotlightnsuseractivityios-searchapi

NSUserActivity Not Getting Indexed by Spotlight


I'm trying to get my NSUserActivity to be indexed by the private index in Spotlight in iOS. I have followed all the steps in Apple's Index Activities and Navigation Points guide but my activity doesn't seem to be getting indexed by spotlight at all.

The guide says that:

To guarantee that the activity and its metadata get indexed, you must hold a strong reference to the activity until it gets added to the index. There are two ways to do this: The first way is to assign the activity to a property in the controller object that creates the activity. The second way is to use the userActivity property of the UIResponder object.

I opted to do the first option (to create a a property in my view controller to hold the NSUserActivity).

var lastSearchedUserActivity: NSUserActivity?

The idea is that, when the user searches for something, his last query is indexed on the device. I have the following method that prepares the user activity and (supposedly) indexes it:

func prepareLastSearchedUserActivity(tags: [String], server: Server) {
    if Settings.applicationIndexedUserActivitiesAsShortcutTypes.contains(.LastSearched) {
        print("Get ready to index. and tags \(tags.reduce("") { "\($0) \($1)" })")
        let activity = NSUserActivity(activityType: ShortcutType.LastSearched.rawValue)

        activity.title = server.serverName
        activity.userInfo = ["tags": tags, "server name": server.serverName]

        let attributeSet = CSSearchableItemAttributeSet()
        attributeSet.contentDescription = tags.reduce("") { "\($0) \($1)" }
        attributeSet.relatedUniqueIdentifier = ShortcutType.LastSearched.rawValue

        activity.contentAttributeSet = attributeSet
        activity.keywords = Set(tags)
        activity.eligibleForSearch = true
        activity.eligibleForHandoff = false
        activity.becomeCurrent()
        self.lastSearchedUserActivity = activity
        //self.lastSearchedUserActivity?.becomeCurrent()
    }
}

This method gets called without an issue, but the activity is not searchable: I have tried to search in Spotlight using the title assigned to it, and the keywords. The activity never shows up.

I have tried many solutions, including:

As far as I can tell, I am doing everything Apple does in their guide. I am completely lost.

I am testing on an iPhone 6S+ so Spotlight indexing is available. The console does not print anything related to Spotlight, either.

Update:

I just set the delegate of the activity to self and implemented the userActivityWillSave method.

According to the NSUserActivityDelegate documentation, about userActivityWillSave:

Notifies the delegate that the user activity will be saved to be continued or persisted.

So this delegate method is getting called, but the indexed item is nowhere to be found. Here's the updated code:

func prepareLastSearchedUserActivity(tags: [String], server: Server) {
    if Settings.applicationIndexedUserActivitiesAsShortcutTypes.contains(.LastSearched) {
        print("Get ready to index. and tags \(tags.reduce("") { "\($0) \($1)" })")
        let activity = NSUserActivity(activityType: ShortcutType.LastSearched.rawValue)

        activity.title = server.serverName
        activity.userInfo = ["tags": tags, "server name": server.serverName]
        activity.delegate = self

        let attributeSet = CSSearchableItemAttributeSet()
        attributeSet.contentDescription = tags.reduce("") { "\($0) \($1)" }
        attributeSet.relatedUniqueIdentifier = ShortcutType.LastSearched.rawValue

        activity.contentAttributeSet = attributeSet
        activity.keywords = Set(tags)
        activity.eligibleForSearch = true
        activity.eligibleForHandoff = false
        self.lastSearchedUserActivity = activity
        activity.becomeCurrent()
        //self.lastSearchedUserActivity?.becomeCurrent()
    }
}

func userActivityWillSave(userActivity: NSUserActivity) {
    print("Yep it will save")
}

Solution

  • Turns out setting the relatedUniqueIdentifier in the attribute set causes the userInfo dictionary to be discarded.

    I commented this line out:

    attributeSet.relatedUniqueIdentifier = ShortcutType.LastSearched.rawValue
    

    And it is now working as expected. Though I will need to find another way to delete my user activities from the index.

    Update: More Information

    If you must use a unique identifier, for your activity, then you need to index it with Core Spotlight first, and then index the NSUserActivity itself. If you try to use the relatedUniqueIdentifier without using it in Spotlight first, the NSUserActivity will not be indexed. This was the problem in my case.

    From the relatedUniqueIdentifier property documentation in the CSSearchableItemAttributeSet Class Reference:

    If you’re using both NSUserActivity and Core Spotlight APIs to index the same item, set this property in the activity to specify the unique identifier of the Core Spotlight item to which the activity is related, and to avoid displaying duplicate results in Spotlight.

    If the unique identifier to which the activity is related hasn’t already been indexed with Core Spotlight, the activity won’t be indexed.