Я — Денис, Android-разработчик в «Лайв Тайпинге». В этой статье я расскажу о том как добавить поддержку App shortcuts в Android. Я поделюсь опытом создания шорткатов на примере мобильного приложения — мессенджера.
Введение
Мобильные приложения дарят возможность совершать почти любые действия на ходу. Назначить встречу в поликлинике всего в несколько касаний, заказать обед, проложить маршрут — все эти функции доступны прямо с мобильного устройства. Но бывают моменты, когда скорость становится критически важной — требуется мгновенное реагирование. Как быть приложению в таких случаях?
С шорткатами пользователь может мгновенно получить доступ к практически любому действию в приложении. Например, в Shazam шорткаты можно использовать для быстрого распознавания музыки — достаточно лишь двух касаний, чтобы узнать, что играет. Это значительно упрощает и ускоряет процесс использования приложения для пользователя.
Обычный сценарий: открываете приложение → ждёте, пока оно загрузится → находите нужное приложение → песня уже закончилась.
Сценарий с шорткатом: вы зажимаете иконку приложения и нажимаете нужное действие — приложение мгновенно распознаёт музыку.

Зачем нужны шорткаты
Для шорткатов предусмотрено много разнообразных возможностей. Вот лишь небольшой обзор того, как пользователи обычно взаимодействуют с ними:
в мессенджерах: быстрый доступ к последнему активному чату, набор номера для звонка, создание новых чатов или групповых бесед.
в приложениях доставки: оплата товаров в корзине, просмотр истории заказов, вызов курьера для доставки.
в коммерческих приложениях: проверка баланса бонусного счета, повторение предыдущего заказа, поиск ближайшего пункта самовывоза.
Как настроить шорткаты
Виды шорткатов
Существуют три вида шорткатов: статичные, динамические, закреплённые.
cтатичные шорткаты — заранее определяются и остаются неизменными. Изменить их можно лишь путем внесения изменений в код приложения;
динамические шорткаты — позволяют изменяться на лету в любое время;
закреплённые шорткаты — находятся выше остальных шорткатов в списке.
?? Пользователи могут создать закреплённые шорткаты, скопировав статические или динамические шорткаты на рабочем столе.
Статичные
Лучше всего подходят для приложений, которым нужно только перейти к опрелённому экрану или действию. Статические шорткаты полезны для выполнения рутинных задач, например, если пользователь хочет просмотреть свой календарь или электронную почту.
Чтобы добавить статический шорткат создайте в res/xml
файл shortcuts.xml
:
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:enabled="true"
android:icon="@drawable/ic_call"
android:shortcutDisabledMessage="@string/disabled_message"
android:shortcutId="static"
android:shortcutLongLabel="@string/static_long_label"
android:shortcutShortLabel="@string/static_short_label">
<intent
android:action="android.intent.action.VIEW"
android:targetClass="ru.popkov.appshortcut.MainActivity"
android:targetPackage="ru.popkov.appshortcut">
<extra
android:name="shortcut_id"
android:value="static" />
</intent>
</shortcut>
</shortcuts>
Android studio не автокомплитит код для шорткатов, поэтому вы можете скопировать и переписать код под своё приложение. Ниже расскажу про параметры из кода выше.
enabled
— определяет доступен шорткат или нет;shortcutDisabledMessage
— сообщение, которое видет пользователь, если шорткат отключен;shortcutShortLabel
— короткий текст, который видет пользователь в списке шорткатов (до 10 символов);shortcutLongLabel
— длинный текст, который видет пользователь в списке шорткатов (до 25 символов);targetClass
— активити, которая будет открыта по клику на шорткат;icon
— адаптивная иконка или bitmap, которая отображается возле текста в списке шорткатов.
Динамические
Нужны в контекстно-чувствительных приложениях. Контекстно-зависимые шорткаты адаптированы к действиям, которые пользователи выполняют в приложении. Например, если вы разрабатываете мессенджер, вы можете динамически обновлять список шорткатов, которые направляют пользователя на часто используемые диалоги.
Чтобы добавить динамический шорткат напишите следующий код:
private val shortcutManager = getSystemService(applicationContext, ShortcutManager::class.java)
fun addDynamicShortcut(
applicationContext: Context,
shortcut: ShortcutModel,
shortcutIntent: Intent,
shortcutId: String,
) {
val shortcutInfo = ShortcutInfoCompat.Builder(applicationContext, shortcutId)
.setShortLabel(shortcut.shortLabel)
.setLongLabel(shortcut.longLabel)
.setIcon(IconCompat.createFromIcon(applicationContext, shortcut.shortcutIcon))
.setIntent(shortcutIntent)
.build()
ShortcutManagerCompat.pushDynamicShortcut(applicationContext, shortcutInfo)
}
В репозитории реализована идея описанная выше: в списке шорткатов появляются часто используемые диалоги, по клику вы попадаете сразу в нужный чат.

