Following last week’s text summary of WWDC 2015’s What’s new in Swift, now I will cover the new (and arguably one of the most interesting new) things Apple talked about at WWDC. The original video can be found on both Apple’s WWDC site or on YouTube.


Your app can now be tightly integrated with Spotlight, and developers choose what to index via Search API’s. The goal of search APIs is to bring content to your apps in a search context. So instead of results just showing up in Spotlight, but they also show up in Safari. As the user types, the OS shows results. With Search APIs we will be able to jump directly to content inside our apps. Public linking of your app can be publicly indexed and be seen by everyone who has an iOS device. This provides a whole new level of exposure to your app. You can index much than content: You can make navigation points and features inside your apps searchable. This is useful because Spotlight is used a lot to search apps.

If your user doesn’t have your app installed, Apple can serve results from their gigantic cloud index anyway. We developers can tag content as public, and when many people interact with it, it will be promoted to the cloud index, making it really discoverable. Apple also finds deep webs from the web.

There are three Search APIs. They are different but entirely related to each other. They have different use cases.

Search APIs

  • NSUserActivity (Viewed app content): Extension of the Handoff API. Users want to search for things they have seen in the past. NSUserActivity makes it easy to index that information and makes it searchable.
  • CoreSpotlight (Any App Content): Comprehensively indexing any content inside your app. Gives you low level access to the index in the device. You can add and remove items. Best way to index any private content you have inside your app for your user.
  • Web Markup (App Content on Web): For apps that mirror their content on a website. You can simply mark your content for deep links and Apple will crawl it and add it to their public index.

The rest of the video covers 5 points:

  1. NSUserActivity
  2. CoreSpotlight
  3. Web Markup
  4. Achieving Best Results
  5. User Guides

NSUserActivity

Background: This API was introduced in iOS 8 to implement Handoff. Captures application state that can be restored later.

In iOS 9, NSUserActivities are indexed and searchable in iOS search and Safari. You can associate metadata with your activities, so you can describe your activities. When users engage with your search results, your app will be launch and pass the activity associated with that result. So you can continue restoring the state bringing the user back to their content.

NSUserActivity APIs

There are now APIs to enable index, public indexing, and handoff support.

To describe your activity, you give your activity:

A title: Used for indexing and display in search results.
Keywords: Describe activity, also added to the index.
contentAttributeSet: Makes it easy to describe the activity fully, setting property
expirationDate: To only be shown until a certain date.
webpageUrl: If your app supports Safari universal links.

To create an activity:

var activity: NSUserActivity = NSUserActivity(activityType: "com.yummly.browseRecipe") // You register this type to tell the system what kind of activities your app can handle. Recommended to use reverse DNS notation.
activity.title = "Baked Potato Chips"

// Contains the information we need to recreate the state.
activity.userInfo = ["id": "http://www.yummly.com/recipe/BPC-983195"]

// Enable on-Device indexing.
activity.eligibleForSearch = true

// This activity represents the user's current activity.
activity.becomeCurrent()

When a user taps your results results, a UIApplicationDelegate method is called.

func application(UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: [AnyObject]? -> Void) -> Bool {

	if userActivity.activityType == "com.yummly.browseRecipe" {
		// Restore state for userActivity and userInfo
	}

	return true
}

NSUserActivity is great to let your users go back to something they already visited. But Apple wanted to take it further, and can do with public indexing.

To do this, you create activities as users navigate your app and designate them as public. As users engage with the search results, they get indexed in the cloud index. If your app can be restored in web, you can increase the discoverability.

To mark an activity as public:

var activity: NSUserActivity = NSUserActivity(activityType: "com.yummly.browseRecipe")
activity.userInfo = ["id": "http://www.yummly.com/recipe/BPC-983195"]
activity.eligibleForPublicIndexing = true // Right here!
activity.eligibleForSearch = true
activity.becomeCurrent()

Of course, just by designating the content as public, it doesn’t mean it will be immediately shared with a cloud index. It has to be engaged with by many users.

There’s additional benefits to this API, such as getting Handoff, Siri suggestions and Siri smart reminders. This allows users to remind Siri about interesting content in your apps. When they do, the activity of your app is embedded in the reminder.

CoreSpotlight

A brand new framework in iOS 9. Provides a database-like API, so you can add and remove items. Can be used for indexing any content.

