Wednesday, June 24, 2015

iOS 9 preview: Spotlight Search

A long, long time ago there used to be an operating system known as PalmOS.  It was used in things like PDAs (smartphones without phones) and, eventually, smartphones.

One great feature of this OS is that it had a built-in global search functionality.  You could search for any term, and not only would built-in programs (what we used to call "apps") be searched, but the contents of third party software would be searched as well.  In other words, if I wrote an app that had access to a bunch of information, I could search from the "home screen" and see results pop up from my own app.

Good times.

It took 8 major OS revisions, but this type of functionality is finally coming to iOS in the upcoming iOS 9.
There are a bunch of new search-related features in iOS 9.0 from the perspective of the app developer, but the one I've been focussed on is CoreSpotlight.  So how does this look from the user's perspective?

Swipe right past the first home screen to get a new search screen (like in the old days of iOS)
Here we have a search screen that I've reached by swiping the screen right past the first home screen. This is how search worked in the early days of iOS.  You can still also swipe the home screen down as you could in the last couple of versions of iOS.

I've type "rule 12." Notice that it has found several matches within an app named "Rules."  This is the app I've been testing the new search features with.  It is a repository for various sets of legal rules and statutes I used in my practice.

Note that it not only has identified the app "rules" as meeting the search criteria, but it has also identified several entries corresponding to possible hits for "Rule 12."

Tapping on the one I want opens my app and jumps right to the relevant rule:

Tapping the search result opens the app and loads the appropriate screen.
Note the "Back to Search" button in the upper left-hand-corner.  The OS now provides this sort of "breadcrumb" to allow the user to jump back to what they were doing.

Here's another one, where I've searched for a specific statute by number:

Here the statute was found by number even though the term "35 USC 121" does not occur anywhere in the actual text of the statute.

Clicking the link jumps to the correct statute, which, notably, does not contain the text "35 USC 121" anywhere in it:

So how does this all work? First you must add the appropriate information to the database which acts as the index for the search engine.  Some sample Swift code here:

NSDictionary *rules=[self getRulesInRuleSet];
forNSString *rule in rules.allKeys) {
           
    // Create an attribute set for an item that represents an image.
    CSSearchableItemAttributeSet* attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString*)kUTTypeImage];
    // Set properties that describe attributes of the item such as title, 
 description, and image.

    [attributeSet setTitle:@"Rules"];
    [attributeSet setContentDescription:rule];
            
    // Create a searchable item, specifying its ID, associated domain, and attribute set.
    CSSearchableItem* item;
    item = [[CSSearchableItem alloc] initWithUniqueIdentifier:rule      domainIdentifier:@"com.maier.rules" attributeSet:attributeSet];
        
    // Index the item.
   [[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:@[item] completionHandler:    ^(NSError * __nullable error) {
      NSLog(@"Search item indexed: %@",rule);
 }];
            
}

What I'm doing here is stepping over each rule in a "rule set."  For example, the "Federal Rules of Civil Procedure" are a ruleset, and the rules within that set are FRCP 1, FRCP 2, etc.

For each rule I create an attributeSet.  For example, FRCP 1 would have the following attributeSet:

Title: Rules (the name of the app, in this case)
Content description: FRCP 1

Next I create the search item.  I provide it a unique identifier (in this case "FRCP 1"), and associate it with the attributeSet.

I have other code, not shown, that also associates the same rule with "Rule 1" so that I can search by typing "Rule 1" or "FRCP 1."

Still elsewhere, in more code not shown, I also add the title of the rule to the index (e.g., for Rule 1, "Scope and Purpose.")  So if I search by a word in the title, e.g. "scope," the same rule pops up in the results.

If I wanted to, I could also index the actual text of the rules.

Globally, what I do, is when the app is started I check a persistent variable to determine if the indexing has already been done and is up to date. I do this by comparing an "indexVersion" value from NSUserDefaults (more on this another time) to a constant that I increment each time I build the app with updated data.  If the indexVersion is less than the required value, I first delete the index for my app using (this time, in Objective-C):

[[CSSearchableIndex defaultSearchableIndex] deleteSearchableItemsWithDomainIdentifiers:@[@“com.maier.rules”] completionHandler:^(NSError *)error) {
    // Handle errors.
})];

Then I rebuild the index.

Next time: how I launch the proper information when someone taps on the search result.

No comments:

Post a Comment