Закреплённые
Используются для конкретных действий. Например, когда пользователь хочет прикрепить определённый веб-сайт к лаунчеру. Это удобно, потому что позволяет выполнить действие ещё на один шаг быстрее, чем использование шорткаты.
Поведение со статическим или динамическим шорткатом: зажал иконку приложения → выбрал шорткат → перешёл к нужному действию.
Поведение с закреплённым шорткатом: нажал на шорткат → перешёл к нужному действию.
Создание закреплённого шортката похоже на создание динамического шортката, но требует дополнительного разрешения от пользователя. Сейчас покажу как это сделать:
private val shortcutManager = getSystemService(applicationContext, ShortcutManager::class.java)
fun addPinnedShortcut(
applicationContext: Context,
shortcut: ShortcutModel,
shortcutIntent: Intent,
shortcutId: String,
) {
if (shortcutManager!!.isRequestPinShortcutSupported) {
val shortcutInfo = ShortcutInfo.Builder(applicationContext, shortcutId)
.setShortLabel(shortcut.shortLabel)
.setLongLabel(shortcut.longLabel)
.setIcon(shortcut.shortcutIcon)
.setIntent(shortcutIntent)
.build()
pinShortcut(applicationContext, shortcutInfo)
}
}
private fun pinShortcut(
applicationContext: Context,
shortcut: ShortcutInfo,
) {
val callbackIntent = shortcutManager!!.createShortcutResultIntent(shortcut)
val successPendingIntent = PendingIntent.getBroadcast(
applicationContext,
0,
callbackIntent,
PendingIntent.FLAG_IMMUTABLE
)
shortcutManager.requestPinShortcut(shortcut, successPendingIntent.intentSender)
}
Контроль действий
Если вы хотите написать логику, которая должна выполниться после нажатия определённого шортката, то вы можете поместить в MainActivity
такой код:
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent?) {
intent?.let {
val shortcutType = when (intent.getStringExtra(SHORTCUT_ID)) {
"static" -> ShortcutType.STATIC
"dynamic" -> ShortcutType.DYNAMIC
else -> ShortcutType.PINNED
}
}
}
Ограничения
Большинство лаунчеров отображают до четырёх шорткатов для одного приложения. Чтобы узнать количество шорткатов, которые поддерживает устройство — напишите:
getMaxShortcutCountPerActivity()
Также нет лимита для количества закреплённых шорткатов, которые может создать пользователь. Ваше приложение не может напрямую удалить такие шорткаты, но их можно отключить.
При очистки кэша приложения динамические и закреплённые шорткаты будут удалены.
Расположение в списке
Шорткаты отображаются в лаунчере в следующем порядке:
статические шорткаты;
динамические шорткаты.
Также шорткаты могут сортироваться в зависимости от rank
(ранга). Это положительное число. Для динамических шорткатов вы можете выставить это значение самостоятельно, когда вызываете метод updateShortcuts
, addDynamicShortcuts
, pushDynamicShortcut
или setDynamicShortuts
.
Большинство лаунчеров отображают максимум четыре шортката. Для любой комбинации статических и динамических шорткатов, которые определены, лаунчер отобразит максимум два статических и два динамических шортката. Например, если вы создадите четыре статических шортката и программно создадите ещё три динамических шортката, лаунчер отобразит два первых статических шортката и два наиболее высоко ранговых динамических шортката.
Особенности работы
Android сам никак не регулирует количество добавляемых шорткатов. Если вы по какой-то причине захотите добавить шестой шорткат, приложение просто упадет, выбросив IllegalArgumentException: Max number of dynamic shortcuts exceeded
.
Если не задать хотя бы одному интенту шортката атрибут action, то в случае динамического шортката приложение упадет при создании этого шортката, а в случае статического — шорткат просто не будет создан.
Если попытаться вызвать getSystemService(ShortcutManager.class)
на устройстве ниже 23 API, то приложение упадет с ClassNotFoundException
.
Заключение
Спасибо, что прочитали статью! Ниже я собрал для вас полезные ссылки и дополнительные материалы по этой теме.
Если вы нашли неточности/ошибки в статье или просто хотите дополнить её своим мнением — то прошу в комментарии!