Xamarin.iOS Mobile Search API


iOS has two different API’s to let your app be discovered by iOS’s mobile search, even if you don’t have the app installed on that particular device. This is similar to Google’s App Indexing in that it registers specific pages in your app and can track user activity.

NSUserActivity (iOS 8+)

An NSUserActivity is designed to mark a significant checkpoint in your app. This might include something like viewing a specific page for example a Recipe in your app, the backgrounding of your app, or any kind of significant action. In doing so you can take advantage of these features.

  1. Handoff, which enables you to continue an activity on another device.
  2. Searching your app in the phone’s search.
  3. Public Indexing, allowing your app to show up in search results in phones that don’t have your app installed.

Limitation: To place something in the index, the user must actually visit the activity in your app.

Handoff is not entirely relevant to App Discovery so I will leave it out here and focus on Searching and Public Indexing. If you want to learn more about handoff have a look at Getting Started with Handoff in iOS by Xamarin. Its not that much extra work once you have implemented NSUserActivity.

Create Your Activity Types

Before we begin creating the activities we need to register them in the info.pList. An example is shown below:


Create NSUserActivity

On each ViewController you want to be an Activity, add in this code.

public NSUserActivity UserActivity { get; set; }

Next you will want to add the below code to whenever there is a significant action that signifies a new activity or when the ViewController loads.

// Remove existing activity if it is already present.
if (UserActivity != null) {
    UserActivity = null;

 // Initialize a new UserActivity and set some properties
 UserActivity = new NSUserActivity(new NSString("com.xamarin.packagename.myactivity"));
 UserActivity.Title = "My Activity";

 // Set the Activity Properties with UserInfo (this is optional)
 var userInfo = new NSMutableDictionary ();
 userInfo.Add(new NSString ("Property"), new NSString (somePropertyValue));

 // Become Current Activity

This has now setup the NSUserActivity and it will be registered with the system appropriately.

Handling NSUserActivity

Now we need to handle the activity when it launches the app from a search result.

public override bool ContinueUserActivity (UIApplication application, 
                                           NSUserActivity userActivity, 
                                           UIApplicationRestorationHandler completionHandler)
     // Do an action based on the activity
     switch (userActivity.ActivityType) {
          case "com.xamarin.mypackagename.myactivity":
               // Do something here, e.g. load the appropriate ViewController
             return false;
     return true; // If we handled it

Public Indexing

With NSUserActivity you can make it eligible for public indexing. Apple monitors how many people who use your app use the search and click on an result to launch your NSUserActivity. If enough people do this, and no one except Apple knows the exact amount of usage it needs, it can start appearing in search results on apps that don’t have your app installed. To enable this feature make sure EligibleForPublicIndexing is set to true when you create your NSUserActivity.

NSUserActivity userActivity = new NSUserActivity()
   EligibleForPublicIndexing = true

CoreSpotlight (iOS 9+)

CoreSpotlight is similar to NSUserActivity but is meant for private app searching. For example if you had an email client you would use CoreSpotlight to index emails for searching, as you would never want to place these items on the Public Index. The benefits of CoreSpotlight are:

  1. Private Searching
  2. Index all items without the user viewing the content.

CoreSpotlight works a little differently to NSUserActivity where we need to index the item regardless of what the user is doing. Use the below code to index an item. This can be done where appropriate in your code, it doesn’t need to be anywhere specific.

var attributes = new CSSearchableItemAttributeSet() {
    Title = "New Email",
    ContentDescription = "Subject line of the email"

// Create an item
var item = new CSSearchableItem("1", "email", attributes);

// Index with CoreSpotlight
CSSearchableIndex.DefaultSearchableIndex.Index(new CSSearchableItem[]{ item }, (error) => {
   // Check and action any errors here

Note: If you want to update an item, use the above code with the same ID and it will overwrite the existing entry. If you need to delete, use CSSearchableIndex.DefaultSearchableIndex.Delete

Handle Launch

When our app is launched from a CoreSpotlight Search we once again appear at the ContinueUserActivity method in your AppDelegate.

public override bool ContinueUserActivity (UIApplication application, 
                                           NSUserActivity userActivity, 
                                           UIApplicationRestorationHandler completionHandler)
     switch (userActivity.ActivityType) {
         case "com.xamarin.packagename.myactivity":
               // if NSUserActivity as above
              if (userActivity.ActivityType == CSSearchableItem.ActionType.ToString()) {
                   // Get the activity and launch the appropriate content from CoreSpotlight

     return true;