CoreSpotlight API

CSSearchableItem represents an item you wish to index. We associate a CSSearchableItemAttributeSet to said item, by describing properties. We pass the searchable item to the CSSearchableIndex and the item will be ready to be searched.

// Create attribute set and populate with metadata.
let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeImage as String)

attributeSet.title = "Haleakala Sunrise"
attributeSet.contentDescription = "May 12, 2015 Maui, Hawaii"

// Create an item with unique identifier: domainIdentifier is used to group items
let item = CSSearchableItem(uniqueIdentifier: "1", domainIdentifier: "album-1", attributeSet: attributeSet)

// Index the item
CSSearchableItem.defaultSearchableIndex().indexSearchableItems([item]) { error in
	if error != nil {
		print(error?.localizedDescription)
	} else {
		print("Item indexed!")
	}
}

When a user taps your results, the same UIApplicationDelegate that got called when dealing with NSUserActivity will be called. But we know the results come from spotlight because the activity type is CSSearchableItemActionType:

func application(UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: [AnyObject]? -> Void) -> Bool {

	if userActivity.activityType == CSSearchableItemActionType {
		let uniqueIdentifier = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String
		// use the identifier
	}

	return true
}

Maintaining your Index

Index supports updating items. You can do this with the same method you use to add items but passing updated metadata.

You can also delete items. There’s many ways to do this:

By identifier: You can pass an array of identifiers to delete to the deleteSearchableItemsWithIdentifiers method.
By domain identifier: You can pass an array of domain identifiers to the deleteSearchableItemsItemsWithDomainIdentifiers method.
You can also delete all the items by calling deleteAllSearchableItemsWithCompletionHandler.

CoreSpotlight Additional Features

Batching
CSSearchableIndexDelegate
Extension
Data Protection Classes

Web Markup

The key is the deeplink.

Apple has their own bot called Apple Bot. You don’t have to do anything.

To index your content, there’s four steps:

1. Making sure Apple can discover and index your website.
2. Ensuring your website contains markup for deeplinks.
3. Make sure your app can handle opening those deeplinks.
4. (Optional but recommended) add markup for structured data.

The easiest way to make your content discoverable is to submit your support or marketing URL when submitting your app.
Your website must have markup for deeplinks. The most popular way is to use smart app banners.

iOS 9 has universal links, which are better than smart banners. They have several advantages over custom URL schemes, such as:
– They are unique. Other apps can’t use them.
– Secure. Apple checks that your app and the website are really linked together.
– User can choose if the app should open the app or the website.
– They are universal. Can be used for web content as well as your app’s content.

You can also use Twitter cards and Facebook app links to link your app and site together.

(The lecturer recommends we check out the Seamless Linking to your App session).

To make sure your app can open deeplinks:

func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
	// In this example, the URL is http://www.example.com/profile/?123
	if let components = NSURLComponents(URL: url, resolvingAgainstBaseURL: true), let path = components.path, let query = components.query {
		if path == "/profile" {
			// Pass the profile ID from the URL, to the view controller
			return profileViewController.loadProfile(query)
		}
	}
}

Structured Data

Let’s Apple understand and parse your information for their results.

They go beyond just a title and a description.
Results can contain images, structured data, and even actions.
They are engaging to your user and improve your ranking.

There’s many ways for structured data. Schema.org and others can be parsed by the Apple Bot.

Actions

– Dialling a phone number
– Getting directions
– Play audio or video.

Testing Tools

Apple will have testing tools to test deeplink and structured data.

Summary

CoreSpotlight is for private data on the device.
Web Markup is for apps that have their content on the web.
NSUserActivity for both Public and Private content, and to index navigation points within your app.

You can adopt them all in the same app. You need to link your content with an ID. The obvious ID for these items is the URL, when using all the APIs.

Ranking. Apple cares about URL popularity, Activities, and engagements.

Search will down-rank or suppress poor results.
Malicious content will be penalised.

User Guidelines:

– Richer results cause more engagement.
– Try to use keywords.
– When user taps the result, take them directly to the result. For the nasty developers, this means no annoying full screen ads, and no long load times.
– Try to add synonyms, as users like typing short search results.

What to index:
– Your app content. Content user has viewed, curated, created.
– Navigation Points.
– New content arrived.

Positive SSL