Сегодня я хочу рассказать вам об интересном и в некотором смысле новом способе взаимодействия с пользователем – кастомных пушах в Android. Именно его мы использовали как основу своего мобильного приложения CoinRoad для отображения графиков и котировок криптовалют на биржах в режиме реального времени в виде обновляемых в фоне пушей, которые продолжают работать даже после закрытия приложения.
Основное преимущество такого подхода заключается в том, что каждый день мы получаем кучу уведомлений на свой телефон, а значит обращаем на них внимание, опуская шторку или видя их на экране блокировки. Однако временной интервал жизни таких пушей крайне мал, поскольку пуш обычно либо свайпается, либо по нему открывается более подробная информация в приложении и он все-равно удаляется.
Разумеется, есть уведомления, которые остаются висеть постоянно, как, например, музыкальный плеер. Но до сих пор такая механика еще не применялась для отображения торговой истории с бирж, когда каждая минута на счету и важно быть в курсе, не переключаясь постоянно между различными приложениями. Виджеты на рабочем столе не решают проблему – чтобы попасть на рабочий стол, нужно сначала свернуть активное приложение.
Кастомные пуши
Android уже довольно давно предоставляет возможность создавать свои собственные варианты оформления пушей. Делается это через RemoteViews, который, правда, ограничен в плане поддержки доступных для отображения элементов следующим списком:
Supported Views
А поскольку для отображения графиков в пушах было решено использовать стороннюю библиотеку, которая реализовывает свой собственный View
, сразу же возникла сложность с ее интеграцией в пуш. Решение было найдено, однако оно является компромиссным и заключается в том, что содержимое графика поставляется как растровое изображение и выводится через ImageView
. Но так как размеры пуша не маленькие, а содержимое получаемого изображения весит прилично, мы наткнулись на проблему с ограничением на размер буфера в 1mb и получили следующее исключение: TransactionTooLargeException.
Во время удаленного вызова фоновой процедуры аргументы и возвращаемое значение вызова передаются как Parcel
объекты, хранящиеся в буфере транзакции Binder
. Если аргументы или возвращаемое значение слишком велики, чтобы поместиться в буфере транзакции, вызов завершится ошибкой.
Для решения этой проблемы пришлось сжимать изображение до 500kb, что незначительно сказалось на качестве итоговых данных, но позволило добиться результата. Изображение включает в себя не только сам график, но и текущие ценовые котировки, название торговой пары и биржи. Вся отрисовка ведется средствами Canvas, что позволяет добиться хорошей производительности и низкого энергопотребления даже на слабых устройствах.
Работа в фоне
Все добавленные пользователем пуши обновляются бесшумно с интервалом в одну минуту, не привлекая лишнего внимания, напоминая о себе звуковым сигналом только при добавлении или удалении пуша из приложения.
Для фоновой работы используется WorkManager в связке с CoroutineWorker
Выбор в пользу WorkManager вместо Service был обусловлен желанием иметь гарантированную возможность работать в новых реалиях Doze mode (режим «отключки», в который переходят все устройства начиная с Marshmallow после некоторого времени обездвижения без зарядки) и не писать свой BroadcastReceiver для запуска сервиса при различных условиях.
WorkManager с версии 2.3.0-alpha02
добавляет поддержку длительно работающих процессов. В таких случаях WorkManager может подавать сигнал в ОС, что процесс должен оставаться активным, если это возможно пока работа выполняется. Под капотом WorkManager управляет и запускает Foreground Service
от вашего имени для выполнения WorkRequest, а также отображает настраиваемое уведомление. А чтобы ничего не умирало, был написан обработчик ошибок, который может перезапустить WorkManager.
Однако стоит принять во внимание, что WorkManager пока еще находится в alpha-версии, так что будьте внимательны.
Удаление пушей
Еще одной болью стало решение проблемы с удалением пушей, которые добавляются в фоновый процесс CoroutineWorker'а через метод
setForeground(ForegroundInfo(..))
Проблема заключалась в том, что невозможно отменить пуш, который ты добавил, для этого просто нет соответствующего метода. А вызов cancel у NotificationManager'а не приводил ни к какому результату, что подтверждает документация:
"If the notification does not currently represent a Service#startForeground(int, Notification), it will be removed from the UI and live notification listeners will be informed so they can remove the notification from their UIs."
Для решения этой проблемы было решено пересоздавать канал уведомлений всякий раз, когда пользователь решит изменить список валютных пар, которые он бы хотел видеть в пушах.
Криптобиржи
На данный момент в приложение интегрированы две популярные криптобиржи с общим количество торговых пар, превышающих 1000. Это биржи Kraken и Hitbtc. В последующих обновлениях список поддерживаемых бирж будет расширен такими известными площадками как: Binance, Bitmex, Bitstamp, Kucoin, Poloniex, что почти полностью покроет основные потребности трейдеров и сделает мониторинг простым и удобным как никогда.
Если же говорить о нашей общей цели и миссии – мы хотим познакомить людей с миром криптовалют, сделать порог входа в эту тему как можно легче и показать всем, что это удобно, полезно и перспективно.