App Indexing for Android uses HTTP URLs to direct users to content in your app.
Understand your site links
Structure your website and app so they share a common set of links that both platforms can open and use. For example, consider the http://www.recipe-app.com website from the codelab on getting your Android app into Search autocomplete. It’s a simple recipe site with content that's ideal for indexing.
The recipe-app.com sample only has one page type (for recipes), but you could have multiple page types on your site, each with a distinct link type. For example, if recipe-app.com included cooking classes, you might include the following link types:
- Recipe Pages—http://www.recipe-app.com/recipe/*
- Registration Page—http://www.recipe-app.com/registration/
- Schedule Page—http://www.recipe-app.com/schedule/
Add a matching view for each link type to your app. Then configure your app to recognize and handle each link type. Understand the number and types of links you'll need to support before you start building streamlines your work. The following instructions refer back this URL structure for the examples.
Connect your site with your app
You should connect your site with your app using Digital Asset Links.
Digital Asset Links take the form of a JSON file called
assetlinks.json
. You upload it to your web server's
.well-known
directory. The file defines asset
links behavior; in the case of App Indexing this means you must
configure the following fields:
- Relation: Specifies the type of relationship or
delegation. For App Indexing specify that all urls delegate to the
related asset link using
delegate_permission/common.handle_all_urls
. - Target: Using the
namespace
value ofandroid_app
determines the android app that receives the URLs. Configure it using its package name and the SHA-256 fingerprint of the certificate you used to sign your app before deploying it to the Play Store. See Signing Your Applications to learn more about deployment and your signing certificate.
Here’s an example assetlinks.json
for an app package named
com.recipe_app
. You’ll need to change the package
name and sha256_cert_fingerprints
content to match those for
your app.
[{ "relation": ["delegate_permission/common.handle_all_urls"], "target" : { "namespace": "android_app", "package_name": "com.recipe_app", "sha256_cert_fingerprints": ["hash_of_app_certificate"] } }]
Upload this content and make sure it's visible to everyone at
https://<yoursite>/.well-known/assetlinks.json
.
Receive incoming links in your app
In the previous section you saw how the URL structure of your site is an essential component for how to best build your app. You saw the type of recipe URLs on recipe-app.com that the app must also support. If your site includes any other URL types, make sure your app supports them.
In the following sections you’ll see how to configure your Android app to recognize and respond to these links.
Add intent filters
The first step is to add intent filters to your android manifest file.
In the AndroidManifest.xml
, intent filters declare the
HTTP URL patterns that your app handles from inbound links; the same
URLs used for corresponding pages on your website. Refer to the
Adding an Intent Filter section of Android Studio Help.
Here’s an example of an Android manifest file for an app with
an activity for Recipe URLs:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.recipe_app" > ... <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/CustomActionBarTheme" > <activity android:name=".client.HomeActivity" android:label="@string/app_name" android:exported="true" android:theme="@android:style/Theme.Holo.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".client.RecipeActivity" android:label="@string/app_name" android:theme="@android:style/Theme.Holo.NoActionBar" /> ... </application> </manifest>
- Select the
<activity>
tag in Android Studio to reveal the lightbulb icon to the left of the tag. - Choose the lightbulb, then select Add URL from the drop-down list.
Now the activity expands to show the updated URL details:
<activity android:name=".client.RecipeActivity" android:label="@string/app_name" android:exported="true" android:launchMode="singleTop" android:theme="@android:style/Theme.Holo.NoActionBar"> <intent-filter android:label="@string/app_name" android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <!-- Accepts URIs that begin with "http://recipe-app.com/recipe" --> <data android:scheme="http" android:host="recipe-app.com" android:pathPrefix="/recipe" /> </intent-filter> </activity>
You’ll likely have to update the host
field, as it
defaults to the app package name. Note that the DEFAULT
and BROWSABLE
categories are required. You may also want
to edit the pathPrefix
and the scheme
.
Here’s an example where the manifest has been updated for the
recipe-app.com
site. It handles the
pathPrefix
property, and both HTTP and HTTPS
schemes
by adding a second <data>
tag.
<activity android:name=".client.RecipeActivity" android:label="@string/app_name" android:exported="true" android:launchMode="singleTop" android:theme="@android:style/Theme.Holo.NoActionBar"> <intent-filter android:label="@string/app_name" android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <!-- Accepts URIs that begin with "http://recipe-app.com/recipe" --> <data android:scheme="http" android:host="recipe-app.com" android:pathPrefix="/recipe" /> <!-- Accepts URIs that begin with "https://recipe-app.com/recipe" --> <data android:scheme="https" android:host="recipe-app.com" android:pathPrefix="/recipe" /> </intent-filter> </activity>
Now, when a user finds the /recipe
link on your site and chooses to view the
search result, your app launches and presents the recipe activity. It's important that the
intent filter is consistent with your app's logic. If the intent filter claims to support a URL,
your app must also include logic to correctly handle the URL, otherwise App Indexing will
fail. In the next section you'll see how to parse the link in this activity to determine how your
app should render it and ensure App Indexing is successful.
Handle incoming URLs
Now that you've set the Intent Filter in your Android Manifest, your
app launches a specific activity based on the URL passed to it. For
example, the RecipeActivity
activity launches in
response to a URL matching http://recipe-app.com/recipe/*, like
http://recipe-app.com/recipe/wedge-salad.
In this Activity you can then call getIntent()
for the
details from this intent. So your onCreate
code could look
like this:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recipe); onNewIntent(getIntent()); }
onCreate()
passes the results of getIntent()
(an Intent
) to onNewIntent
, for processing.
The URL is available as a result of getDataString()
, so
it’s relatively simple to parse it. For example, suppose you want your
app to display a specific recipe. To parse out the last element of the URL (the recipe ID), build
a URI to retrieve the recipe from the database, and display your activity, use code like this:
protected void onNewIntent(Intent intent) { String action = intent.getAction(); String data = intent.getDataString(); if (Intent.ACTION_VIEW.equals(action) && data != null) { String recipeId = data.substring(data.lastIndexOf("/") + 1); Uri contentUri = Uri.parse("content://com.recipe_app/recipe/").buildUpon() .appendPath(recipeId).build(); showRecipe(contentUri); } }
When you finish building your app, and deploy it to the play store , your app launches in response to recognized URLs from search results.
Control indexing (optional)
You can control which app elements appear in Google Search. Specifically, you can adjust the following:
- Exclude specific pages from Search results—
For first-time App Indexing use, you can configure your manifest to
include only those pages you want indexed by Google. Otherwise,
create a
noindex.xml
file to specify the URLs you want excluded from Google Search. This is similar to how the robots noindex meta tag works for websites. - Exclude real-time app notifications from Search
results—Use a
noindex.xml
file with a specific exclude tag for app notifications.
Create the noindex.xml
file
Create a new XML file in your app's XML resources directory:
res/xml/noindex.xml
. Use statements with specific
attributes to indicate the parts of your app to exclude from
Google Search. These attributes are as follows:
uri
—Excludes a specific URI from Google Search. Google doesn't index URLs that exactly match this attribute.uriPrefix
—Excludes all content below a URI path from Google Search. Google doesn't index those URLs starting with a string matching this attribute.android:value="notification"
—Excludes your app's notifications from Google Search. Google doesn't index the notifications of the app if you specify this attribute.
The following example shows a noindex.xml
file that
excludes a specific page, hidden directories, and limits app
notifications from appearing in Google Search:
<?xml version="1.0" encoding="utf-8"?> <search-engine xmlns:android="http://schemas.android.com/apk/res/android"> <noindex android:value="notification"/> <noindex uri="http://recipe-app.com/profile/hidden-page"/> <noindex uriPrefix="http://recipe-app.com/users/hidden_prefix"/> </search-engine>
Reference the noindex.xml file
After you add the noindex.xml
file, reference it from the
application section of the app’s AndroidManifest.xml
file
with the following line:
<meta-data android:name="search-engine" android:resource="@xml/noindex"/>
For example:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.recipe_app"> <application> <activity android:name=".client.HomeActivity" ...> ... </activity> <meta-data android:name="search-engine" android:resource="@xml/noindex"/> </application> ... </manifest>