Application Indexing and Deep Linking
Xamarin.Forms application indexing and deep linking provide an API for publishing metadata for application indexing as users navigate through applications. Indexed content can then be searched for in Spotlight Search, in Google Search, or in a web search. Tapping on a search result that contains a deep link will fire an event that can be handled by an application, and is typically used to navigate to the page referenced from the deep link.
The sample application demonstrates a Todo list application where the data is stored in a local SQLite database, as shown in the following screenshots:
Each TodoItem
instance created by the user is indexed. Platform-specific search can then be used to locate indexed data from the application. When the user taps on a search result item for the application, the application is launched, the TodoItemPage
is navigated to, and the TodoItem
referenced from the deep link is displayed.
For more information about using an SQLite database, see Xamarin.Forms Local Databases.
Note
Xamarin.Forms application indexing and deep linking functionality is only available on the iOS and Android platforms, and requires a minimum of iOS 9 and API 23 respectively.
Setup
The following sections provide any additional setup instructions for using this feature on the iOS and Android platforms.
iOS
On the iOS platform, ensure that your iOS platform project sets the Entitlements.plist file as the custom entitlements file for signing the bundle.
To use iOS Universal Links:
- Add an Associated Domains entitlement to your app, with the
applinks
key, including all the domains your app will support. - Add an Apple App Site Association file to your website.
- Add the
applinks
key to the Apple App Site Association file.
For more information, see Allowing Apps and Websites to Link to Your Content on developer.apple.com.
Android
On the Android platform, there are a number of prerequisites that must be met to use application indexing and deep linking functionality:
- A version of your application must be live on Google Play.
- A companion website must be registered against the application in Google's Developer Console. Once the application is associated with a website, URLs can be indexed that work for both the website and the application, which can then be served in Search results. For more information, see App Indexing on Google Search on Google's website.
- Your application must support HTTP URL intents on the
MainActivity
class, which tell application indexing what types of URL data schemes the application can respond to. For more information, see Configuring the Intent Filter.
Once these prerequisites are met, the following additional setup is required to use Xamarin.Forms application indexing and deep linking on the Android platform:
- Install the Xamarin.Forms.AppLinks NuGet package into the Android application project.
- In the MainActivity.cs file, add a declaration to use the
Xamarin.Forms.Platform.Android.AppLinks
namespace. - In the MainActivity.cs file, add a declaration to use the
Firebase
namespace. - In a web browser, create a new project via the Firebase Console.
- In the Firebase Console, add Firebase to your Android app, and enter the required data.
- Download the resulting google-services.json file.
- Add the google-services.json file to the root directory of the Android project, and set its Build Action to GoogleServicesJson.
- In the
MainActivity.OnCreate
override, add the following line of code underneathForms.Init(this, bundle)
:
FirebaseApp.InitializeApp(this);
AndroidAppLinks.Init(this);
When google-services.json is added to the project (and the GoogleServicesJson* build action is set), the build process extracts the client ID and API key and then adds these credentials to the generated manifest file.
Note
In this article, the terms application links and deep links are often used interchangeably. However, on Android these terms have separate meanings. On Android, a deep link is an intent filter that allows users to directly enter a specific activity in the app. Clicking on a deep link might open a disambiguation dialog, which allows the user to select one of multiple apps that can handle the URL. An Android app link is a deep link based on your website URL, which has been verified to belong to your website. Clicking on an app link opens your app if it's installed, without opening a disambiguation dialog.
For more information, see Deep Link Content with Xamarin.Forms URL Navigation on the Xamarin blog.
Indexing a Page
The process for indexing a page and exposing it to Google and Spotlight search is as follows:
- Create an
AppLinkEntry
that contains the metadata required to index the page, along with a deep link to return to the page when the user selects the indexed content in search results. - Register the
AppLinkEntry
instance to index it for searching.
The following code example demonstrates how to create an AppLinkEntry
instance:
AppLinkEntry GetAppLink(TodoItem item)
{
var pageType = GetType().ToString();
var pageLink = new AppLinkEntry
{
Title = item.Name,
Description = item.Notes,
AppLinkUri = new Uri($"http://{App.AppName}/{pageType}?id={item.ID}", UriKind.RelativeOrAbsolute),
IsLinkActive = true,
Thumbnail = ImageSource.FromFile("monkey.png")
};
pageLink.KeyValues.Add("contentType", "TodoItemPage");
pageLink.KeyValues.Add("appName", App.AppName);
pageLink.KeyValues.Add("companyName", "Xamarin");
return pageLink;
}
The AppLinkEntry
instance contains a number of properties whose values are required to index the page and create a deep link. The Title
, Description
, and Thumbnail
properties are used to identify the indexed content when it appears in search results. The IsLinkActive
property is set to true
to indicate that the indexed content is currently being viewed. The AppLinkUri
property is a Uri
that contains the information required to return to the current page and display the current TodoItem
. The following example shows an example Uri
for the sample application:
http://deeplinking/DeepLinking.TodoItemPage?id=2
This Uri
contains all the information required to launch the deeplinking
app, navigate to the DeepLinking.TodoItemPage
, and display the TodoItem
that has an ID
of 2.
Registering Content for Indexing
Once an AppLinkEntry
instance has been created, it must be registered for indexing to appear in search results. This is accomplished with the RegisterLink
method, as demonstrated in the following code example:
Application.Current.AppLinks.RegisterLink (appLink);
This adds the AppLinkEntry
instance to the application's AppLinks
collection.
Note
The RegisterLink
method can also be used to update the content that's been indexed for a page.
Once an AppLinkEntry
instance has been registered for indexing, it can appear in search results. The following screenshot shows indexed content appearing in search results on the iOS platform:
De-registering Indexed Content
The DeregisterLink
method is used to remove indexed content from search results, as demonstrated in the following code example:
Application.Current.AppLinks.DeregisterLink (appLink);
This removes the AppLinkEntry
instance from the application's AppLinks
collection.
Note
On Android it's not possible to remove indexed content from search results.
Responding to a Deep Link
When indexed content appears in search results and is selected by a user, the App
class for the application will receive a request to handle the Uri
contained in the indexed content. This request can be processed in the OnAppLinkRequestReceived
override, as demonstrated in the following code example:
public class App : Application
{
...
protected override async void OnAppLinkRequestReceived(Uri uri)
{
string appDomain = "http://" + App.AppName.ToLowerInvariant() + "/";
if (!uri.ToString().ToLowerInvariant().StartsWith(appDomain, StringComparison.Ordinal))
return;
string pageUrl = uri.ToString().Replace(appDomain, string.Empty).Trim();
var parts = pageUrl.Split('?');
string page = parts[0];
string pageParameter = parts[1].Replace("id=", string.Empty);
var formsPage = Activator.CreateInstance(Type.GetType(page));
var todoItemPage = formsPage as TodoItemPage;
if (todoItemPage != null)
{
var todoItem = await App.Database.GetItemAsync(int.Parse(pageParameter));
todoItemPage.BindingContext = todoItem;
await MainPage.Navigation.PushAsync(formsPage as Page);
}
base.OnAppLinkRequestReceived(uri);
}
}
The OnAppLinkRequestReceived
method checks that the received Uri
is intended for the application, before parsing the Uri
into the page to be navigated to and the parameter to be passed to the page. An instance of the page to be navigated to is created, and the TodoItem
represented by the page parameter is retrieved. The BindingContext
of the page to be navigated to is then set to the TodoItem
. This ensures that when the TodoItemPage
is displayed by the PushAsync
method, it will be showing the TodoItem
whose ID
is contained in the deep link.
Making Content Available for Search Indexing
Each time the page represented by a deep link is displayed, the AppLinkEntry.IsLinkActive
property can be set to true
. On iOS and Android this makes the AppLinkEntry
instance available for search indexing, and on iOS only, it also makes the AppLinkEntry
instance available for Handoff. For more information about Handoff, see Introduction to Handoff.
The following code example demonstrates setting the AppLinkEntry.IsLinkActive
property to true
in the Page.OnAppearing
override:
protected override void OnAppearing()
{
appLink = GetAppLink(BindingContext as TodoItem);
if (appLink != null)
{
appLink.IsLinkActive = true;
}
}
Similarly, when the page represented by a deep link is navigated away from, the AppLinkEntry.IsLinkActive
property can be set to false
. On iOS and Android, this stops the AppLinkEntry
instance being advertised for search indexing, and on iOS only, it also stops advertising the AppLinkEntry
instance for Handoff. This can be accomplished in the Page.OnDisappearing
override, as demonstrated in the following code example:
protected override void OnDisappearing()
{
if (appLink != null)
{
appLink.IsLinkActive = false;
}
}
Providing Data to Handoff
On iOS, application-specific data can be stored when indexing the page. This is achieved by adding data to the KeyValues
collection, which is a Dictionary<string, string>
for storing key-value pairs that are used in Handoff. Handoff is a way for the user to start an activity on one of their devices and continue that activity on another of their devices (as identified by the user's iCloud account). The following code shows an example of storing application-specific key-value pairs:
var pageLink = new AppLinkEntry
{
...
};
pageLink.KeyValues.Add("appName", App.AppName);
pageLink.KeyValues.Add("companyName", "Xamarin");
Values stored in the KeyValues
collection will be stored in the metadata for the indexed page, and will be restored when the user taps on a search result that contains a deep link (or when Handoff is used to view the content on another signed-in device).
In addition, values for the following keys can be specified:
contentType
– astring
that specifies the uniform type identifier of the indexed content. The recommended convention to use for this value is the type name of the page containing the indexed content.associatedWebPage
– astring
that represents the web page to visit if the indexed content can also be viewed on the web, or if the application supports Safari's deep links.shouldAddToPublicIndex
– astring
of eithertrue
orfalse
that controls whether or not to add the indexed content to Apple's public cloud index, which can then be presented to users who haven't installed the application on their iOS device. However, just because content has been set for public indexing, it doesn't mean that it will be automatically added to Apple's public cloud index. For more information, see Public Search Indexing. Note that this key should be set tofalse
when adding personal data to theKeyValues
collection.
Note
The KeyValues
collection isn't used on the Android platform.
For more information about Handoff, see Introduction to Handoff.