App Shortcuts
В наше время прогресса, когда сложные системы стараются стать проще для потребителя, операционные системы, такие как Android, пытаются следовать тем же путем, стараясь привлечь всё нового и нового потребителя своих услуг. Функционал Android App Shortcuts может упростить некоторые повседневные функции, такие как, например, отправка сообщения, загрузка в мобильной игре последней контрольной точки или, как в нашем случае, проложить маршрут к избранному адресу и просчитать стоимость поездки в приложении заказа такси нажатием одной кнопки.
На текущий момент в API доступны следующие типы App Shortcuts:
Static shortcuts - статические ярлыки, создаются через xml и жестко прописываются в AndroidManifest.
Dynamic shortcuts - динамические ярлыки, могут создаваться, обновляться и удаляться Вашим приложением в runtime.
Pinned shortcuts - закрепленные ярлыки, могут быть добавлены в поддерживаемые launcher-ы, если пользователь добавит соответствующий permission.
Максимальное количество ярлыков, поддерживаемых устройством, может различаться. Используя метод getMaxShortcutCountPerActivity()
, можно определить, сколько ярлыков поддерживает конкретное устройство. Количество Pinned shortcuts вашего приложения, которые могут создавать пользователи, не ограничено.
Типы App Shortcuts
Static shortcuts
Данный тип ярлыков жестко указывается в AndroidManifest и создается на основе xml-файла. Не буду детально останавливаться на этом типе ярлыков, так как на Хабре есть отличная статья для тех, кто захочет использовать именно этот тип ярлыков. Хоть статья и 2017 года, но описано всё предельно точно и за это время API статических ярлыков не сильно изменилось. Я же хочу более детально описать работу с другими типами ярлыков.
Dynamic shortcuts
Динамические ярлыки предоставляют ссылки на определенные контекстно-зависимые действия в вашем приложении. Эти действия могут меняться в зависимости от использования вашего приложения, и они могут меняться даже во время работы вашего приложения на основе изменяемых данных, будь то запрос к API, данные из БД и т.п.
Библиотека ShortcutManagerCompat Jetpack - помощник для ShortcutManager API, который позволяет вам управлять динамическими ярлыками в вашем приложении. Использование библиотеки ShortcutManagerCompat
сокращает шаблонный код и обеспечивает единообразную работу ярлыков в разных версиях Android.
ShorcutManagerCompat
API позволяет вашему приложению выполнять следующие операции с ярлыками динамическими:
push и update: используйте
pushDynamicShortcut()
для публикации и обновления динамических ярлыков. Если уже есть динамические или закрепленные ярлыки с таким же идентификатором, каждый изменяемый ярлык обновляется;delete: удалить набор динамических ярлыков с помощью
removeDynamicShortcuts()
или удалить все динамические ярлыки с помощьюremoveAllDynamicShortcuts()
.
В нашем приложении для заказа такси мы решили использовать Dynamic shortcuts для того, чтобы облегчить пользователю процесс создания заказа. В качестве действий для ярлыков были выбраны фавориты - так называемые “любимые адреса”. Особенность реализации в том, что фавориты хранятся на сервере и их мы получаем уже после запуска приложения и авторизации. Именно потому нам идеально подошли Dynamic shortcuts.
Добавление Dynamic shortcuts происходит следующим образом:
ShortcutManagerCompat.pushDynamicShortcut(
context,
ShortcutInfoCompat.Builder(context, id)
.setShortLabel(shortLabel)
.setLongLabel(longLabel)
.setIcon(IconCompat.createWithResource(context, icon))
.setIntent(intent)
.build()
)
где,
id - идентификатор ярлыка, по которому этот ярлык обновляется или удаляется;
setShortLabel - краткое название ярлыка, тип CharSequence. Это обязательное поле при публикации нового ярлыка. Это поле предназначено для краткого описания ярлыка. Рекомендуемая максимальная длина - 10 символов;
setLongLabel - текст ярлыка, тип CharSequence. Это поле предназначено для большей наглядности, чем ярлык заголовка. Launcher показывает его вместо shortLabel, когда на нем достаточно места. Рекомендуемая максимальная длина - 25 символов.
Обращаю внимание, что shortLabel это обязательное поле. Более того, оно не должны быть пустым, иначе получите исключение IllegalArgumentException("Shortcut must have a non-empty label").
setIntent - устанавливает назначение ярлыка. В intent мы описываем activity, которая должна запуститься при нажатии на ярлык, и флаги, с которыми она должна запуститься. Например:
Intent(Intent.ACTION_MAIN, Uri.EMPTY, context, StartActivity::class.java).apply {
putExtra(BundleKeys.KEY_APP_SHORTCUT_ID, id)
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
Тут мы указали нашу точку входа в приложение - StartActivity, с соответствующим action и flags. В качестве альтернативы можно использовать setIntents(Intent [])
для запуска activity с другими activities в стеке.
Также нам понадобилась функция удаления ярлыков при смене пользователя. Происходит это следующим образом:
ShortcutManagerCompat.removeDynamicShortcuts(context, ids)
где,
ids - List идентификаторов ярлыков(помните, которые мы указывали при создании ярлыка).
Кроме того можно удалить абсолютно все ярлыки:
ShortcutManagerCompat.removeAllDynamicShortcuts(context)
Pinned shortcuts
Начиная с версии Android 8.0 (уровень API 26) и выше вы можете создавать закрепленные ярлыки. В отличие от статических и динамических ярлыков закрепленные ярлыки отображаются в поддерживаемых launcher-ах как отдельные значки.
Создать закрепленный ярлык можно следующим образом:
context.getSystemService(ShortcutManager::class.java)?.let { shortcutManager ->
if (shortcutManager.isRequestPinShortcutSupported) {
val pinShortcutInfo = ShortcutInfo.Builder(context, id)
.setShortLabel(shortLabel)
.setLongLabel(longLabel)
.setIcon(Icon.createWithResource(context, icon))
.setIntent(intent)
.build()
// Create the PendingIntent object only if your app needs to be notified
// that the user allowed the shortcut to be pinned. Note that, if the
// pinning operation fails, your app isn't notified. We assume here that the
// app has implemented a method called createShortcutResultIntent() that
// returns a broadcast intent.
val pinnedShortcutCallbackIntent = shortcutManager.createShortcutResultIntent(pinShortcutInfo)
// Configure the intent so that your app's broadcast receiver gets
// the callback successfully.For details, see PendingIntent.getBroadcast().
val successCallback = PendingIntent.getBroadcast(
context, /* request code */ 0,
pinnedShortcutCallbackIntent, /* flags */ 0
)
shortcutManager.requestPinShortcut(
pinShortcutInfo,
successCallback.intentSender
)
}
}
где,
shortcutManager.isRequestPinShortcutSupported - для проверки, что launcher устройства поддерживает закрепленные ярлыки;
pinShortcutInfo - создается по принципу динамического ярлыка(см. пункт Dynamic shortcuts);
pinnedShortcutCallbackIntent и successCallback - опциональные, если вы хотите получить callback о том, что пользователь разрешил добавление закрепленного ярлыка;
shortcutManager.requestPinShortcut - соответственно запрос на добавление закрепленного ярлыка из приложения, successCallback.intentSender может быть равен null, если вы не хотите иметь callback о создании.
Вызвав код выше, мы можем увидеть нативный диалог добавления закрепленного ярлыка из приложения:
После нажатия "Добавить автоматически", вы увидите закрепленный ярлык на главном экране своего телефона.
Управление ярлыками
После создания ярлыков вам может потребоваться управлять ими в течение всего жизненного цикла вашего приложения. Например, вы можете оптимизировать свое приложение, определив, как часто ваши пользователи выполняют определенные действия с вашими ярлыками. В другом случае вы можете решить отключить закрепленный ярлык, чтобы ваше приложение не выполняло устаревшие или отсутствующие действия. Далее рассмотрим некоторые из возможностей управления ярлыками.
Управление несколькими intents и activity
Если вы хотите, чтобы ваше приложение выполняло несколько операций, когда ваш пользователь активирует ярлык, вы можете настроить его для запуска последовательных действий. Вы можете сделать это, назначив несколько intents, запустив одну activity из другой или установив флаги intents, в зависимости от типа ярлыка.
Создавая ярлык с помощью ShortcutInfoCompat.Builder
, вы можете использовать setIntents() вместо of setIntent().
Вызывая setIntents()
, вы можете запускать несколько activities в своем приложении, когда пользователь выбирает ярлык, помещая все, кроме последнего activity в списке, в back stack. Если затем пользователь решит нажать кнопку «Назад» на устройстве, он увидит другое activity в вашем приложении вместо того, чтобы вернуться к launcher-у устройства.
Обновление ярлыков
Значок запуска каждого приложения может содержать не более чем getMaxShortcutCountPerActivity()
количество комбинированных статических и динамических ярлыков. Однако количество закрепленных ярлыков, которые может создать приложение, не ограничено.
Когда динамический ярлык закреплен, даже когда приложение удаляет его как динамический ярлык, закрепленный ярлык по-прежнему виден и доступен для запуска. Это позволяет приложению иметь больше, чем getMaxShortcutCountPerActivity()
количество ярлыков.
В качестве примера предположим, что getMaxShortcutCountPerActivity() =
четыре:
Приложение публикует четыре динамических ярлыка, представляющих четыре последних любимых адреса(c1, c2, c3, c4).
Пользователь закрепляет все четыре ярлыка.
Позже пользователь создал три дополнительных любимых адреса (c5, c6 и c7), поэтому приложение повторно публикует свои динамические ярлыки. Новый динамический список ярлыков: c4, c5, c6, c7.
Приложение должно удалить c1, c2 и c3, потому что оно не может отображать более четырех динамических ярлыков. Однако c1, c2 и c3 по-прежнему являются закрепленными ярлыками, к которым пользователь может получить доступ и запустить.
Теперь пользователь может получить доступ к семи ярлыкам, которые ссылаются на действия в приложении. Это связано с тем, что общее количество включает как максимальное количество ярлыков, так и три закрепленных ярлыка.
Приложение может использовать
updateShortcuts(Context, List)
для обновления любого из семи существующих ярлыков. Например, вы можете обновить этот набор ярлыков при изменении названия любимого адреса.addDynamicShortcuts(Context, List)
ИsetDynamicShortcuts(Context, List)
методы могут быть также использованы для обновления существующих ярлыков с одинаковыми идентификаторами. Однако их нельзя использовать для обновления нединамических закрепленных ярлыков, потому что эти два метода пытаются преобразовать заданные списки ярлыков в динамические ярлыки.
Отключение ярлыков
Поскольку ваше приложение и его пользователи могут закреплять ярлыки на панели запуска устройства, возможно, что эти закрепленные ярлыки могут направлять пользователей к activity в вашем приложении, которые устарели или больше не существуют. Чтобы справиться с этой ситуацией, вы можете отключить ярлыки, которые вы не хотите, чтобы пользователи выбирали, вызывая disableShortcuts()
, что удаляет указанные ярлыки из статического и динамического списка ярлыков и отключает любые закрепленные копии этих ярлыков.
Best practices для App Shortcuts
Ну и под конец хотелось бы поделиться рекомендованными Google best practices:
Следуйте рекомендациям по дизайну. Чтобы ярлыки вашего приложения визуально соответствовали ярлыкам, используемым для системных приложений, следуйте рекомендациям по созданию App Shortcuts.
Публикуйте только четыре различных ярлыка. Хотя API в настоящее время поддерживает комбинацию до пятнадцати статических и динамических ярлыков для вашего приложения в любой момент времени, Google рекомендует публиковать только четыре отдельных ярлыка, чтобы улучшить их внешний вид в launcher-е.
Ограничение длины описания ярлыка. Место в меню, которое показывает ярлыки вашего приложения на панели запуска, ограничено. По возможности ограничивайте длину
setShortLabel
ярлыка 10 символами и ограничивайте длинуsetLongLabel
25 символами.Обновляйте ярлыки только тогда, когда их значение сохраняется. При изменении динамических и закрепленных ярлыков вызывать
updateShortcuts()
только при изменении информации ярлыка, который сохранил свое значение. Например, если вы создали ярлык для перехода на любимый адрес, было бы целесообразно обновить ярлык, если название адреса изменилось, но его другие его параметры остались прежними.
Итог
В данной статье я попытался рассказать о нашем опыте работы с такой полезной технологией как App Shortcuts, а так же о рекомендуемых подходах использования данной технологии.
Полезные ссылки: Android App Shortcuts official guidelines, Изучаем App Shortcuts в Android Nougat 7.1