blog

Image via https://www.flickr.com/photos/blondinrikard/, licensed under CC.

Indexing App Content with Core Spotlight

by

Core Spotlight has been available since iOS 9 but Apple has made some updates in iOS 10 that make it worth another look. In this series of posts I’ll look at how you can use Core Spotlight to index your application data and search that data both from within iOS using Spotlight and from within an app using some of the new Core Spotlight APIs such as CSSearchQuery.

Our Demo App

To demonstrate how to index application data using Core Spotlight I’ve created a basic iOS app that loads and displays information about some airports and heliports around the world. The app loads this data from a CSV file bundled within the app, displays a list of airports, and provides a basic detail view showing the airport on a map along with the type of airport and identification code. The source to the app is available on GitHub.

Airports Demo app

Airports – a demo app that displays some basic information about airports.

Indexing Application Data with Core Spotlight

After loading the airport data from the bundled CSV the app adds information about each airport to the on-device Spotlight index. The indexAirportData method of the ALAirportController class takes care of this for us:

indexairportdata.mindexairportdata.m

- (void)indexAirportData
{
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
      for (ALAirport* airport in self.airports)
      {
         // Create the attribute set
         CSSearchableItemAttributeSet* attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString*)kUTTypeItem];
         attributeSet.displayName = airport.airportName;
         attributeSet.latitude = @(airport.coordinate.latitude);
         attributeSet.longitude = @(airport.coordinate.longitude);
         attributeSet.thumbnailData = UIImagePNGRepresentation([UIImage imageNamed:@"AppIcon"]);
         // Create the searchable item
         CSSearchableItem* item = [[CSSearchableItem alloc] initWithUniqueIdentifier:airport.airportIdentifier
                                                                    domainIdentifier:@"airports"
                                                                        attributeSet:attributeSet];
         [[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:@[item]
                                                        completionHandler:^(NSError * _Nullable error) {
                                                           NSLog(@"Indexed: %@", airport.airportName);
                                                        }];
      }
   });
}

We first create an CSSearchableItemAttributeSet instance for each airport and set the displayName, latitude, longitude, and thumbnailData attributes. For now, when searching I’ll rely on the displayName attribute, which is set to the name of the airport. The thumbnailData image data will be displayed by iOS when searching using Spotlight. Here I’m simply using the app icon, but if your content has an associated image you could provide it instead. Finally, I include the location of the airport in case we want to support searching by location in a later update.

Next, we create an CSSearchableItem using the attribute set we just created along with a unique identifier. In this case, I’m simply using the airport identification code. When a user taps on a Spotlight search result for your app’s data you’ll get this identifier as part of the data passed to your app delegate.

Finally, we ask the CSSearchableIndex class to index the item we created and log the airport name when it’s done indexing.

Responding to Spotlight Queries

Here we can see a Spotlight search in action. As I start typing a query into the Spotlight search field, results from within the app are presented to the user.

Animated GIF of an example Spotlight search.

When I tap on one of the search results our UIApplicationDelegate will receive an application:continueUserActivity:restorationHandler message. The NSUserActivity instance passed to this method, as part of its userInfo dictionary, will contain the unique identifier for the CSSearchableItem that we created and indexed earlier. Your app can use that identifier as appropriate. Here we’re using it to display the detail view of the related airport.

What’s Next?

In Part 2 we’ll look at how we can use the CSSearchQuery API introduced in iOS 10 to search the Spotlight index of our airport data from within our demo app.


Header image via https://www.flickr.com/photos/blondinrikard/, licensed under CC.

+ more

Accurate Timing

Accurate Timing

In many tasks we need to do something at given intervals of time. The most obvious ways may not give you the best results. Time? Meh. The most basic tasks that don't have what you might call CPU-scale time requirements can be handled with the usual language and...

read more