This guide describes basic steps you can take to migrate your actions from an
actions.xml
file to a shortcuts.xml
file. Use this guide alongside the App
Actions actions.xml to shortcuts.xml conversion utility to
simplify your migration to the shortcuts.xml
format.
Differences between actions.xml and shortcuts.xml
There are several important differences between the actions.xml
and
shortcuts.xml
files:
You use the same file that you use to define the voice capabilities of your app (usually
res/xml/shortcuts.xml
in your app project) to define Android shortcuts. If you previously implemented static Android shortcuts for your app, migrate your actions fromactions.xml
to that existing file.Entity sets no longer exist. Instead, entities are defined using
shortcut
elements.Deep links are still supported but are not the core method of fulfillment. Instead, use explicit Android intents.
Prerequisites
To support the app
namespace used by attributes in shortcuts.xml
, you must
include the Android Jetpack Core library version 1.6.0 or later with your
app. Examples on this page demonstrate when it's necessary to use the
app
namespace.
Set up shortcuts.xml
If you previously implemented Android shortcuts for your app, use that file to set up your capabilities.
If the shortcuts.xml
file doesn't exist, follow these steps:
In your app project's
res/xml
directory, create theshortcuts.xml
file.Remove the
<meta-data>
tag referencingactions.xml
in theAndroidManifest.xml
file.Add a reference to
shortcuts.xml
inAndroidManifest.xml
using a<meta-data>
tag in the activity that has intent filters for bothMAIN
andLAUNCHER
. The details for this process can be seen in the creating shortcuts overviewIn
shortcuts.xml
, define ashortcuts
element as shown in the following example:<?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android"> </shortcuts>
Set up capabilities
When migrating your actions from an actions.xml
file to a shortcuts.xml
file, you must set
up capability
elements. A capability
identifies the App Action intent that
your app wants to recognize. To migrate, every action in actions.xml
must be
converted to a capability in shortcuts.xml
.
If you have entity sets associated with your actions, complete this procedure to add the capabilities, and then set up shortcuts to represent the entity sets.
For more information about setting up capabilities, see
Create shortcuts.xml
.
To migrate an action to a capability, follow these steps:
In
shortcuts.xml
, in theshortcuts
element, define acapability
element:<?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android"> <capability> </capability> </shortcuts>
Set the
android:name
attribute of thecapability
to the BII your action uses. Inactions.xml
, the value is found in theintentName
attribute of youraction
element.If your action uses a custom intent, you must also include the
app:queryPatterns
attribute. Inactions.xml
, the value is found in thequeryPatterns
attribute of youraction
element.For example, suppose your action invokes the
actions.intent.RECORD_FOOD_OBSERVATION
intent, as shown in the following sampleactions.xml
:Built-in intent
<?xml version="1.0" encoding="utf-8"?> <actions> <action intentName="actions.intent.RECORD_FOOD_OBSERVATION"> ... </action> </actions>
In this example, you set the
android:name
attribute of yourcapability
toactions.intent.RECORD_FOOD_OBSERVATION
inshortcuts.xml
:<shortcuts xmlns:android="http://schemas.android.com/apk/res/android"> <capability android:name="actions.intent.RECORD_FOOD_OBSERVATION"> </capability> </shortcuts>
Custom intent
<?xml version="1.0" encoding="utf-8"?> <actions> <action intentName="custom.actions.intent.RECORD_FOOD_OBSERVATION" queryPatterns="@array/foodObservationQueries"> ... </action> </actions>
In this example, you set the
android:name
attribute of yourcapability
toactions.intent.RECORD_FOOD_OBSERVATION
and setapp:queryPatterns
to@array/foodObservationQueries
inshortcuts.xml
:<?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android"> <capability android:name="custom.actions.intent.RECORD_FOOD_OBSERVATION" app:queryPatterns="@array/foodObservationQueries"> </capability> </shortcuts>
In the
capability
, for eachfulfillment
defined in your action, create anintent
orslice
. You need to add aslice
element only if thefulfillmentMode
attribute of afulfillment
is set toactions.fulfillment.SLICE
. Otherwise, create anintent
element. This is shown in the following exampleshortcuts.xml
:Deep link (default)
<?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android"> <capability android:name="actions.intent.RECORD_FOOD_OBSERVATION"> <intent> </intent> </capability> </shortcuts>
Slice
<?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android"> <capability android:name="actions.intent.RECORD_FOOD_OBSERVATION"> <slice> </slice> </capability> </shortcuts>
For each element that you created in the previous step, define a
url-template
element and set theandroid:value
attribute to the same value used for theurl-template
attribute of yourfulfillment
element.For example, suppose your action uses the following URL template in
actions.xml
:<?xml version="1.0" encoding="utf-8"?> <actions> <action intentName="actions.intent.RECORD_FOOD_OBSERVATION"> ... <fulfillment urlTemplate="myfoodapp://record{?food,meal}"> ... </fulfillment> </action> </actions>
In this example, you set the
android:value
attribute of theurl-template
element tomyfoodapp://record{?food,meal}
inshortcuts.xml
:Deep link (default)
<?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android"> <capability android:name="actions.intent.RECORD_FOOD_OBSERVATION"> <intent> <url-template android:value="myfoodapp://record{?food,meal}" /> </intent> </capability> </shortcuts>
Slice
<?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android"> <capability android:name="actions.intent.RECORD_FOOD_OBSERVATION"> <slice> <url-template android:value="myfoodapp://record{?food,meal}" /> </slice> </capability> </shortcuts>
For each
parameter-mapping
element for the URL template of your action, define aparameter
element and set values for theandroid:name
andandroid:key
attributes.Set
android:name
to the same value as theintentParameter
attribute of yourparameter-mapping
element.Set
android:key
to the same value as theurlParameter
attribute of yourparameter-mapping
element.
If one or more of your parameters is required, set the
android:required
attribute of theparameter
totrue
.For example, suppose your action includes the following parameter mappings for your URL template in
actions.xml
:<?xml version="1.0" encoding="utf-8"?> <actions> <action intentName="actions.intent.RECORD_FOOD_OBSERVATION"> ... <fulfillment urlTemplate="myfoodapp://record{?food,meal}"> ... <parameter-mapping intentParameter="foodObservation.forMeal" urlParameter="meal" entityMatchRequired="true" /> <parameter-mapping intentParameter="foodObservation.aboutFood.name" urlParameter="food" /> </fulfillment> </action> </actions>
In this example, you create the following
parameter
elements inshortcuts.xml
:Deep link (default)
<?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <capability android:name="actions.intent.RECORD_FOOD_OBSERVATION"> <intent> <url-template android:value="myfoodapp://record{?food,meal}" /> <parameter android:name="foodObservation.forMeal" android:key="meal" android:required="true" app:shortcutMatchRequired="true" /> <parameter android:name="foodObservation.aboutFood.name" android:key="food" /> </intent> </capability> </shortcuts>
Slice
<?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <capability android:name="actions.intent.RECORD_FOOD_OBSERVATION"> <slice> <url-template android:value="myfoodapp://record{?food,meal}" /> <parameter android:name="foodObservation.forMeal" android:key="meal" android:required="true" /> <parameter android:name="foodObservation.aboutFood.name" android:key="food" /> </slice> </capability> </shortcuts>
Set up shortcuts
In shortcuts.xml
, entities are represented as shortcuts. If you haven't
yet migrated your actions to capabilities, you must first
set up a capability for each action.
When migrating from actions.xml
to shortcuts.xml
, if your action has an
entity set, you must create a shortcut
for each entity.
The following examples demonstrate the migration steps.
Suppose your original action in actions.xml
looks like this:
<?xml version="1.0" encoding="utf-8"?>
<actions>
<action intentName="actions.intent.RECORD_FOOD_OBSERVATION">
<parameter name="foodObservation.forMeal">
<entity-set-reference entitySetId="MealEntitySet"/>
</parameter>
<fulfillment urlTemplate="myfoodapp://record{?food,meal}">
<parameter-mapping
intentParameter="foodObservation.forMeal"
urlParameter="meal"
entityMatchRequired="true" />
<parameter-mapping
intentParameter="foodObservation.aboutFood.name"
urlParameter="food" />
</fulfillment>
</action>
<entity-set entitySetId="MealEntitySet">
<entity
sameAs="http://schema.googleapis.com/MealTypeBreakfast"
identifier="1" />
<entity
sameAs="http://schema.googleapis.com/MealTypeLunch"
identifier="2" />
<entity
sameAs="http://schema.googleapis.com/MealTypeDinner"
identifier="3" />
</entity-set>
</actions>
In this example, assume that you have already defined the
capability in shortcuts.xml
, including the intent and parameters:
<?xml version="1.0" encoding="utf-8"?>
<shortcuts
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<capability android:name="actions.intent.RECORD_FOOD_OBSERVATION">
<intent>
<url-template android:value="myfoodapp://record{?food,meal}" />
<parameter
android:name="foodObservation.forMeal"
android:key="meal"
android:required="true" />
<parameter
android:name="foodObservation.aboutFood.name"
android:key="food" />
</intent>
</capability>
</shortcuts>
To set up shortcuts for your entities, follow these steps:
In the
shortcuts
element, for each parameter and entity, define ashortcut
element and set a value for theandroid:shortcutId
attribute. The value ofandroid:shortcutId
must be the same as theidentifier
attribute of the corresponding entity.In this example, you create a shortcut for each entity in the
MealEntitySet
entity set, as shown in the following sampleshortcuts.xml
:<?xml version="1.0" encoding="utf-8"?> <shortcuts> <capability android:name="actions.intent.RECORD_FOOD_OBSERVATION"> ... </capability> <shortcut android:shortcutId="1"> </shortcut> <shortcut android:shortcutId="2"> </shortcut> <shortcut android:shortcutId="3"> </shortcut> </shortcuts>
For each shortcut, define a
capability-binding
element. Set theandroid:key
attribute to the built-in intent or custom intent in your capability:... <shortcut android:shortcutId="1"> <capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION"> </capability-binding> </shortcut> <shortcut android:shortcutId="2"> <capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION"> </capability-binding> </shortcut> <shortcut android:shortcutId="3"> <capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION"> </capability-binding> </shortcut> ...
In each
capability-binding
, define aparameter-binding
. Set theandroid:key
attribute to the name of the corresponding parameter in the intent:... <shortcut android:shortcutId="1"> <capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION"> <parameter-binding android:key="foodObservation.forMeal" /> </capability-binding> </shortcut> <shortcut android:shortcutId="2"> <capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION"> <parameter-binding android:key="foodObservation.forMeal" /> </capability-binding> </shortcut> <shortcut android:shortcutId="3"> <capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION"> <parameter-binding android:key="foodObservation.forMeal" /> </capability-binding> </shortcut> ...
Add the
android:value
attribute to yourparameter-binding
, and then define anextra
element.Using the example, to support the entities, you update your
capability-bindings
formeal_breakfast
,meal_lunch
, andmeal_dinner
, and add the correspondingextra
elements:... <shortcut android:shortcutId="1"> <capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION"> <parameter-binding android:key="foodObservation.forMeal" /> </capability-binding> <extra android:key="sameAs" android:value="http://schema.googleapis.com/MealTypeBreakfast" /> </shortcut> <shortcut android:shortcutId="2"> <capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION"> <parameter-binding android:key="foodObservation.forMeal" /> </capability-binding> <extra android:key="sameAs" android:value="http://schema.googleapis.com/MealTypeLunch" /> </shortcut> <shortcut android:shortcutId="3"> <capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION"> <parameter-binding android:key="foodObservation.forMeal" /> </capability-binding> <extra android:key="sameAs" android:value="http://schema.googleapis.com/MealTypeDinner" /> </shortcut> ...
Your migrated capabilities are now ready for testing.
Examples: actions.xml to shortcuts.xml
The following examples demonstrate implementations of App Actions using
actions.xml
and shortcuts.xml
files.
actions.xml - Finance
<?xml version="1.0" encoding="utf-8"?>
<actions>
<action intentName="actions.intent.CREATE_MONEY_TRANSFER">
<fulfillment urlTemplate="mybankapp://transfer{?amount,currency,recipientBankAccountType,senderBankAccountType,mode}">
<parameter-mapping
intentParameter="moneyTransfer.amount.value"
urlParameter="amount" />
<parameter-mapping
intentParameter="moneyTransfer.amount.currency"
urlParameter="currency" />
<parameter-mapping
intentParameter="moneyTransfer.moneyTransferDestination.name"
urlParameter="recipientBankAccountType" />
<parameter-mapping
intentParameter="moneyTransfer.moneyTransferOrigin.name"
urlParameter="senderBankAccountType" />
<parameter-mapping
intentParameter="moneyTransfer.transferMode"
urlParameter="mode" />
</fulfillment>
</action>
</actions>
shortcuts.xml - Finance
<?xml version="1.0" encoding="utf-8"?>
<shortcuts>
<capability android:name="actions.intent.CREATE_MONEY_TRANSFER">
<intent>
<url-template android:value="mybankapp://transfer{?amount,currency,recipientBankAccountType,senderBankAccountType,mode}" />
<parameter
android:name="moneyTransfer.amount.value"
android:key="amount"
android:required="true" />
<parameter
android:name="moneyTransfer.amount.currency"
android:key="currency" />
<parameter
android:name="moneyTransfer.moneyTransferDestination.name"
android:key="recipientBankAccountType" />
<parameter
android:name="moneyTransfer.moneyTransferOrigin.name"
android:key="senderBankAccountType" />
<parameter
android:name="moneyTransfer.transferMode"
android:key="mode" />
</intent>
</capability>
</shortcuts>
actions.xml - Fitness and nutrition
<?xml version="1.0" encoding="utf-8"?>
<actions>
<action intentName="actions.intent.RECORD_FOOD_OBSERVATION">
<parameter name="foodObservation.forMeal">
<entity-set-reference entitySetId="MealEntitySet"/>
</parameter>
<fulfillment urlTemplate="myfoodapp://record{?food,meal}">
<parameter-mapping
intentParameter="foodObservation.forMeal"
urlParameter="meal"
entityMatchRequired="true" />
<parameter-mapping
intentParameter="foodObservation.aboutFood.name"
urlParameter="food" />
</fulfillment>
</action>
<entity-set entitySetId="MealEntitySet">
<entity
sameAs="http://schema.googleapis.com/MealTypeBreakfast"
identifier="1" />
<entity
sameAs="http://schema.googleapis.com/MealTypeLunch"
identifier="2" />
<entity
sameAs="http://schema.googleapis.com/MealTypeDinner"
identifier="3" />
</entity-set>
</actions>
shortcuts.xml - Fitness and Nutrition
<?xml version="1.0" encoding="utf-8"?>
<shortcuts>
<capability android:name="actions.intent.RECORD_FOOD_OBSERVATION">
<intent>
<url-template android:value="myfoodapp://record{?food,meal}" />
<parameter
android:name="foodObservation.forMeal"
android:key="meal"
android:required="true" />
<parameter
android:name="foodObservation.aboutFood.name"
android:key="food" />
</intent>
</capability>
<shortcut android:shortcutId="1">
<capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION">
<parameter-binding android:key="foodObservation.forMeal" />
</capability-binding>
<extra
android:key="sameAs"
android:value="http://schema.googleapis.com/MealTypeBreakfast" />
</shortcut>
<shortcut android:shortcutId="2">
<capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION">
<parameter-binding android:key="foodObservation.forMeal" />
</capability-binding>
<extra
android:key="sameAs"
android:value="http://schema.googleapis.com/MealTypeLunch" />
</shortcut>
<shortcut android:shortcutId="3">
<capability-binding android:key="actions.intent.RECORD_FOOD_OBSERVATION">
<parameter-binding android:key="foodObservation.forMeal" />
</capability-binding>
<extra
android:key="sameAs"
android:value="http://schema.googleapis.com/MealTypeDinner" />
</shortcut>
</shortcuts>
actions.xml - Food ordering
<?xml version="1.0" encoding="utf-8"?>
<actions>
<action intentName="actions.intent.ORDER_MENU_ITEM">
<parameter name="menuItem.inMenuSection.inMenu.forRestaurant.servesCuisine">
<entity-set-reference entitySetId="CuisineEntitySet"/>
</parameter>
<fulfillment urlTemplate="myfoodapp://order{?restaurant}">
<parameter-mapping
intentParameter="menuItem.inMenuSection.inMenu.forRestaurant.name"
urlParameter="restaurant"
required="true" />
</fulfillment>
<fulfillment urlTemplate="myfoodapp://browse{?food}">
<parameter-mapping
intentParameter="menuItem.name"
urlParameter="food" />
</fulfillment>
</action>
<entity-set entitySetId="CuisineEntitySet">
<entity
url="myfoodapp://browse/italian/pizza"
name="@string/pizza"
alternateName="@array/pizzaSynonyms" />
<entity
url="myfoodapp://browse/american/hamburger"
name="@string/hamburger"
alternateName="@array/hamburgerSynonyms" />
<entity
url="myfoodapp://browse/mediterranean"
name="@string/mediterranean"
alternateName="@array/mediterraneanSynonyms" />
</entity-set>
</actions>
shortcuts.xml - Food ordering
<?xml version="1.0" encoding="utf-8"?>
<shortcuts
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<capability android:name="actions.intent.ORDER_MENU_ITEM">
<intent>
<url-template android:value="myfoodapp://order{?restaurant}" />
<parameter
android:name="menuItem.inMenuSection.inMenu.forRestaurant.name"
android:key="restaurant"
android:required="true" />
</intent>
<intent>
<url-template android:value="myfoodapp://browse{?food}" />
<parameter
android:name="menuItem.name"
android:key="food"
android:required="true" />
</intent>
</capability>
<shortcut android:shortcutId="food_pizza">
<intent android:data="myfoodapp://browse/italian/pizza"/>
<capability-binding android:key="actions.intent.ORDER_MENU_ITEM">
<parameter-binding
android:key="menuItem.name"
android:value="@string/pizza" />
</capability-binding>
</shortcut>
<shortcut android:shortcutId="food_hamburger">
<intent android:data="myfoodapp://browse/american/hamburger"/>
<capability-binding android:key="actions.intent.ORDER_MENU_ITEM">
<parameter-binding
android:key="menuItem.name"
android:value="@string/hamburger" />
</capability-binding>
</shortcut>
<shortcut android:shortcutId="food_mediterranean">
<intent android:data="myfoodapp://browse/mediterranean"/>
<capability-binding android:key="actions.intent.ORDER_MENU_ITEM">
<parameter-binding
android:key="menuItem.name"
android:value="@string/mediterranean" />
</capability-binding>
</shortcut>
</shortcuts>
actions.xml - Transportation
<?xml version="1.0" encoding="utf-8"?>
<actions>
<action intentName="actions.intent.CREATE_TAXI_RESERVATION">
<fulfillment urlTemplate="https://taxi-actions.firebaseapp.com/order{?dropoffAddress}">
<parameter-mapping
intentParameter="taxiReservation.dropoffLocation.name"
urlParameter="dropoffAddress"/>
</fulfillment>
</action>
</actions>
shortcuts.xml - Transportation
<?xml version="1.0" encoding="utf-8"?>
<shortcuts
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<capability android:name="actions.intent.CREATE_TAXI_RESERVATION">
<intent>
<url-template android:value="https://taxi-actions.firebaseapp.com/order{?dropoffAddress}" />
<parameter
android:name="taxiReservation.dropoffLocation.name"
android:key="dropoffAddress" />
</intent>
</capability>
</shortcuts>
actions.xml - Other
<?xml version="1.0" encoding="utf-8"?>
<actions>
<action intentName="actions.intent.OPEN_APP_FEATURE">
<parameter name="feature">
<entity-set-reference entitySetId="FeatureEntitySet"/>
</parameter>
<fulfillment urlTemplate="myexampleapp://pathto{?appFeature}">
<parameter-mapping intentParameter="feature" urlParameter="appFeature" />
</fulfillment>
</action>
<entity-set entitySetId="FeatureEntitySet">
<entity identifier="FEATUREONE" name="first feature" />
<entity identifier="FEATURETWO" name="second feature" />
</entity-set>
</actions>
shortcuts.xml - Other
<?xml version="1.0" encoding="utf-8"?>
<shortcuts
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<capability android:name="actions.intent.OPEN_APP_FEATURE">
<intent>
<url-template android:value="myexampleapp://pathto{?appFeature}" />
<parameter android:name="feature" android:key="appFeature" />
</intent>
</capability>
<shortcut android:shortcutId="FEATUREONE">
<capability-binding android:key="actions.intent.OPEN_APP_FEATURE">
<parameter-binding
android:key="feature"
android:value="@string/featureOne" />
</capability-binding>
</shortcut>
<shortcut android:shortcutId="FEATURETWO">
<capability-binding android:key="actions.intent.OPEN_APP_FEATURE">
<parameter-binding
android:key="feature"
android:value="@string/featureTwo" />
</capability-binding>
</shortcut>
</shortcuts>