How do Core Spotlight, NSUserActivity, Handoff and universal links make an app’s content discoverable and continuable?

17.5.2 · L3 · Interview

Predict first

What are the default eligibility flags of an activity, and what does a searchable item keep?

import CoreSpotlight
import UniformTypeIdentifiers

let a = NSUserActivity(activityType: "com.example.view")
print(a.isEligibleForHandoff, a.isEligibleForSearch, a.isEligibleForPublicIndexing, a.isEligibleForPrediction)
let attrs = CSSearchableItemAttributeSet(contentType: .text)
attrs.title = "Doc"
let item = CSSearchableItem(uniqueIdentifier: "id1", domainIdentifier: "docs", attributeSet: attrs)
print(item.uniqueIdentifier, item.domainIdentifier ?? "", item.attributeSet.title ?? "")
  • true false false false, then id1 docs Doc
  • true true true true, then docs id1 Doc
  • false false false false, then id1 docs Doc

Mental model. An activity is a bookmark that says “the user was reading page 7 of this”, and Handoff is carrying the open book to another desk. Core Spotlight is writing your library’s catalogue cards so the system’s search can find the book itself.

These APIs describe what the user is doing or what your content is to the system, which then surfaces it. NSUserActivity represents a task or screen: an activityType (a reverse-DNS string you declare in Info.plist under NSUserActivityTypes), a title, a userInfo dictionary (kept small), and eligibility flags: isEligibleForHandoff (true by default), isEligibleForSearch, isEligibleForPublicIndexing and isEligibleForPrediction (the last three false by default, so you opt in). Set userActivity on the current view (SwiftUI: .userActivity(_:)) and the system can do Handoff (continue on another of the user’s devices: the receiving app gets the activity in application(_:continue:restorationHandler:) or the scene equivalent and restores the screen), Spotlight search for things the user has seen, Siri suggestions and shortcuts. Handoff payloads are small, so send an identifier and rebuild the screen from your own data, and keep the type name stable across versions. Core Spotlight (CSSearchableItem) indexes your content directly: build a CSSearchableItemAttributeSet (content type, title, description, keywords, thumbnail), wrap it in a CSSearchableItem(uniqueIdentifier:domainIdentifier:attributeSet:) and index it with CSSearchableIndex.default().indexSearchableItems(_:); the unique identifier and domain identifier let you update and delete later (deleteSearchableItems(withIdentifiers:), or by domain). Tapping a result launches the app with an activity of type CSSearchableItemActionType carrying the identifier in CSSearchableItemActivityIdentifier.

The modern layer on top is App Intents and App Entities: describe your content and actions as AppEntity and AppIntent types and the system uses them for Spotlight, Siri, Shortcuts and Apple Intelligence, with IndexedEntity bridging to Core Spotlight. Universal links (covered in the platform topic) route web URLs into the app: a user tapping https://example.com/item/7 opens the app on that screen, and the same URL is what you put in an activity’s webpageURL so Handoff can fall back to the web. Practical advice: index what is valuable and stable (not everything), keep the index in sync (delete on removal and on sign-out, since results persist on the device and can leak private data), respect privacy (never index secrets or data the user would not expect on the lock screen, and mind that Spotlight results can appear without unlocking depending on settings), provide good titles and thumbnails, handle the launch-from-result path robustly, and test with different search terms. Remember that indexing is best effort and may be throttled, and large initial indexing should run in the background.

Handoff eligibility is on by default and the other three are opt-in. A searchable item stores its identifier, domain and attributes.

Common traps

  • Indexing private data and never removing it. Search results persist on the device; delete items on removal and sign-out.

They might follow up with

  • Which activity flags are on by default? Only Handoff eligibility; search, public indexing and prediction must be opted in.
  • What identifies an indexed item for updates and deletion? Its unique identifier, and optionally its domain identifier.

Related questions

  • 17.5.1 How do passkeys, Sign in with Apple and ASWebAuthenticationSession work in AuthenticationServices?
  • 17.7.1 How do you approach an unfamiliar Apple framework: what do you check before you write code, and how do you…
  • 6.7.2 What is the difference between a custom URL scheme and a universal link, and which do you use?

← How do passkeys, Sign in with Apple and ASWebAuthenticationSession…