Indexing content using Core Spotlight
Asked Answered
S

1

7

In the Mail app or in the Messages app you can search for the content of any message using the Core Spotlight search. Also I can see OneNote doing this, so it should be available in APIs.

However, documentation about that is almost none existent. I can see only that in CSSearchableItemAttributeSet there is contentUrl, but I have tried to set NSUrl of the .txt file and nothing happened. Also tried to set contentType to kUTTypeText and kUTTypeUTF8PlainText but no improvements.

Is some specific file format required? Or something else one should do?

Saurian answered 25/7, 2016 at 12:59 Comment(4)
so your data is messages? what attributes are you setting values for currently? the subject or text content?Tetragon
Why can't you just deeplink the .txt file in your app. I know this will be a hack for your case but, can solve your problem too. To deeplink, set the unique identifier and get it in -(BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * _Nullable))restorationHandler{} in AppDelegate.mRobillard
@Wain, data is stored by the user so in theory it can be any text, its usual length is around 5000 characters, though it can be any length. I set title and thumbnailUrl, if the item originates fromt the web I also set contentSources.Godred
@SanchitKumarSingh I don't mind hacks, I already have some deeps links and I am using the API that you mention for those cases. However, I don't see how it could help. Do you refer to something like nativescript.org/blog/details/… ? I believe you should answer below, even if it is not a full solution for me if there is some useful information and is at least partial solution someone (including me) may vote for it.Godred
J
8

The Apple documentation on CoreSpotlight breaks down the process of creating and adding items to a searchable index:

  • Create a CSSearchableItemAttributeSet object and specify properties that describe the item you want to index.

  • Create a CSSearchableItem object to represent the item. A CSSearchableItem object has a unique identifier that lets you refer to it later.

  • If needed, specify a domain identifier so that you can gather multiple items together and manage them as a group.

  • Associate the attribute set with the searchable item.

  • Add the searchable item to the index.

Here's a quick example I that shows how to index a simple Note class:

class Note {
    var title: String
    var description: String
    var image: UIImage?

    init(title: String, description: String) {
        self.title = title
        self.description = description
    }
}

Then in some other function, create your notes, create a CSSearchableItemAttributeSet for each note, create a unique CSSearchableItem from the attribute set, and index the collection of searchable items:

import CoreSpotlight
import MobileCoreServices

// ...

// Build your Notes data source to index
var notes = [Note]()
notes.append(Note(title: "Grocery List", description: "Buy milk, eggs"))
notes.append(Note(title: "Reminder", description: "Soccer practice at 3"))
let parkingReminder = Note(title: "Reminder", description: "Soccer practice at 3")
parkingReminder.image = UIImage(named: "parkingReminder")
notes.append(parkingReminder)

// The array of items that will be indexed by CoreSpotlight
var searchableItems = [CSSearchableItem]()

for note in notes {
    // create an attribute set of type Text, since our reminders are text
    let searchableItemAttributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeText as String)

    // If we have an image, add it to the attribute set
    if let image = note.image {
        searchableItemAttributeSet.thumbnailData = UIImagePNGRepresentation(image)
        // you can also use thumbnailURL if your image is coming from a server or the bundle
//        searchableItemAttributeSet.thumbnailURL = NSBundle.mainBundle().URLForResource("image", withExtension: "jpg")
    }

    // set the properties on the item to index
    searchableItemAttributeSet.title = note.title
    searchableItemAttributeSet.contentDescription = note.description

    // Build your keywords
    // In this case, I'm tokenizing the title of the note by a space and using the values returned as the keywords
    searchableItemAttributeSet.keywords = note.title.componentsSeparatedByString(" ")

    // create the searchable item
    let searchableItem = CSSearchableItem(uniqueIdentifier: "com.mygreatapp.notes" + ".\(note.title)", domainIdentifier: "notes", attributeSet: searchableItemAttributeSet)
}

// Add our array of searchable items to the Spotlight index
CSSearchableIndex.defaultSearchableIndex().indexSearchableItems(searchableItems) { (error) in
    if let error = error {
        // handle failure
        print(error)
    }
}

This example has been adapted from AppCoda's How To Use Core Spotlight Framework in iOS 9 guide.

Jobi answered 27/7, 2016 at 14:59 Comment(2)
I had some comments, but deleted them and done the experiment. In not so short email (18600 characters), EVERY word is searchable, including common ones like 'this'. I believe that it excludes using description and very likely excludes keywords too. Do you agree?Godred
@IvanIčin it is possible OneNote has a list of pronouns or other blacklisted words which are stripped from the searchable text before creating an index of searchable items.Jobi

© 2022 - 2024 — McMap. All rights reserved.