1 of 73

Slide Notes

Привет!

меня зовут Евгений Тютюев

занимаюсь разработкой под ios уже 5 год.

сейчас я работаю в компании SaintLab
и мы разрабатываем приложение для ресторанов
– Omonm

Хотелось бы поделиться опытом нашей команды
рассказать какие задачи перед нами появлялись и как мы их решали
DownloadGo Live

CodeFest Тютюев

Published on Nov 21, 2015

No Description

PRESENTATION OUTLINE

Ставка на iBeacon.

lessons learned
Привет!

меня зовут Евгений Тютюев

занимаюсь разработкой под ios уже 5 год.

сейчас я работаю в компании SaintLab
и мы разрабатываем приложение для ресторанов
– Omonm

Хотелось бы поделиться опытом нашей команды
рассказать какие задачи перед нами появлялись и как мы их решали

о чем

  • iBeacon?
в этом докладе я вам расскажу немного про технологию ibeacons
какие возможности она дает и какие подводные камни в себе она таит.

о чем

  • iBeacon?
  • Способы запуска приложения.
также расскажу про то как можно запустить приложение кучей способов и зачем вам это может пригодится

о чем

  • iBeacon?
  • Способы запуска приложения.
  • Socket как альтернатива Push.

о чем

  • iBeacon?
  • Способы запуска приложения.
  • Socket как альтернатива Push.
  • Аналитика
также пару слов как мы реализовали аналитику в приложении

Omnom

для начала как для меня появился Омном?

однажды Дима Сысоев позвал меня на собеседование и сказал

Хочу такое приложение, чтобы пользователь пришел в ресторан, заказал еду, покушал, достал свой телефон нажал оплатить, встал и ушел. Не дожидаясь официанта, не прося счет, не отдавая свою карточку незнакомому официанта и не дожидаясь сдачи.

Задачи

  • Определить ресторан
таким образом перед командой была поставлена следующая задача

понять что гость пришел в ресторан и сел за стол
определить ресторан и показать ему пуш – добро пожаловать, тут работает Omnom

Задачи

  • Определить ресторан
  • Определить стол
потом, когда гость запустит приложение,
определить стол

показать заказы для этого стола

оплатить счет

Задачи

  • Определить ресторан
  • Определить стол
  • Получить заказы на столе и оплатить
показать заказы для этого стола
оплатить счет

Как определить стол?

  • QR-код
  • Номер на столе
  • Спросить официанта
  • Или...
чтобы все это стало возможным нам как минимум нужно было узнать за каким столом сидит гость.

как определить стол?

наклеить на стол qr-код который его кодирует?
ввести номер стола в ручную?
спросить у официанта?

неее, не хватает магии.

Untitled Slide

и с этими словами Дима достал вот такую штуку
и сказал, - мы будем находить столы при помощи ibeacon's
Photo by avlxyz

lesson 1: iBeacon

  • UUID
  • major + minor
  • RSSI
Давайте для начала немного расскажу что такое iBeacon?

согласно википедии
айбикон это небольшой блютус лоу энерджи маячок, который с определенным интервалом передаёт пакеты установки соединения, не устанавливая само соединение,
эти пакеты содержат
UUID маячка
Major
Minor
и силу сигнала RSSI

чем больше rssi тем ближе бикон к телефону

таким образом зная rssi можно определить стол за которым сидит пользователь


Почему iBeacon?

  • iOS 7.0
  • все, кроме iPhone 4
чем хороши биконы для нас

так это тем что на всех ios девайсах под начиная с версии 7 ios кроме 4 айфона, есть поддержка этой технологии.

iBeacons:

  • Estimote
  • RedBear
  • Stick-n-find
  • RadBeacon
  • китайские unnamed
Так как на тот момент технология была новая и буйков нужно было много решили для начала закупить тестовую партию буйков от разных производителей

под наш взгляд попали
....


оказалось что не все биконы одинаково полезны

у естимотов нельзя было поменять батарейку, не разобрав сам маяк, и батарейка сама была маленькой емкости

