редакции Выбор
Как мы вывезли Весёлого водовоза в доставку за час
С «Веселым водовозом», компанией, о кейсе которой пойдет речь в этой статье, мы успешно сотрудничаем уже 2 года.
На данный момент мы для них написали 2 приложения: водительское (служит для помощи в доставке и передаче заказа клиенту) и клиентское (служит для упрощения процесса заказа воды).
Статья будет полезна начинающим аккаунт/проджект-менеджерам, мобильным разработчикам, а также компаниям, которые хотят реализовать похожую функцию у себя.
Конкуренция за место под солнцем
Эта история начинается с Москвы и Яндекса.
Один из поставщиков артезианской воды в Москве начал сотрудничать с Яндекс.Доставкой, в результате многие компании доставки воды потеряли большое количество пользователей и были вынуждены закрыться.
Одной из основных причин этому стала фича доставки за час. Она настолько понравилась пользователям, что они быстро перешли на доставку воды от Яндекса.
Аналитики из «Веселого водовоза» решили перестраховаться и пришли к нам с запросом на реализацию доставки за час.
Выбор пути
Сначала казалось, что все просто: нам нужно было сделать так, чтобы координаты водителей поступали из приложения на сервер заказчика стабильно, не реже раза в минуту. Это было необходимо для того, что сервер заказчика мог просчитать, кого из водителей можно отправить на поступивший заказ с доставкой за час.
Сначала решили сделать отправку координат по таймеру из приложения, раз в 30 секунд, но быстро поняли, что в этой реализации координаты перестают поступать почти сразу, стоит только водителю заблокировать телефон или перейти в другое приложение.
То есть, вариант, конечно, работал, но не в бэкграунд режиме.
Следующей идеей было сделать отправку с бэкенда silent-push уведомлений, которые выводили бы приложение из background режима и вызывали бы отправку координат на сервер.
Кстати, обращаем ваше внимание:
FirebaseMessaging.onBackgroundMessage это правильный метод.
FirebaseMessaging.onForegroundMessage — неправильный.
На этапе первых тестов столкнулись с тем, что разработчик по ошибке указал не тот метод, и поэтому пуши просто не принимались. Еще подробнее про тестирование расскажу ниже.
Тестирование решения
Для того, чтобы проверить решение, мы сделали ветку со счётчиком пришедших silent-push уведомлений на главной странице приложения.
Нужно было проверить 2 сценария.
1. Работа в бэкграунде, если приложение свернуто:
- запускаем приложение;
- открываем маршрутный лист;
- проверяем, что координаты начали идти;
- отмечаем у себя время начала тестов;
- переходим в другое приложение (либо просто выходим из приложения по кнопке «Домой»);
- оставляем девайс на час;
- открываем приложение;
- проверяем количество пришедших уведомлений (с учётом того, что они отправляются раз в 30 сек, счётчик должен показывать 120);
- далее проверяем количество пришедших координат (мы запрашивали у заказчика скрин из их CRM-системы, на нем был отображён список всех пришедших по маршрутному листу координат с указанием времени, количество с момента открытия должно было равняться количеству пришедших сайлент пушей).
2. Работа приложения в бэкграунде, если экран телефона заблокирован.
Все шаги те же, но вместо перехода в другое приложение/выхода по кнопке «Домой», мы блокировали экран.
Минусы этого решения:
- если смахнуть приложение из системного трея, меню всех недавно открытых приложений, — работать не будет;
- если у приложения не стоит доступ к геолокации «всегда», — работать не будет.
О второй пункт мы споткнулись, да так больно, что успели уже похоронить надежду сдать заказчику задачу в полном объеме. Ситуацию вполне можно было назвать эпик фейлом.
При тестировании второго сценария у нас в момент блокировки просто переставали идти координаты на сервер. В коде с геолокацией проблем не было, пуши с сервера, судя по логам (лог — это текстовый файл, куда автоматически записывается важная информация о работе системы или программы), шли нормально. Ситуация казалось безвыходной.
Спустя 4 часа упорного тестирования, чтения документации, паники и попыток понять, где ошибка, до нас дошло, что проблемы, в общем-то, и не было.
При переустановке сборки слетело разрешение «использовать геолокацию всегда», стояло «только при использовании».
Итак, решение для iOS сработало, но этот вариант не подходил для Androd, потому что в операционных системах разный механизм работы в background-режиме, для Android не предусмотрен вообще вариант работы с silent-push уведомлениями, как и для iOS, к сожалению, невозможна реализация варианта описанного ниже.
Единственный вариант сделать отправку координат непрерывной — реализовать работу приложения в background режиме, как если бы это был сервис. В этом случае координаты не переставали бы поступать на сервер.
Для начала нужно было описать входную точку, которая будет работать с нативным кодом через Dart API.
А также создать инициализирующий метод для работы служб в режиме заднего фона.
Этот метод вызывается в мейне, до запуска самого приложения.
После чего, при запуске основного экрана, был подвешен обработчик ивента, отправляемого Dart’ом в background mode.
Приложение занимается прослушкой данного события, сообщая блоку, что ему нужно считать позицию от служб геолокации и отправить сообщение на сервер/телеграм.
Тестирование решения для Android
В целом, сценарии тестирования были такие же, как и на iOS, но без сверки с количеством silent-пушей, так как их тут не было. Нам надо было просто по логам посмотреть, что координаты идут стабильно.
Работа в бэкграунде, если приложение свернуто:
- запускаем приложение;
- открываем маршрутный лист;
- проверяем, что координаты начали идти;
- отмечаем у себя время начала тестов;
- переходим в другое приложение (либо просто выходим из приложения по кнопке «Домой»);
- оставляем девайс на час;
- открываем приложение;
- проверяем количество пришедших координат (мы запрашивали у заказчика скрин из их CRM-системы, на нем был отображён список всех пришедших по маршрутному листу координат с указанием времени, количество с момента открытия должно было быть не).
2. Работа приложения в бэкграунде, если экран телефона заблокирован.
Здесь все было куда проще, чем с iOS, но и это решение оказалось не без минусов. Все шаги те же, но вместо перехода в другое приложение/выхода по кнопке «Домой», мы блокировали экран.
Минусы:
- работает только если не смахивать приложение из меню «последних»;
- сильно съедает заряд батареи.
В ближайших планах ещё доработка по пушам. Необходимо сделать так, чтобы они отправлялись не каждые 30 секунд и не на всех водителей, а на определенных, и только когда координаты перестали поступать.
Однако глобально поставленная задача от клиента была решена.
Какие выводы сделала я лично для себя?
От глубины понимания PM-ом задачи зависит успех проекта в целом.
Поэтому после завершения работы над этой задачей я обложилась различной профессиональной литературой и по сей день стараюсь натаскивать себя в этой области.
Мне казалось, что понимать суть задачи и ожидаемый результат должно быть достаточным для моей работы. Сейчас я вижу, что это не совсем так и стараюсь расширять свои технические знания. Много читаю о том, как работают платформы и устройства, чтобы лучше понимать, что они могут, а что нет. В будущем это поможет мне избежать или эффективней выйти из похожей ситуации.
Второе, что я вынесла — не стоит недооценивать сложность подобных задач. Если изначально оценка задачи казалась мне большой, сейчас, оглядываясь назад, я понимаю, что здравая оценка на эту фичу должна быть раза в два больше.
В итоге, мы с разработчиками потратили вдвое больше времени на реализацию, а заработали, соответственно, меньше.
Важно, что такой опыт позволяет вырасти в х2 раза и в будущем быть эффективней в своих проектах.
Еще больше полезной информации о мобильной разработке и полезных лайфхаках в нашем telegram-канале «Рупор InstaDev mobile» или во ВKонтакте.