App shortcuts в Jetpack Compose

App shortcuts в Jetpack Compose

https://habr.com/ru/articles/793636/?utm_source=habrahabr&utm_medium=rss&utm_campaign=793636

Я — Денис, Junior Android-разработчик в «Лайв Тайпинге». В этой статье я расскажу о том как добавить поддержку App shortcuts в Jetpack Compose. Я поделюсь опытом создания шорткатов на примере мобильного приложения — мессенджера.

Введение

Мобильные приложения дарят возможность совершать почти любые действия на ходу. Назначить встречу в поликлинике всего в несколько касаний, заказать обед, проложить маршрут — все эти функции доступны прямо с мобильного устройства. Но бывают моменты, когда скорость становится критически важной — требуется мгновенное реагирование. Как быть приложению в таких случаях?

С шорткатами пользователь может мгновенно получить доступ к практически любому действию в приложении. Например, в 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()

Также нет лимита для количества закреплённых шорткатов, которые может создать пользователь. Ваше приложение на может напрямую удалить такие шорткаты, но их можно отключить.

При очистки кэша приложения динамические и закреплённые шорткаты будут удалены.

Расположение в списке

Шорткаты отображаются в лаунчере в следующем порядке:

  1. статические шорткаты;

  2. динамические шорткаты.

Также шорткаты также могут сортироваться в зависимости от rank (ранга). Это положительное число. Для динамических шорткатов вы можете выставить это значение самостоятельно, когда вызываете метод updateShortcutsaddDynamicShortcutspushDynamicShortcut или setDynamicShortuts.

Большинство лаунчеров отображают максимум четыре шортката. Для любой комбинации статических и динамических шорткатов, которые определены, лаунчер отобразит максимум два статических и два динамических шортката. Например, если вы создадите четыре статических шортката и программно создадите ещё три динамических шортката, лаунчер отобразит два первых статических шортката и два наиболее высоко ранговых динамических шортката.

Особенности работы

Android сам никак не регулирует количество добавляемых шорткатов. Если вы по какой-то причине захотите добавить шестой шорткат, приложение просто упадет, выбросив IllegalArgumentException: Max number of dynamic shortcuts exceeded.

Если не задать хотя бы одному интенту шортката атрибут action, то в случае динамического шортката приложение упадет при создании этого шортката, а в случае статического — шорткат просто не будет создан.

Если попытаться вызвать getSystemService(ShortcutManager.class) на устройстве ниже 23 API, то приложение упадет с ClassNotFoundException.

Заключение

Спасибо, что прочитали статью! Ниже я собрал для вас полезные ссылки и дополнительные материалы по этой теме.

Если вы нашли неточности/ошибки в статье или просто хотите дополнить её своим мнением — то прошу в комментарии!

Report Page