стикнфайнд вообще были ужасные, - маленькая батарейка неадекватный апи, плюс постоянно терялся сигнал

у части китайских не было перепрошивки, у кого то не было адекватного апи

в общем поизучав все доступные маячки пришли к выводу, больше всех нам подходят redbear

почему RedBear?

в сдк redbear была вшита возможность перепрограммировать
следующие характеристики
uuid+major+minor

можно было менять силу сигнала и интервал с которым вещает бикон

и изменение всех характеристик маячка возможно только при вводе пароля

это большой плюс, так как мы хотели чтобы кто попало мог перепрошить бикон и внести суматоху в определение столов

при копании интернетов, оказалось что энергопотребление биконов полностью зависит от интервала вещания, а сила сигнала почти не влияет

заверению разработчкика при интервале вещания 250 мс, 2 батареек должно было хватить на 2 года работы
что тоже было в плюс этого маячка

Геолокационный регион

  • UUID
  • Уведомления: вход и выход
  • Поиск
  • Запуск приложения в фоне
Как же он работает?

в ios бикон представляет собой геолокационный регион
который может состоять из
uuid.

мы можем подписаться на регион и ios будет уведомлять нас каждый раз когда пользователь вошел и вышел из региона.

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

и также получим одно уведомление когда покинем область всех маячков с одним uuid.

также мы можем искать все биконы в указанном регионе.

причем если приложение не запущено, оно будет запущено в бг когда мы войдем или выйдем из региона

Как определить ресторан и стол?

  • major = ресторан
  • minor = стол
major кодирует ресторан
minor кодирует стол

Как определить ресторан и стол?

  • major = ресторан
  • minor = стол
  • UUID = регион
Так как количество регионов в ios на которые можно подписаться одновременно не больше 10.

То кодировать каждый ресторан и стол в регион не вариант.

Приходится создавать всего один регион, состоящий из uuid который кодирует нашу фирму.

таким образом, найдя любой наш UUID то приложение будет запущено в фоне

Первая проблема

мы запустились, но не знаем major+minor
первая проблема состояла в том что когда Айось находит бикон, кодированный только uuid'ом

она всеголишь знает что наш бикон где то рядом, но
она не сообщает его minor+major.

значит когда приложение запустилось в бг, нужно запустить бг таску и в ней найти все биконы с нашим UUID с major+minor+rssi.

Как узнать что мы рядом со столом?

На этом этапе мы знаем все список всех маячков, которые находятся рядом с телефоном.

эппл говорит, – что при сканировании биконов будет выдан массив всех биконов, которые были найдены телефоном, и самый первый бикон в массиве будет
ближе всего к телефону.

на практике все оказалось что первый бикон в массиве может быть намного дальше чем последний бикон в массиве


Расстояние до стола

оказалось что одного измерения недостаточно

решили найти усредненное значение rssi, по нему найти расстояние до бикона, понять что он находится на расстоянии меньше метра.

и рядом с ним больше нет ни одного бикона.

чтобы понять какие значения выдают биконы, собрали стенд на котором начали проверять различные конфигурации

Untitled Slide

Сначала посмотрели какая разница между значениями, которые вещают одинаково сконфигурированные биконы

Untitled Slide

потом смотрели как влияет сила сигнала от того как расположен телефон к биконам

Untitled Slide

потом меняли взаимное расположение биконов к телефону

Untitled Slide

смотрели как меняется сила сигнала от экранирования

мы выяснили, – сила сигнала очень сильно зависит от модели девайса.
от расположения самого девайса, и даже от того лежит ли он экраном вниз или вверх

и от расположения бикона и от экранирующей поверхности

Untitled Slide

ну и самое главное меняли расстояние от телефона до бикона

оказалось что бикон который находится на расстоянии 1 метр, может выдать сигнал сильнее чем бикон, который лежит в 30 см

Что хотели

мы думали что получим примерно такую картину
распределения силы сигнала

Что получили

оказалось что мы не можем разграничить биконы которых находятся на расстоянии до метра

на гафике указана чила сигнала для биконов находящихся на расстоянии от 30 см до 1.5 метров.

Гипотеза про силу сигнала

как видно из графика мы не сможем определить стол зная силу сигнала.

Следующим шагом решили менять силу сигнала маяка.

Оказалось, что при минимальной силе сигнала
rssi затухает очень сильно при удалении от девайса.

и можно не завязываться на самом значении
а только лишь на разнице между 2 разными биконами.

Untitled Slide

уменьшив силу сигнала до минимально возможной
получили такое распределение.

где белый бикон был на расстоянии примерно 30 см от телефона, а остальные на расстоянии больше метра.

Чтобы разрулить ситуации когда пользователь сидит не прямо у бикона, а примерно между 2 маячков
набираем статистику по 5 измерениям.

задача с определением стола была решена.

Боль 1

Отваливающийся BLE
в полевых условиях оказалось что периодически отваливается location manager и возвращает ошибку поиска биконов

помогает только перезагрузка телефона

в iOS 7.1.2 почти починили в ios 7.1.2+ возникает редко

Боль 2

зависший BLE
однажды Дима С звонит и говорит что в ресторане всегда ловится один и тот же стол

зайдя в аналитику я там увидел что действительно все время декодируется 4 стол.

так как большой ошибки не было видно и она больше не воспроизводилась, а то что не воспроизводится , того нет, про нее мы забыли.

однажды сидя дома и тестируя поиск столов, вместо одного маяка стал ловить еще один. выключив тот, что лежал на столе и ходя по квартире с телефоном начал искать второй. через какое то время выйдя в коридор и по прежнему находя стол я заподозрил неладное.

оказалось в какой то момент core location “зависает” и начинает в общем потоке биконов возвращать постоянно один и тот же “залипший бикон”.

таким образом даже если выключить буек, мы все равно будем его находить.

Оказалось что он выдает постоянный rssi, таким образом мы стали отбрасывать в декоде все маяки который выдают одинаковый rssi.

лечится только перезагрузкой девайса

Боль 3

столы
проблемы копились.

например оказалось, что 2 стола можно сдвинуть и это уже один стол или в случае длинного стола, один стол начинают кодировать 2 разных бикона.

например чем толще стол в заведении, тем меньше сигнал.

также для разных ресторанов могла потребоваться различная логика определения столов.

также могло понадобится игнорировать некоторые столы.

Решение

декодирования на серваке
в общем всю логику по определению ресторан + стол вынесли на сервак

Отправив на сервер 5 измерений uuid+major.minor.rssi
В ответ получали либо ничего, либо список ресторанов которые нашлись в бг либо конкретный ресторан, либо, если все прошло успешно ресторан и стол

это нам позволило менять логику определения на лету, сразу на двух системах ios+android без перезаливки в стор

Не повторяйте наших ошибок делайте также

Untitled Slide

Untitled Slide

Что в итого получили:

Телефон нашел бикон и запустил нас в бг.

нашли все биконы и декодировали их.

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

Сервак в ответ на это начинает каждые 2 минуты слать Сайлент пуш с флагом wake-up который будит нас в бг.

Запускаем бг таску и смотрим через кор мошен менеджер вектор силы тяжести, если мы не на столе то ничего не делаем.

Если на столе, то начинаем поиск и декодирование биконов.

Если находим стол, сообщаем серверу что пользователь сел за стол, он перестает слать пуши.

И показываем пуш добро пожаловать в ресторан.
На все эти танцы уходит примерно 6-7 сек

по нажатию на этот пуш запускаем приложение сразу на нужном столе.

Profit

по нажатию на этот пуш запускаем приложение сразу на нужном столе.

lesson 2: Запуск приложения

в какой то момент у нас появилось 2 сервака, тестовый и боевой.

началась реальная боль, нужно было собирать внутренние сборки, одни на бой одни на тест.
приходилось собирать сборки под тестовые рестораны, которых не было в общем списке.
приходилось блокировать в боевых сборках сырой функционал итд.

Запуск приложения

  • по local push
Помимо запуска приложения по локальному пушу.

оказалось что приложение может быть запущено кучей способов а именно:

Запуск приложения

  • по local push
  • по remote push
мы можем получить пуш с рекомендациями
и показать пользователю экран с рекомендациями.
Или пуш о том что наш счет готов и при нажатии на него открыть счет.

Запуск приложения

  • по local pushпо внешней url
  • по remote push
  • по бикону
также найдя новый регион в фоне нужно начать выполнять всю магию в фоне.

Запуск приложения

  • по local pushпо внешней url
  • по remote push
  • по бикону
  • по внешней url
отсканировать qr на столе или в счете в левой программе
она отредиректит на наш сайт, который запустит наше приложение по внешней URL
и открыть omnon сразу на этом столе или счете.

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

Как разрулили?

  • ***LaunchHandler
  • URLLaunchHandlerPushLaunchHandler
  • PushLaunchHandlerBeaconLaunchHandler
  • BeaconLaunchHandlerDefaultLaunchHandler
  • DefaultLaunchHandler
была введен LaunchHandler который отвечал за способ запуска.
от которой были унаследованы все возможные способы запуска.

был создан Router который управляет всей иерархией контроллеров.

каждый LaunchHandler знает что прокинуть Router.
чтобы правильно обработать запуск приложения.

Untitled Slide

у нас появилась страничка, где есть список ulr-ов

перейдя по которым с телефона мы может запустить приложение в любом ресторане.
посмотреть счета на любом столе.

Что дает?

  • конфиги
  • быстрая отладка
  • ios + android
также бонусом это нам дало что мы можем запуститься как на боевом сервере так и на тестовом.

всего лишь запустив приложение по определенной ссылке,

без необходимости пересобирать приложение.

что очень ускорило процесс тестирования и отладки.

такую штуку можно реализовать также Android

делайте также :)

lesson 3: Данные

Помимо запуска приложения по локальному пушу.

оказалось что приложение может быть запущено кучей способов а именно:

lesson 3: Данные

Помимо запуска приложения по локальному пушу.

оказалось что приложение может быть запущено кучей способов а именно:

Нужно прокидывать данные

  • real-time
  • много
  • кроссплатформенно
  • гарантированно
помимо того что мы можем получить счета за столом
нам нужно было прокидывать все изменения связные со счетами.

такие как оплата, добавление продуктов, закрытие счета.

требования были следующими.

Пуши?

  • мало
  • тяжело
  • задержки
сначала смотрели в сторону пушей

но пуши можно отключить,
ограничен размер.
256 байта
в ios8 2 кб

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

Untitled Slide

Socket?

писать все на юниксовых сокетах не хотелось.

WebSocket?

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

Socket.IO

внезапно нашлась библиотечка socket.io.

которая позволяла все это разрулить.

В андроиде было готовое решение, а вот нормальной socket.io библиотеки под ios в тот момент не было.

пришлось использовать webview в котором крутился node.js скрипт, который осуществлял всю работу с socket.io.

проброс сообщений туда и обратно был сделан через
JSContext *context;

при сворачивании приложения, скрипт останавливается. при разворачивании запускается заново авторизуется и коннектится ко всем комнатам.

Socket.io

  • гарантированные
  • много
  • ping
  • комнаты
какие приемущества мы получили?

можем очень быстро фильтровать события которые хочем получать а какие нет.

на серваке были созданы комнаты на события за которым мы хотим следить. чтобы начать получать события нам нужно зайти в нужную комнату.

например, - зашли на экран счета, присоединились к комнате счета.

обновился счет, прилетело событие обновление счета сразу с готовым json который сразу можно показать, мгновенно, без всяких рест задержек и
ограничений по размеру пушей.
+ гарантированная доставка.

недостаток только в том, что сокеты не работает когда приложение свернуто.

Выводы по сокетам

  • масштабируюется
  • любой размер сообщения
  • Кроссплатформенные
В общем по поводу сокетов.

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

Если в приложение нужно прокидывать относительно большые объемы данных.

это решение кроссплатформенное есть как для веба, для ios и android.

lesson 4: Аналитика

Так как наше приложение активно работает с пользователями, процессит оплату.

С самомго начала было понятно что без аналитики не обойтись.

Так как задач на команду было много,
решили не писать свой велосипед а использовать готовое решение.

Требования

  • готовое решение
  • в реальном времени
  • фильтры + воронки
  • iOS + Android

требования были следующими:
должна работать в реальном времени.
должна быть возможность строить всевозможные воронки и фильтры.

Под наши нужды лучше всего подошел Mixpanel. Хорошая кроссплатформенная библиотека которая работала под ios+android.

Mixpanel

Что логировали?

благодаря тому что мы использовали ibeacons
у нас появилась возможность логировать следующие события:

гость прошел рядом с рестораном.
гость вошел в ресторан.
гость сел за стол.

соответственно все эти события уходили в аналитику.

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

без ibeacon это было бы невозможно.

Что дало?

  • воронка
  • конверсия


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

на моменте шел мимо можно предложить скидку.
на моменте сел за стол можно предложить блюдо дня.
на моменте посмотрел чек можно предложить дозаказать на основе его предпочтений и заказа.

Untitled Slide

также было введено разделение статистики на 2 типа

1) бизнесс аналитика, –
оплаты,
посещения,
в общем все что помогает считать доходы и конверсию.

2) плюс системная аналитика, –
общение с сервером и различные действия пользователя в приложении.

также запросы\ответы от экваеринга, чтобы разруливать спорные ситуации.

Уровни логирования:

  • required
  • debug
для системной аналитики были введены разные уровни логирования, от логируем все до логируем ничего.

уровень логирования получались с сервера при старте приложения

на начале разработки на каждую спорную ситуацию создавалось отдельное событие.

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

request-id

типичная боль разработки, случился косяк, приложение зависло, выдало левую ошибку или вообще закрашилось.

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

только осталось проблема, - откуда взялся этот косяк?
так как система довольно сложная, и было много связующих звеньев, любое из них могло дать сбой.

чтобы найти всю цепочку запросов которая принимала участие в проблеме.

Через все запросы на сервере в хедерах пробрасывается request-id.

по которому можно узнать где родился запрос и проследить всю цепочку по которой он шел.

и в мобилке этот request-id тоже уходит в аналитику.

Аналитика

  • чем больше тем лучше
  • разруливание косяков
  • докозательства
  • тесты
в общем по поводу аналитики,

лучше перелогировать чем недологировать.

разруливание спорных ситуаций проходит за минуты вместо дней.

у вас всегда есть доказательства вашей правоты или косяка.

очень часто можно воспроизвести баг и написать на него тест имея все исходные данные.

в целом аналитика это лучик света в темном царстве косяков и недопонимания.

iBeacon

  • привязка
технология ibeacons открывает возможность геотаргетированного поведения вашего приложения.

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

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

пример с картинной галереей

iBeacon

  • привязка
  • iBeacon = телефон
помимо самих маячков сам телефон может выступать в качестве ibeacon.

iBeacon

  • привязка
  • iBeacon = телефон
  • bluetooth =(

на данный момент самая большая проблема с этой технологией это выключенный блютус у 95% пользователей.

если вам необходим такой функционал сможете донести до пользователя что разница между вкл и выкл BLE составляет около 1% потребления аккумулятора, то будет вам счастье.

iBeacon

  • привязка
  • iBeacon = телефон
  • bluetooth =(
  • iOS + Android

Socket.io

  • масштабируемый

Socket.io

  • масштабируемый
  • web + iOS + Android

Socket.io

  • масштабируемый
  • web + iOS + Android
  • real-time

Запуск приложения

  • myapp://
  • одна сборка
  • быстрая отладка

Вопросы?