Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 1980 сообщений
Cообщения с меткой

разработка мобильных приложений - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

Московский Droidcon 2016: взгляд со стороны

Четверг, 29 Сентября 2016 г. 15:21 (ссылка)

Команда наших Android-разработчиков побывала на Droidcon 2016 в Москве и осталась не слишком довольна мероприятием. Мы делимся своим мнением про программу, доклады и общую атмосферу на Droidcon и призываем сообщество к дискуссии. Надеемся, что открытое обсуждение конференции будет способствовать ее улучшению в будущем.









image

Артем Кулаков

“Droidcon в этом году выдался весьма посредственным. Интересных докладов было очень мало, а некоторые и вовсе были маркетинговыми. Тема тестирования не была затронута вообще, хотя, как я считаю, это не самая сильная сторона Android-разработки в данный момент и хорошие, практические доклады на эту тему очень хотелось бы видеть на мероприятии подобного уровня. Тем более Google вкладывает немалые ресурсы в развитие тестирования.

Отдельным пунктом стоит организация мероприятия. Видно, что организаторы старались, но получилось весьма блекло. Развлечения, конкурсы, стенды с интересными разработками, где это все? Все эти, казалось бы, бесполезные вещи весьма способствуют нетворкингу, за которым, собственно, и стоит ходить по конференциям. Как результат: послушали ряд докладов (почти без перерыва), поели, послушали еще ряд докладов и ушли домой. Все это несколько скрасила afterparty, но там было от силы 30 человек, и у большинства участников конференции не было и этого впечатления.”




image

Владислав Шипугин

“Конференция — это место, где можно пообщаться с коллегами, обменяться опытом. Когда на доклад выделяется полчаса, очень трудно рассказать о чем-либо, а отсутствие перерывов не позволило обсудить доклады и нормально пообщаться. Хардкорных докладов не было. На конференции были затронуты такие темы, как новый Android, архитектура мобильных приложений и firebase. Из-за отставаний по графику во втором зале произошел сдвиг докладов, и я пропустил интересный доклад про Unsafe, видимо придется смотреть видео. Это был мой первый Droidcon, и все же это было здорово. Приятно, когда рядом много людей, которые понимают, как трудно писать код под Samsung”.



image

Александер Блинов

“Прошлый московский Droidcon был посвящен архитектуре приложений. Именно на нем у меня и моего друга возникла идея написать MVP-библиотеку, которая решила бы все озвученные проблемы, и в этом году мы представили свое MVP-решение Moxy на крупнейшей Android-конференции в России. Надеюсь, оно будет полезно для сообщества. В целом, уровень московского Droidcon понизился — это выразилось в квалификации и подготовке докладчиков, а также уменьшении количества хардкорных докладов и заграничных спикеров. Были и реально интересные темы, такие как MVVM и Unsafe. Надеюсь, в следующем году таких докладов будет больше”.



image

Сергей Зароченцев

“Жаль, что Droidcon шел всего один день, да и тот рабочий. Московские Droidcon, увы, по-прежнему уступают нью-йоркскому и берлинскому по уровню докладов. В этом году, как и в прошлом, очень много внимания уделялось архитектуре: если про MVP уже говорили очень много, то подход с ViewModel — в новинку. Интересно, доведет ли все же Google до ума свой Data Binding или нет? Интересно было послушать и про новый, модный Firebase. Здесь о нем было целых три доклада. Стоит отметить также доклад про sun.misc.Unsafe. Забавно, что в Android-разработку стали проникать хардкорные вещи из большой Java. Также были интересны доклады Дениса Неклюдова про Android Nougat (который не принес никаких радикальных изменений) и Александра Смирнова про UI. Однако меня удивляет отсутствие на Droidcon тем, связанных с Rx, Kotlin и тестированием”.



image

Илья Шульгин

“Вот и пролетел так давно ожидаемый всем русскоязычным Android-сообществом московский Droidcon 2016. Именно пролетел, а не прошёл – в этом году конференция длилась всего один день. Огорчило то, что вообще никак не затронули Kotlin, который сейчас переживает пик своей славы.

В остальном конференция оправдала ожидания – новые фишки Нуги разложены по полочкам, хорошо освещён Firebase, был ряд докладов по VR и IoT. Спикеры разобрали интересные кейсы по автоматизации, архитектуру тоже не обошли стороной. Большое спасибо авторам докладов и организаторам за проведение конференции! Очень надеюсь на то, что следующий Droidcon будет ещё сильнее насыщен интересными выступлениями!”




image

Александер Михалевич

“К сожалению количество докладов и их средний уровень оказались пониже чем в прошлом году. Особенно неприятно удивил уровень организации конференции. Первый же доклад был задержан на 20 минут, а потом еще и сопровождался техническими проблемами. Впоследствии время на перерыв между докладами было сокращено до пяти минут, а потом совсем исчезло, переключив мероприятие в режим нон-стоп.

Начало дню, уже по традиции, задал Денис Неклюдов со своим докладом об Android Nougat. Весьма интересным оказался доклад от создателя библиотеки Moxy — Юрия Шмакова. Эта библиотека выделяется своим механизмом взаимодействия между моделью и представлением в шаблоне MVP, позволяющем не думать о жизненных циклах компонентов Android. Даниил Сердюков своим докладом замотивировал поближе познакомиться с паттерном MVVM. А единственный хардкорный доклад был от Александра Ефременкова. Александр рассказывал как аллоцировать и использовать память с помощью класса sun.misc.Unsafe. В завершении дня Александр Смирнов направил всех на путь истинного UI-самурая”.




image

Никита Трегубов

“Смена организаторов (и места проведения) очередного слета отечественных адептов зеленого человечка не пошла на пользу никому, кроме кассиров. Думаю, нет ни одного разработчика, посетившего мероприятие и не упомянувшего про крайне унылую его атмосферу, от неоправданно затянувшейся регистрации и сдвига всего графика на 20 минут, до включения в программу рекламных докладов и даже прямых попыток хантинга. От себя добавлю, что умудрился зафейлить буквально каждый шаг онлайн-регистрации, в результате чего обзавелся лишним почтовым ящиком и неприятным осадком ещё до начала выступлений.

Что касается самой сути, было немного интересной информации, в частности, детали адаптации под Android N и более-менее подробный обзор сервисов Firebase, разрекламированных на последней Google I/O. Ничего такого, чего не успел уже «потрогать» интересующийся специалист в свободное время, но полезно для тех, у кого этого времени не было. Полезность докладов несколько преуменьшил также непривычный для формата нормальной конференции лимит в 30 минут. В общем и целом, мероприятие вызвало диссонанс с прошлогодним и заставило поностальгировать по mail.ru как по весьма неплохому организатору”.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/311332/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Как я делал игру индейцев Центральной Америки

Среда, 28 Сентября 2016 г. 22:48 (ссылка)

Хочу представить вашему вниманию небольшую статью о том, как я делал для Android пулук — настольную игру индейцев Центральной Америки.



"Обучать" компьютеры человеческим играм я начал едва научившись программировать. Первым был калах (разновидность манкалы) для калькулятора МК-61. Позже — Волк и овцы, сначала для MS-DOS, а потом и для Android.



Общие сведения об игре



Читая на Хабре статьи GlukKazan, я наткнулся на интересный ЖЖ Дмитрия Скирюка с описаниями настольных игр разных народов мира. Одна из них — пулук — меня на столько увлекла, что я решил реализовать ее для Android.



Историю игры, а также ее сакральное значение для урожаев маиса можно прочесть в ЖЖ Дмитрия. Я же приведу здесь лишь правила.



Доска для пулука состоит из 11 полосок, причем первая и последняя служат "городами" для фишек игроков. Фишек у каждого игрока по пять штук. Вместо игрального кубика обычно используются четыре кукурузных зернышка, у которых одна из сторон каким-либо образом помечена. Очки считаются так:




  1. одно из четырех зерен выпало пустой стороной вверх — одно очко

  2. два зерна выпали пустой стороной верх — два очка

  3. три зерна — три очка

  4. четыре зерна — четыре очка

  5. все зерна выпали метками вверх — пять очков



В начале игры все фишки игроков стоят в "городах". Во время своего хода игрок бросает зерна и перемещает одну из своих фишек на соответствующее число полосок по направлению к "городу" соперника.



Две фишки одного игрока не могут занимать одну полоску (кроме "города"). Но можно ставить свою фишку на полоску, на которой стоит фишка противника — брать эту фишку в плен. Далее этот столбик продолжает двигаться как одна (верхняя) фишка и может брать в плен другие фишки противника.



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



Когда игрок приводит столбик в "город" на другом конце доски, то все плененные фишки выводятся из игры (бьются), а своя возвращается в свой город и снова может вступить в игру. Точный бросок для захода в "город" противника не нужен.



Побеждает игрок, который захватит или побьет все фишки противника.



Как пишет Дмитрий: "Несмотря на кажущуюся простоту и непривычно маленькую доску, пулук очень увлекателен. Тактика его уникальна, он не похож на игры других народов: это не гонки с преследованием, не военная игра и не «переходы» вроде Уголков, а некая хитрая «ловилка-уводилка»".



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



Второе изменение связано с освобождением своих фишек из плена. У Дмитрия сказано: "а нижняя фишка, бывшая в плену, освобождается и продолжает путь самостоятельно". Но в случае одновременного освобождения нескольких фишек, возникает ситуация, когда все они занимают одну полоску. А это противоречит правилу "Две фишки одного игрока не могут занимать одну полоску". В англоязычных же правилах освобождение своих фишек происходит лишь когда столбик достигает "города" на противоположной стороне доски — все свои фишки освобождаются, а фишки противника бьются. В моем варианте освобожденные фишки сразу перемещаются в свой город. Это не приводит к нарушению других правил и позволяет вводить фишки снова в игру очень быстро.





Технические особенности



В техническом плане игра, наверное, особого интереса не представляет, так как особых хитростей при разработке я не использовал. Программировал Android-приложение я с помощью фреймворка AndEngine. Хотя он в последнее время практически не развивается, его возможностей мне вполне хватило.



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



Разработка ИИ



Случайный характер выпадающий игровых очков не позволяет прогнозировать следующие ходы и использовать, например, альфа-бета алгоритм для реализации ИИ. Во время своего хода игрок может выполнить (при возможности) одно из следующих действий:




  • вывести фишку из "города"

  • захватить в плен фишку противника

  • освободить из плена свою фишку

  • вывести из игры плененные фишки противника



Например, при следующей ситуации:





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



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




  1. Найти все доступные ходы

  2. Присвоить каждому ходу его вес

  3. Выбрать ход с наибольшим весом.



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



public class OpponentAIFirstController extends OpponentAIController {

protected static final int WEIGHT_IND_HOME = 0;
protected static final int WEIGHT_IND_CAPTURE = 1;
protected static final int WEIGHT_IND_RELEASE = 2;
protected static final int WEIGHT_IND_CAPTURED_MOVE = 3;

protected float movementWeights[];

public OpponentAIFirstController(...) {
super(...);
initMovementWeights();
}

protected void initMovementWeights() {
movementWeights = new float[] {1.0f, 1.1f, 1.1f, 1.5f};
}

private void calcInitialScores(int pCornsValue) {
for(i = mFirstChipIndex; i < mLastChipIndex; i++) {
...
int newRow = mFieldController.calcNewRow(curChip, pCornsValue);
if (mFieldController.isHomeRow(newRow)) {
mMoveScores[j] += 1 + curChip.capturedCount();
mMoveScores[j] *= movementWeights[WEIGHT_IND_HOME];
continue;
}
...
}
}
...
}

public class OpponentAISecondController extends OpponentAIFirstController {
...
@Override
protected void initMovementWeights() {
movementWeights = new float[] {1.0f, 2.0f, 1.1f, 1.1f};
}
}


На самом деле кое-какие предсказания можно сделать, основываясь на теории вероятностей. Например, если перед рассмотренной выше ситуацией выпадали значения 5, 5, 4, 3, 2, 3, то с высокой долей вероятности можно предположить, что противнику выпадет значение 1. В этом случае крайне желательно спасти от пленения фишку, стоящую на 8-й полоске. Поэтому третий алгоритм, который я разработал, запоминает выпавшие значения зерен и приписывает высокий вес тем ходам, которые спасают фишки от потенциального пленения.



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



Дабы привнести некоторый образовательный элемент в игру, в диалог выбора ИИ я добавил ссылки на соответствующие статьи на Wikipedia, а в диалог "О программе" — ссылку на статью Дмитрия о пулук.









После некоторого количества игр я получил следующую статистику:





Итог



Пулук действительно оригинальная и забавная игра. Теперь "играть партия за партией до изнеможения" можно на дому. С помощью Internet и Google Play Game Services даже можно сразиться с настоящим майя. Ну а фермеры могут проверить ее влияние на урожаи кукурузы :)


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/310404/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Перевод] Разработка взаимодействия с пользователем мобильных устройств — ключевые принципы

Среда, 28 Сентября 2016 г. 16:50 (ссылка)





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



Хорошая разработка пользовательского интерфейса решает обе эти проблемы проектирования:




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

  • Пользовательский интерфейс обязан быть предельно ясным. Чтобы эффективно использовать разработанный вами интерфейс, должна быть обеспечена возможность легко понимать, для чего он и как его использовать. В нём просто не должно быть ни малейшего места для какой-либо путаницы.



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



1. Не допускайте перегруженности



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





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



Есть знаменитое высказывание писателя Антуана де Сент-Экзюпери: «Совершенство достигается не тогда, когда уже ничего нельзя добавить, а когда уже ничего нельзя убрать». В интерфейсе мобильного приложения важно избавиться от всего, что не является абсолютно необходимым; снижение загруженности улучшает понимание.



Простое эмпирическое правило: должно быть только одно основное действие в каждом окне. Каждое окно, разработанное вами для приложения, должно поддерживать только одно-единственное действие, представляющее ценность для пользователя. Это облегчает обучение, использование и добавление, или встраивание при необходимости. Иметь сто продуманных по заполненности окон лучше, чем иметь одно забитое до предела.



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





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



2. Обеспечьте интуитивно понятную навигацию



Помощь пользователю в навигации должна быть приоритетной для каждого приложения. Хорошая навигация должна ощущаться как невидимая рука, направляющая пользователя по его пути. В конце концов, даже самая крутая фишка или самый привлекательный контент являются бесполезными, если люди не могут найти их. Принципы хорошей навигации в приложении для мобильного устройства:




  • Навигация должна быть ясной. Необходимо использовать надлежащие символы (правильные зрительные образы), чтобы для навигации не требовались какие-либо пояснения, и следует обеспечить, чтобы каждый элемент навигации (такой как, например, иконка) приводил к надлежащему месту назначения.








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

  • Навигация должна обеспечивать пользователя информацией о его текущем нахождении в приложении. Отсутствие такой индикации является, вероятно, одной из наиболее распространённых ошибок, которые встречаются во многих меню приложений. «Где я?» — один из основных вопросов, ответ на который требуется пользователям при навигации.





3. Обеспечьте продуманное взаимодействие



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





Apple Music



Возьмите для примера Apple Music. Вы можете поместить плей-лист на ваш Mac, и он немедленно станет доступным на вашем iPhone. Apple осознаёт, что, в то время как структура мобильного приложения имеет чрезвычайно большое значение, продуманное взаимодействие между iPhone, Mac и IPad также важно для пользователей.



4. Разрабатывайте сенсорные элементы управления такими, чтобы они были удобными для пальцев



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



Размеры элемента управления должны быть 7-10 мм, так чтобы палец мог точно накрыть его. Такой элемент позволяет пользователю удобно расположить палец внутри него. Края элемента будут видны из-под пальца. Это обеспечивает пользователю ясную обратную связь, показывающую, что контакт с элементом управления обеспечен.





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



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



5. Тексты должны быть удобочитаемыми



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



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





Изображение получено от Apple.



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





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



6. Делайте элементы интерфейса хорошо видимыми



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



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




  • Малый текст должен иметь контраст, как минимум, 4,5:1 относительно фона.

  • Большой текст (начиная с 14 точек для полужирного и 18 точек для обычного) должен иметь контраст, как минимум, 3:1 относительно фона.





Текст, не отвечающий рекомендациям по цветовому контрасту, трудно читать. Изображение получено от Apple.



Чрезвычайно важно иметь достаточный контраст на мобильном устройстве: при нахождении на открытом воздухе контраст может быть низким из-за внешней освещённости.





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



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





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



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



Стивен Хубер в своём исследовании по использованию мобильных устройств показал, что 49% людей полагается только на большой палец, чтобы проводить какие-то операции на своих телефонах. На рисунке ниже области, показанные на экранах мобильных телефонов, цветом ориентировочно информируют, какие участки экрана пользователь может достать большим пальцем, чтобы взаимодействовать с ними.





Удобные зоны для управления смартфоном одним пальцем. Изображение получено от uxmatters.



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




  • Важно расположить меню верхнего уровня, часто используемые элементы управления и элементы типовых действий в зелёной зоне экрана, поскольку их тогда можно удобно достать одним пальцем.







Типовые действия тамблера. Изображение получено от Capptivate.




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



8. Минимизируйте необходимость ввода с клавиатуры



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




  • Формы должны быть предельно короткими и простыми и содержать только абсолютно необходимые поля.







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




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





Поле с автозаполнением для страны



9. Тестируйте вашу разработку



Чрезвычайно часто мобильное приложение выглядит великолепно на большом экране настольного компьютера, но оказывается просто в разы хуже при тестировании на реальном мобильном устройстве. Даже, кажется, тщательнейшим образом проработанный продукт взаимодействия с пользователем, в конечном счёте, будет содержать некоторый дефект, который проявится в условиях реального использования. Поэтому чрезвычайно важно протестировать ваше приложение с реальными пользователями на множестве мобильных устройств. Вы должны просить реальных пользователей выполнять их регулярные задачи; только после этого можно будет понять, насколько, действительно, хорошо функционирует ваша разработка. Рассматривайте ваше приложение как постоянно развивающийся объект, используя данные из аналитики и отзывов пользователей, чтобы постоянно улучшать взаимодействие.



Заключение



Так же как с любыми другими элементами разработок, указанные выше советы являются лишь отправной точкой для размышлений. Соединяйте и согласовывайте эти идеи со своими, чтобы получить наилучшие результаты. Всегда помните, что любой проект предназначен, прежде всего, не для разработчиков, а для пользователей.
Original source: habrahabr.ru.

https://habrahabr.ru/post/310956/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

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

Среда, 28 Сентября 2016 г. 14:24 (ссылка)



Badoo — это сервис знакомств, который доступен в виде сайта и мобильных приложений под основные платформы. В начале прошлого года мы глобально переработали сайт, в результате чего он превратился в «толстого клиента» и стал работать так же, как и мобильные приложения: вызывать команды на сервере и получать от него ответы согласно протоколу, описывающему взаимодействие клиентской и серверной частей. Эти две части делаются разными разработчиками, и, как правило, клиентская часть делается уже после того, как серверная будет готова. При этом есть проблема: как разработчик новой фичи может убедиться, что серверная часть работает корректно, если клиента для нее пока нет и проверить ее не на чем?



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



Что это такое и как это работает?



В нашем случае эти тесты представляют собой надстройку над PHPUnit, благодаря которой тест становится приложением-клиентом, которое обращается к серверу по протоколу. При этом есть возможность настроить, к какому именно серверу мы хотим обратиться. Это может быть:




  • площадка разработчика;

  • «шот» — специальная площадка с «боевой» базой, на которую выкладывается код создаваемой фичи;

  • «стейджинг».



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



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



class ServerGetUserGiftsTest extends BmaFunctionalTestCase
{
public function testGiftsSending()
{
// Given
$ClientGiftSender = $this->getLoginedConnection(
\BmaFunctionalConfig::USER_TYPE_NEW,
[
'app_build' => 'Android',
'supported_features' => [
\Mobile\Proto\Enum\FeatureType::ALLOW_GIFTS,
],
]
);
$ClientGiftReceiver = $this->getLoginedConnection();

$gift_type = 1;
$gift_add_result = $ClientGiftSender->QaApiClient->addGiftToUser(
$ClientGiftReceiver->getUserId(),
$ClientGiftSender->getUserId(),
$gift_type
);
$this->assertGiftAddSuccess($gift_add_result, "Precondition failed: cannot add gift from sender to receiver");

// When
$Response = $ClientGiftSender->ServerGetUser(
[
'user_id' => $ClientGiftReceiver->getUserId(),
'client_source' => \Mobile\Proto\Enum\ClientSource::OTHER_PROFILE,
'user_field_filter' => [
'projection' => [\Mobile\Proto\Enum\UserField::RECEIVED_GIFTS],
],
]
);

// Then
$this->assertResponseHasMessageType(\Mobile\Proto\Enum\MessageType::CLIENT_USER, $Response);
$user_received_gifts = $Response->CLIENT_USER['received_gifts'];

$this->assertArrayHasKey('gifts', $user_received_gifts, "No gifts list at received_gifts field");
$this->assertCount(1, $user_received_gifts['gifts'], "Unexpected received gifts count");

$gift_info = reset($user_received_gifts['gifts']);
$this->assertEquals($ClientGiftSender->getUserId(), $gift_info['from_user_id'], "Wrong from_user_id value");
}
}


Давайте разберем этот пример по частям.



Каждый тест наследуется от класса BmaFunctionalTestCase — наследника PHPUnit_Framework_TestCase. В нем реализовано несколько вспомогательных методов, главным из которых является возможность получения объекта клиента, через который можно отправлять запросы к серверу:



$ClientGiftSender = $this->getLoginedConnection(
\BmaFunctionalConfig::USER_TYPE_MALE,
[
'app_build' => 'Android',
'supported_features' => [\Mobile\Proto\Enum\FeatureType::ALLOW_GIFTS],
]
);


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



Этого зарегистрированного пользователя мы берем из специального пула тестовых пользователей. В нем есть некоторое количество «чистых» пользователей, т.е. все они имеют одно и то же начальное состояние. Когда в тесте вызывается метод getLoginedConnection(), выбирается один из этих пользователей, и он блокируется для использования другими тестами. Блокировка нужна для того, чтобы мы всегда имели дело с пользователями в известном нам состоянии. После блокировки с этим пользователем можно проводить любые манипуляции, а после окончания работы теста запускается механизм очистки, который приведет пользователя в исходное «чистое» состояние, и тот снова будет доступен для использования в тестах. Все тестовые пользователи находятся в одной локации, в которой нет реальных пользователей. Поэтому, с одной стороны, мы в тестах имеем дело с предсказуемым окружением, а с другой — реальные пользователи не видят тестовых.



Как правило, мы не можем запускать проверку сразу после получения объекта клиента: нужно создать окружение, необходимое тесту (в данном примере — отправить подарок другому пользователю). Делать это мы можем «честно», отправляя запросы серверу через объект клиента, но это не всегда возможно. В случае подарка «честный» путь был бы слишком сложным: нам нужно пополнить счет пользователя, получить список доступных подарков, отправить его и дождаться, пока он будет обработан скриптом отправки. Все это усложнит тест и увеличит время его разработки и выполнения.



Чтобы это упростить, мы используем внутренний инструмент под названием QaAPI (про него уже рассказывал мой коллега Дмитрий Марущенко, презентацию и видео можно найти на «Хабре»). Он состоит из множества небольших методов, каждый из которых позволяет совершать отдельные действия над пользователями в обход стандартных механизмов или получить какие-то сведения о пользователе. С его помощью можно добавить пользователю фотографии и сразу отмодерировать их, минуя очереди и проверку модераторами; изменить значения отдельных полей в его профиле, проголосовать за других пользователей в «Знакомствах» и т.д.



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



$gift_add_result = $ClientGiftSender->QaApiClient->addGiftToUser(
$ClientGiftReceiver->getUserId(),
$ClientGiftSender->getUserId(),
$gift_type_id
);
$this->assertGiftAddSuccess($gift_add_result, "Precondition failed: cannot add gift from sender to receiver");


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



Если мы по каким-то причинам не хотим «честно» приводить пользователя в нужное состояние, то мы можем использовать удаленные mock-объекты. В отличие от локальных, они бывают одноразовые (действующие только на одну команду) и постоянные (работающие до конца выполнения теста).



Технически mock-объекты реализованы с помощью другого нашего решения, SoftMocks. Оно используется либо напрямую (на площадке разработчика, когда тест работает в рамках одного процесса), либо через «прокладку» в виде memcache (на удаленной площадке). Во втором случае во время работы теста мы кладем информацию о новом mock-объекте в массив одноразовых или постоянных mock-объектов, а перед отправкой запроса на сервер объединяем эти два массива и кладем их в memcache, откуда их сможет забрать серверная часть.



Мы часто используем такие mock-объекты для проверок лексем, когда нужно убедиться, что в ответе придет нужный нам текст. Это можно сделать «честно», но это будет не очень удобно: тексты могут меняться со временем (и это будет ломать тест), плюс на разных языках они могут быть разные. Чтобы избежать этих проблем, мы заменяем лексемы на какие-то предопределенные значения или даже на пути к текстам.



В целом использование mock-объектов делает тест более быстрым, т.к. позволяет избавиться от одного или нескольких удаленных вызовов, но добавляет зависимости от серверного кода и делает их менее надежными: они чаще ломаются и больше «врут».



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



$Response = $ClientGiftSender->ServerGetUser(
[
'user_id' => $ClientGiftReceiver->getUserId(),
'user_field_filter' => [
'projection' => [\Mobile\Proto\Enum\UserField::RECEIVED_GIFTS],
],
]
);


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



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



$this->assertResponseHasMessageType(\Mobile\Proto\Enum\MessageType::CLIENT_USER, $Response);


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



$user_received_gifts = $Response->CLIENT_USER['received_gifts'];

$this->assertArrayHasKey('gifts', $user_received_gifts, "No gifts list at received_gifts field");
$this->assertCount(1, $user_received_gifts['gifts'], "Unexpected received gifts count");

$gift_info = reset($user_received_gifts['gifts']);
$this->assertEquals($ClientGiftSender->getUserId(), $gift_info['from_user_id'], "Wrong from_user_id value");


Для команд, которые модифицируют состояние пользователя, недостаточно проверить ответ сервера. Например, если мы отправляем команду на удаление подарка, то мало получить Success в ответе — нужно еще проверить, что подарок действительно удален. Для этого можно либо вызвать другие команды и проверить их ответы, либо воспользоваться тем же QaAPI, вызвав метод, возвращающий состояние параметра, который мы хотим проверить. В примере с удалением подарка мы могли бы вызвать QaAPI-метод, возвращающий список подарков и проверить, что в нем нет только что удаленного.



Какие достоинства?



Главное достоинство таких тестов — понимание того, что новый функционал работает так, как мы ожидаем. Если мы описали сценарий в виде такого теста и он прошел, то мы понимаем, что весь функционал работает и может быть использован реальным приложением-клиентом.



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



Какие недостатки?



Главными недостатками этих тестов является долгое время работы и нестабильность, вытекающие из их высокого уровня. Хотя тесты обычно проверяют результаты одной команды протокола, для них создается полновесное окружение, работающее с теми же базами и сервисами, что и у обычных клиентов. Все это, а так же «честное» воссоздание окружения, требующее других запросов (часто не одного-двух) к серверу, требует времени.



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



Из-за этой сложности тесты становятся очень «хрупкими»: поломка в воссоздании окружения сломает вам тест, и хотя проблема не относится к тому, что вы проверяете, ваш тест падает. Такие тесты не укажут вам, что именно сломалось, вы только поймете, что что-то не работает. Конкретный метод, изменение которого поломало тест, придется искать самостоятельно, а иногда сделать это бывает очень непросто.



Заключение



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



Виктор Пряжников, разработчик отдела Features


Original source: habrahabr.ru.

https://habrahabr.ru/post/311218/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Как это было: раскрываем детали Droidcon Moscow 2016

Вторник, 27 Сентября 2016 г. 12:46 (ссылка)

22 сентября в Москве прошла третья ежегодная конференция Android-разработчиков Droidcon Moscow 2016. В Технополисе собрались более четырехсот жадных до знаний участников, Google Developer Expert’ов и представителей СМИ. Мы впервые присоединились к организации этой конференции в этом году. И вот наш отчет.







Деловая программа проходила в два потока и была разделена на четыре секции: Android, VR, IoT и Firebase. Секцию Android открыл Google Developer Expert Денис Неклюдов с докладом об адаптации приложений под новые возможности API 24 (Android 7.0 Nougat). Обсуждение жизненного цикла Activity в условиях MultiWindow перенеслось в Issue Tracker андроида, что привело к интересным результатам: оказалось, что вызов onStop не произойдет, если пользователь нажмет кнопку “Домой” во время работы с многооконными приложениями, а вот on Pause вызовется. Юрий Шмаков из Arello Mobile рассказал об их собственной библиотеке для реализации MVP. Тема жизненного цикла и проблем наследования от множества библиотечных базовых Activity вызвала бурный интерес у слушателей.







Затем Никита Слушкин, разработчик Aviasales.ru, рассказал о решении наболевшей проблемы предоставления скриншотов локализаторам – таким образом, чтобы они понимали контекст тех строк, которые переводят. Даниил Сердюков из Kaspersky Lab поделился личным опытом реализации архитектурного подхода MVVM с помощью DataBinding. Несмотря на комментарии участников о собственном негативном опыте, Даниил настоятельно рекомендовал использовать этот подход в Android. Завершил первую часть секции Android Дмитрий Школьников из компании Tapcore докладом о рынке пиратства мобильных приложений. В комментариях к выступлению слушатели активно генерировали варианты обхода пиратов, а также рассказали о личном опыте публикации бесплатной версии своей игры на пиратских ресурсах.



Каждый год конференция Droidcon Moscow собирает профессионалов в области мобильной и Android разработки. В этом году постарались в программу конференции включить как можно больше практических докладов и примеров использования технологий и решений Google в продакшне приложений.



Наталия Ефимцева, Региональный менеджер программ взаимодействия с разработчиками, Google Russia






Вторую часть секции Android открыла Наталия Кривенко, руководитель по международному развитию Apps4All, c презентацией программы, посвященной международным перспективам для разработчиков. Сначала Лютс Лайксенринг представил сообщество Jobreloaded от глобального Droidcon, которое соединяет Android-разработчиков по всему миру и помогает им построить карьеру на международном уровне. Далее Дмитрий Григорьев из Rubrain, международной freelance-платформы, рассказал о преимуществах и недостатках работы с иностранными заказчиками, а также дал несколько советов о том, как наладить процесс работы и сделать его наиболее продуктивным.



Александр Ефременков из Surf добрался до самых глубин Android и несмотря на то, что доклад был сложным, смог за 20 минут объяснить детали даже тем, кто подобными вещами ранее не увлекался. Слушатели прониклись его рассказом о sun.Misc.Unsafe и с пониманием задавали вопросы о применимости инструмента в продакшене, а также интересовались о практической полезности данного подхода. Опытный разработчик и молодой видеоблогер Александр Смирнов из Splyt рассказал о тонкостях создания хороших UI-компонентов и нюансах профилирования производительности их отрисовки в рантайме. Продолжили программу представители 1С – Петр Грибанов и Анна Лавринова, которые рассказали об интеграции мобильных приложений с их платформой. Дмитрий Провоторов из Мануфактуры в своем докладе продемонстрировал эффектные решения в рамках жестких ограничений Google Material Design. Слушатели с интересом смотрели на тщательно подобранные образцы приложений, сделанные с соблюдением стиля Material Design, но при этом воплощенного в виде UI, не просто строго по гайдлайнам, а «с душой» и креативностью. Закрыл масштабную секцию Android Александр Белов из SPB TV c докладом о существующих технологиях стриминга контента с Android-устройств, причинах выбора той или иной технологии стриминга и некоторых проблемах, с которыми сталкиваются разработчики подобных мультимедиа-приложений.



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



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



@nekdenis Денис Неклюдов, старший Android-разработчик Revolut, GDE








Секция VR стартовала с доклада «Проектирование для Google Cardboard» от Михаила Вайсмана из Trinity Digital, одного из лидеров GDG Москва. Михаил рассказал о том, как делать крутые приложения для Google Cardboard с точки зрения проектирования и применяемых технологий на примере разработанного Trinity Digital приложения Airpano Virtual Travel для Android. Затем Александр Коршак – программист и энтузиаст, лидер GDG Нижний Новгород и Android Team Lead в компании Mera, рассказал о разработке для Daydream. Докладчик поделился хаками и нюансами разработки для этой платформы. На этом Александр решил не останавливаться и поделился своим опытом в презентации «Сферическое видео — взгляд изнутри».



Секцию IoT открыл Google Developer Expert Звиад Кардава. Звиад не просто рассказал, но и продемонстрировал в режиме реального времени участникам, как с помощью двустороннего зеркала, любого планшета на Android, экрана и скотча сделать умное зеркало, которое сможет показывать время, дату, погоду, последние новости или даже вашу ленту в Twitter. Продолжил секцию невероятно харизматичный иностранный GDE Саша Вольтер из Deutsche Telekom. Он рассказал об IoT и продемонстрировал необычные примеры использования интернета вещей. Также Саша объяснил участникам, с чем связаны опасения многих относительно этой концепции и показал, что начать строить свои решения в области IoT и соединять самые разные умные вещи не так сложно. Свои слова Саша подкрепил лайв-кодингом и демонстрацией того, как можно взаимодействовать с реальными устройствами из Minecraft и наоборот.



Далее Алексей Витенко и Женя Рыжкин из AppMetrica рассказали об автоматизации тестирования SDK под Android. Первым в финальной секции Firebase выступил Тимур Ахметгареев из App in the Air и рассказал об одной из core-фич Firebase – Firebase Analytics, а также об её интеграции с Notifications Console и Remote Config. Тимур рассмотрел несколько интересных сценариев использования этой связки, а также пробежался по обновлениям компонентов, перешедших под крыло Firebase: App Indexing, App Invites, Test Lab. Программу продолжил Сергей Сметанин из Rubeacon с презентацией о том, как в его компании применяли Firebase Remote Config и Realtime Database, а также о результатах, которых достигли благодаря этому. В заключение секции и всей деловой программы выступил Алексей Милеев из App in the Air. Известно, что Firebase позиционируется в том числе и как альтернатива ушедшему в небытие Parse.com. Алексей мигрировал свой проект с Parse на Firebase и рассказал о различных подходах к миграции, а также о проблемах, связанных с ними.







That's All, Folks! Фото выложим на этой неделе в официальной встрече на Facebook, а видеозаписи докладов будут готовы примерно через две недели. Следите за новостями.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/311126/

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Из песочницы] Зачем нужны UITableViewController и UICollectionViewController

Понедельник, 26 Сентября 2016 г. 18:07 (ссылка)

Всем привет, меня зовут Артём, я iOS-разработчик. Сегодня хочу рассказать о подходах к использованию UITableViewController и UICollectionViewController.



Едва ли можно найти мобильное приложение, в котором не используется списочное представление данных. Существенную часть времени мы (iOS-разработчики) проводим с TableView или CollectionView. Именно поэтому критически важным является выбор подходов к использованию этих базовых элементов из соображений скорости разработки и стоимости дальнейшей поддержки создаваемых решений. Хочу поделиться выводами, к которым пришли с коллегами в Touch Instinct.



Статья рассчитана на разработчиков, которые работают с TableView (CollectionView), но почему-то не работают с TableViewController (CollectionViewController). Далее будет упоминаться только TableView(Controller), но все написанное касается и CollectionView(Controller) тоже.



Вариант 1. MassiveViewController



Самый простой и привычный для многих вариант — когда разработчик создает в storyboard’е ViewController, располагает на нём TableView и указывает ViewController в качестве объекта, который будет реализовывать протоколы UITableViewDelegate и UITableViewDataSource.





Все хорошо, но не всегда. Порой, возникают проблемы. И возникают они, когда в данном контроллере появляется дополнительная логика, мало связанная с TableView. Ладно еще, если в контроллере появляются обработчики UIBarButtonItem’ов. Но, как правило, появляется в этом контроллере всё подряд: обработчики кнопок под (над/слева/справа) TabieView, различные всплывающие элементы, работа с сетью, конфигурирование ячеек и так далее. Налицо грубое нарушение принципов Single Responsibility. ViewController грустит… Еще больше грустят другие разработчики, когда видят такую картину.



Вариант 2. Sолидный



Рядового разработчика после первой встречи со статьями про SOLID начинают преследовать сомнительные идеи различной степени тяжести. Одна из таких идей заключается в повсеместном применении принципа Single Responsibility. В том числе, в ущерб здравому смыслу.



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





Но проблема такого подхода заключается в том, что UIKit зачастую затрудняет поддержку данного принципа. На деле получается, что тесно связанные между собой вещи оказываются по разную сторону баррикад. Элементарный пример: при расчете высоты ячейки (Delegate) необходимо знать её содержимое (DataSource). В конечном итоге всё может стать еще более запутанным, чем в предыдущем варианте.



Вариант 3. ПолуSолидный



Разработчик понял, что использование Sолидного варианта связано с определенными трудностями, и решил слегка упростить его. Для этого создается не два класса, а один, который реализует протоколы Delegate и DataSource. Данный вариант реализовать легче, но и у него есть свои недостатки, которые заключается в том, что все равно необходимо создать дополнительный класс и обеспечить двустороннюю связь между ViewController’ом и объектом, реализующим протоколы.







На самом деле все просто



Когда-то давным-давно обсуждали эту проблему с коллегами. И тут один опытный разработчик сказал: «А что тут обсуждать-то? Все и так есть из коробки».



И ведь действительно есть. Почему-то многие разработчики не используют TableViewController, аргументируя это тем, что есть отдельный TableView, который можно положить на view, как захочется. На это хочется ответить двумя аргументами:




  1. Практически всегда TableView будет растягивается на всю view – не проще ли сразу использовать TableViewController?

  2. Если TableView будет расположен не на всю view, значит будут присутствовать другие элементы, а связанный с ними код появится в ViewController’е.



Нет ничего хорошего в том, что код TableView смешивается с кодом других элементов, за которые отвечает ViewController. А представьте насколько усугубляется картина, если речь идет об iPad приложении и на экране больше чем две таблицы, которые обрабатываются одним ViewController’ом.



Подход, который я предлагаю рассмотреть – компромисс между Sолидностью и простотой. Заключается он в отказе от отдельно лежащих TableView. Последние версии iOS и Xcode позволяют применять данный подход без боли и мучений, с удобством и удовольствием.





Многим придется не по вкусу идея плодить ViewController’ы, но на деле они будут появляться только там, где это действительно нужно. К примеру, стоит задача сделать таблицу на весь экран. Лучше сразу использовать для этой цели TableViewController. Если нужно добавить такую же таблицу куда-нибудь еще, то вы спокойно сможете переиспользовать данный TableViewController, т.к. в нём будет только относящаяся к таблице логика и ничего лишнего.



Если вдруг появилась необходимость изменить расположение TableView, то просто создается отдельный ViewController, в который интегрируется TableViewController (через ViewController Containment). Данное решение является настолько коробочным, что все можно сделать через storyboard:





А еще интегрированные ViewController’ы будут изменять свой размер в соответствии с контейнером, в который они интегрированы, что не может не радовать глаз и в очередной раз подтверждает «коробочность» данного решения.



Тоже самое можно сделать и в коде:



let embedController = UIViewController()
addChildViewController(embedController)
view.addSubview(embedController.view)
embedController.view.frame = view.bounds // Здесь можно использовать Auto Layout, но это совсем другая история
embedController.didMoveToParentViewController(self)


Специальная рубрика: вопрос на засыпку!



Почему не нужно вызывать embedController.willMoveToParentViewController(self)?



Правильный ответ
Данный метод вызывается внутри
addChildViewController(embedController)


Следует обратить внимание, что в случае удаления встроенного ViewController’а все происходит наоборот:



embedController.willMoveToParentViewController(nil)
embedController.view.removeFromSuperview()
embedController.removeFromParentViewController()


А метод embedController.didMoveToParentViewController(self) будет вызван автоматически.



Идем далее.



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




  • BarButtonItems. Их можно легко добавить в TableViewController и обработать там же. Для этого необходимо включить отображение NavigationBar’а в Simulated Metrics и добавить Navigation Item.






  • Шапка таблицы. Не все знают, что в TableView можно вставить header для всей таблицы, а не только для секций.





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




Как теперь с этим жить работать?



Если из ParentViewController нужно что-то передать в ChildViewController, необходимо переопределить метод prepareForSegue.



private var someController: SomeViewController!

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let someController = segue.destinationViewController as? SomeViewController {
self.someController = someController
}
}


Ну и совсем уж очевидный совет напоследок



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



func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if let cell = cell as? SomeCell {
cell.textLabel = someObject.someText // плохо
cell.numberLabel = someObject.someNumber // плохо
cell.configureForObject(someObject) // хорошо
} else if let cell = cell as? OtherCell {
cell.textLabel = otherObject.text // плохо
cell.numberLabel = otherObject.number // плохо
cell.configureForObject(otherObject) // хорошо
}
}


Резюме




  • Не используем отдельный TableView

  • Используем TableViewController

  • Нужно добавить что-то в TableViewController — создаем ParentViewController

  • Не конфигурируем ячейки прямо во ViewController’е, а передаём модель в ячейку и производим конфигурацию там

  • Применяем все тоже самое и к CollectionView


Original source: habrahabr.ru.

https://habrahabr.ru/post/311064/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Безопасность Android-приложений. Лекция в Яндексе

Воскресенье, 25 Сентября 2016 г. 16:55 (ссылка)

Разработчик Дмитрий Лукьяненко, чью лекцию мы публикуем сегодня, не только является специалистом Яндекса, но и умеет проверять на прочность решения разработчиков других компаний. Это позволяет учиться на чужих ошибках — не исключая порой своих, конечно. В докладе Дмитрий поделится примерами Android-уязвимостей, в том числе найденных им собственноручно. Каждый пример сопровождается рекомендациями — как нужно и как не нужно писать приложения под Android.









Меня зовут Дмитрий, я работаю в компании Яндекс в минском офисе, занимаюсь разработкой аккаунт-менеджера. Это библиотека, которая отвечает за авторизацию пользователей. Поэтому мы поговорим о безопасности Android-приложений.



Я бы выделил следующие источники проблем. Первые — сетевые, связанные с коммуникацией с сервером. Это когда ваши данные передаются не совсем защищенным способом. Вторые связаны с проблемой хранения данных: это когда ваши данные хранятся где-то в открытом виде, могут даже где-то на SD-карте храниться, либо они не зашифровываются, в общем, когда к ним есть доступ извне.



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



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







Этот доклад будет полезен тем, кто занимается Android-разработкой. Я бы советовал уделить внимание этим аспектам всем, кто делает приложения. Например, тестировщикам. Тестировщики, мне кажется, если посмотрят эти нюансы, смогут какие-то премии выбивать, они начнут более глубоко вникать в разработку, даже программировать можно особо не учиться. Manifest-файл просто смогут анализировать и выявлять потенциально опасные места. И всем остальным, кто интересуется такими вопросами безопасности.







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







Стоит отметить удобную утилиту для Android — ManifestViewer. Она позоляет очень быстро просматривать manifest-файлы всех установленных приложений. Я её использую по работе, например, когда ко мне приходят и говорят: аккаунт-менеджер не работает, что такое? В первую очередь всегда смотрю manifest-файл, чтобы убедиться, что аккаунт-менеджер был правильно интегрирован, то есть что все его компоненты объявлены как надо.

Эта программка полезна, чтобы вы на скорую руку открыли и посмотрели точки входа, вектор атак из manifest-файла.



Если вы любите всё делать из консоли, вот вам все эти программы отдельно. apktool позволяет выдернуть все ресурсы и manifest-файл. Dex2jar и enjarify позволяют конвертировать apk-файл в jar. Dex2jar может какие-то apk не конвертнуть, выдать с каким-то исключением. Не отчаивайтесь: часто такие файлы скушает enjarify, и вы получите jar. Это две хороших утилиты.



После того, как у вас есть jar-файлы, вы можете взять Java Decompiler и сконвертировать их в более удобный вид — в вид классов. Понятно, что их нельзя будет запустить, но анализировать их гораздо проще, чем код, который там получается, и т. п.







Давайте рассмотрим самые базовые проблемы. Во-первых, сначала нам нужно проанализировать manifest-файл, потому что в нем обязательно должны быть описаны все компоненты Android-приложения. Это Activity, Service, Broadcast Receiver, ContentProvider. Все они, за исключением Broadcast Reciever, обязательно должны там находиться.



Поэтому когда мы начинаем поиск каких-то проблем, мы смотрим эти компоненты. Вот конкретный пример. Это сервис, который был объявлен в manifest-файле одного приложения, он явно экспортируется. В нем даже явно указано, что он экспортирован. Это означает, что он доступен любому другому стороннему приложению. Любое другое приложение, в свою очередь, может послать в этот сервис интент, и сервис может выполнить какие-то действия, если они там предусмотрены.



В данном случае мы видим потенциальный вектор для атаки. Если копнем глубже и посмотрим исходники, по ним станут понятно, что этот сервис позволяет, допустим, удалить авторизованного пользователя в этой программе. Я сомневаюсь, что разработчики предусматривали такую фичу для каких-то сторонних приложений. Это конкретный пример, которому следует уделить внимание.



Ещё один момент: когда у нас какая-то компонента использует интент-фильтры, то по умолчанию она тоже становится экспортируемой. Тут, возможно, начинающие разработчики могут споткнуться. Если интент-фильтр есть, то всё, эта компонента уже публичная. Тут стоит быть внимательным.



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







Что делало это событие? Оно обрабатывалось при помощи публичного BroadcastReciever. То есть злоумышленник тоже мог послать любой бродкаст — подобрать ID письма и, допустим, удалить его. Причем необязательно, чтобы это было сообщение в панели.



Когда-то давно в Яндекс.Почте была такая уязвимость. Уже всё поправили, так что можно пользоваться, всё отлично. Спасибо Ильдару, они оперативно всё это делают.







Как это решилось? Компоненту просто сделали недоступной извне, поставили ещё permission дополнительно. Его можно было и не ставить, главное — если она не экспортируется, значит, уже никто не сможет к ней подключиться и что-то выполнить.







Следующий вид проблем — использование неявных интентов, когда в интенте не задается конкретное место, в которое он должен прийти. Это означает, что у вас нет гарантии, что этот интент придет туда, куда вы хотите. Он может прийти куда-то ещё. Поэтому тут надо быть внимательным.



Ещё нюанс, который я отнес бы к неявным интентам, — это Browsable Activity, когда у нас из браузера можно открыть Activity стороннего приложения. Это происходит, когда задана какая-то схема, хост, там кликают и у вас открывается окно. Хорошо, когда просто открылось окно и например, передалась позиция на карте. Это не страшно. А страшно — следующее. Допустим, у нас некоторые ребята предлагают использовать Slack в компании. В Slack очень интересная авторизация. Если вы авторизовались в браузере на Android, то вы можете авторизоваться и в установленном приложении Slack. Это работает по такой схеме, когда в браузере есть URL, вы по нему кликаете и его перехватывает приложение Slack.







Но здесь нет гарантии, что URL не перехватит кто-то другой, причем по нему передается токен. Схема достаточно простая: когда вы кликаете в браузере, вас сразу авторизовывают в приложении Slack. Значит, этого URL достаточно для авторизации.







Здесь отмечены кнопки, которые можно кликать в браузере и которые инициируют это открытие. Это не только «Открыть Slack», но и логотип — он всегда находится сверху, на любом экране.



Давайте посмотрим видео, которое демонстрирует использование этой проблемы. Мы авторизовались, зашли в свою директорию, нажали на логотип Slack — но приложения Slack у нас нет, у нас злоумышленник подставил интент-фильтр. Вернулись, нажали… Можно фишинг сделать — точно такой же по внешнему виду, как Slack. Написать, что авторизация не сработала и всё такое. Пользователь ничего не поймет, а токен окажется у вас. Поэтому если пользуйтесь Slack, то будьте внимательны с этой браузерной авторизацией.







Решение очень простое. Как говорил мой коллега, можно использовать явные интенты, которые открываются из браузера. Но когда я в Slack зарепортил и мой тикет получил номер 80000 с чем-то, они сказали, что это дубликат и что уже есть тикет 50000-какой-то. Если прикинуть, получится, что им это больше чем полгода назад сообщили. Исправляется вроде достаточно просто, но — не исправили. Значит, это не критичная проблема и можно тогда о ней рассказать.



Здесь есть рекомендация, что лучше всегда использовать явный интент. Если вы почитаете и вникнете более глубоко, то узнаете, что у Android была прикольная опечатка. Они в одном месте использовали неявный pending intent. Из-за этого можно было получить доступ к пользователю с правами system. Они эти ошибки исправили в Android 5. Такие ошибки у всех бывают, даже у Google.



Всегда лучше использовать явный интент или, если это невозможно, всегда задавать какой-то permission. Он позволяет ограничить доступ.



Рассмотрим другой вид уязвимостей — основанный на пользовательских данных.







У нас есть приложения, которые могут получить какие-то данные от пользователей, например отправить какой-то файл, открыть его, просмотреть. Это обычно осуществляется при помощи интентов типа view и send.



Вот это зловредное приложение может вам сказать: отправь мне файл, который лежит у тебя же в приватной директории, в твоей же песочнице. Допустим, этот файл может быть вашей базой данных, содержащей всю переписку, или преференсы, если хранятся какие-то токены. Некоторые приложения могут выполнять с этими файлами какие-то действия. Они могут, например, файл закешировать на SD-карте или отправить куда-то. В том числе можно выполнить такое действие, что этот файл станет доступен злоумышленнику, хотя изначально они предполагали, что это будет их внутренний файл.



Можно взять getAbsolutePath() и проверить, совпадает ли директория с вашей приватной. Но это неправильно.







Вам злоумышленник может прислать не сам файл, а ссылку на него.



Как может создаваться эта ссылка? У злоумышленника создается readme.txt — он сделал ссылку на приватный файл вашего приложения. Затем он запихнул эту ссылку вам, и если вы будете использовать getAbsolutePath(), то вам вернётся путь ссылки — путь к файлу readme.txt. А вы подумаете, что всё нормально.



Чтобы это исправить, лучше использовать метод getCanonicalPath(). Он возвращает полный путь, самый настоящий. В данном случае система вернет не readme.txt, а какой-нибудь mailbox. Учитывайте эти проблемы.



Я сталкивался с ситуацией, когда подобная проблема была у одного приложения более чем с 50 млн пользователей. Говоришь: покажите мне этот файл. Они его кешируют на SD-карту и потом пытаются открыть. Так можно было все токены украсть. Они уже всё исправили, но попросили пока не разглашать. Тем не менее, такое встречается.



Следующий интересный момент: вам могут прислать ссылку на content provider, и он тоже может быть передан. Даже если он защищен через permission, даже если он не экспортируемый, то всё равно — когда ваше приложение попытается его открыть, выполнится метод query, который есть в content provider.



Тут надо быть осторожным. Вот ещё один реальный пример, уже из другого приложения. Они делали бэкап БД из метода query. Туда можно было передать action типа backup и программа сразу дублировала всю БД на SD-карту. Получается, вроде провайдер защищен, но его можно так подсунуть, чтобы получить в итоге всю БД.











Я больше нигде не встречал, чтобы кто-то делал запись в методе query, но там всегда лучше открывать что-то для чтения. А ещё — учитывать, что там может быть SQL-инъекция. Сейчас есть ряд приложений, в которых я обнаружил возможность SQL-инъекции. Однако доступы у них только для чтения, и я пока не понял, можно ли там дальше что-то сделать. Но вдруг найдется уязвимость в самой БД SQLite, которая позволит выполнить уже не настолько безобидную инъекцию? Всё-таки лучше их не допускать, даже если если при открытии есть доступ только для чтения.







Теперь давайте рассмотрим одну проблему с WebView, причем срабатывает она во всех Android до версии 5.0 и позволяет обойти SOP. Из этого мы сделаем вывод, что в WebView лучше никому не давать открывать свои файлы.







Рассмотрим этот вид атаки. Зловредное приложение может попросить ваше приложение, если оно имеет доступы к WebView: покажи мне файлик index.html. Предположим, ваше приложение открыло index.html. Содержимое файлика очень простое — JavaScript, который через 5 секунд сам файлик, самого себя, загружает в iframe, перезагружает как бы.







В этот период времени зловредное приложение указанный файлик удаляет и заменяет на символическую ссылку на приватный файл из вашего приложения. Проходит 5 секунд, оно перезагружается, но контент в нём уже становится контентом того самого приватного файла. На Android до 5.0 ещё до WebView, видимо, стоит неправильная проверка на то, что это символическая ссылка. Таким образом можно прочитать контент. Оно смотрит — имена файлов совпадают, значит SOP не нарушена, контент можно отдать и значит, JavaScript может взять контент и отправить его на сервер.







Такой вид атаки встречается не только в WebView. Он до сих пор работает в UCBrowser, у которого больше 100 млн установок. Я встречал такое и на некоторых версиях Android-браузера, до Android 5.0. Наверное, он тоже на WebView построен. Например, на телефонах Samsung у меня такое не получилось воспроизвести, а на моем телефоне Acer срабатывает.







Глянем небольшое видео о том, как это работает в UCBrowser. Речь о небольшом зловредном приложение, но оно может сработать. Вы легли спать, телефон тоже, внезапно запускается activity, страничка. Вы спите, а там запустилось — какой-то iframe, подтверждение, алерт. Если алерт прочитал контент, значит, мы точно так же могли отправить этот контент куда угодно. Это bookmark.db, тут хранятся закладки. Думаю, кому интересно — может поисследовать. Возможно, удастся найти там более приватные пользовательские данные. Можно и куки украсть. Но куки у них названы по имени сайта, поэтому надо перебирать. ВКонтакте можно взять. Уязвимость до сих пор есть, вроде пока ещё не исправили и не спешат исправлять.











Вывод: если у вас есть WebView, то не давайте никому открывать в нём свои ссылки. А если всё-таки даёте, то хотя бы запретите открытие локальных файлов. В этом плане большие молодцы компания Qiwi, я их приложение пробовал, обрадовался, что сейчас открою файлик — ан нет, они запретили открывать локальные файлы и ничего не сделаешь.



Рассмотрим следующий вид нетривиальной проблемы. Она основана на особенностях десериализации в Android. Возможно разработчикам самой Java может быть полезно.



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



Есть в Android до 5.0 такой бонус: на некоторых версиях при десериализации не проверяется, что класс действительно имплементирует интерфейс сериализации.



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







Итак, что тут опасного? Если объект был создан, он когда-нибудь будет удален. Обычно в том, что метод finalize вызовется, нет ничего опасного, ничего не реализуется. Однако когда есть нативная разработка, то обычно в методе finalize вызывают деструктор из нативной области и передают туда указатель. Я нативной разработкой не занимался, но поизучал, как туда передаются указатели. Если данный указатель сериализуется, то злоумышленник может подставить свой, а он, в свою очередь, может как вызвать ошибку выхода за границы памяти, так и указать на другую память, которая потом возьмет и выполнит какой-то код.







Этим воспользовались ребята из компании IBM. Они проанализировали весь список классов на платформе Android — проверили больше тысячи или сколько их там. И нашли всего один, который удовлетворял критериям: он был сериализуемый, и он сериализовал native-указатель. Они взяли этот класс, подставили свой указатель, он сериализовался и десериализовался. Он был новым не каждый раз. Сделали proof of concept, демонстрацию, есть видео. Эта уязвимость позволила им при помощи этого класса заслать интент в системное приложение. Оно позволило им, допустим, удалить оригинальное приложение Facebook и заменить его на фейковое. Видео длится минут 7. Там приходится повертеть — пока finalize вызовется, пока очистится память. Но вывод — никогда не надо десериализовывать нативный указатель.







Подытожим. Лучше никогда не экспортировать компоненты, которые есть в вашем приложении. Либо — ограничивать доступ по permission. Интенты всегда лучше использовать явные, либо permission задать. Никогда не доверяйте тем данным, которые придут от пользователя — это могут данные на что угодно, даже на ваши приватные области. Вы их потом можете повредить. Внимательно отнеситесь к ContentProvider, в том числе к SQL-инъекции и т. п.



Такая штука, как WebView, — она вообще не для игрушек. Если она есть в вашем приложении, закройте её и никому не давайте с ней играться.



Сериализация, а точнее, нативная разработка — это тоже как спички, будьте с ней поосторожнее. Спасибо за внимание.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/310926/

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Дайджест интересных материалов для мобильного разработчика #172 (19-25 сентября)

Воскресенье, 25 Сентября 2016 г. 16:09 (ссылка)

App Store пустеет, приложения интегрируются с Siri, HoloLens получает свой Hello World, жестокая реальность губит мобильные FPS шутеры, РЖД заказывает приложение за 67 млн рублей – это лишь малая часть нового большого дайджеста.












Сентябрь. Пустеет яблоневый сад

Это не метафора. Число приложений в магазине Apple резко уменьшилось. А началась эта история 1 сентября.






Masking Bitmaps на Android

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



Теперь дайджест доступен и в виде рассылки. Подписаться вы можете тут.



iOS



Android



Windows



Разработка



Аналитика, маркетинг и монетизация



Устройства и IoT





<- Предыдущий дайджест. Если у вас есть другие интересные материалы или вы нашли ошибку — пришлите, пожалуйста, в почту.
Original source: habrahabr.ru.

https://habrahabr.ru/post/310966/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Проба гибридных технологий

Четверг, 22 Сентября 2016 г. 19:53 (ссылка)

image



Мы почти четыре года занимаемся разработкой нативных мобильных приложений на Objective-C и Java. И Нам часто предлагают партнерские отношения, отдавать на субподряд разработку мобильных приложений. Но на самом деле у студий разработчиков мобильных приложений нет проблем с объемом заказов. Существует огромный дефицит программистов на Objective-C и Java.



А если прибавить к этому работу проект-менеджера и тестировщика в двойном объеме, получается печальная картина. Впрочем Мы долгое время противились истории гибридных приложений, так как они были откровенно не потребные. Но время шло… технологии менялись и учитывая отсекание древних устройств со столь же древними операционными системами, осталась iOS 8+ и Android 4+ у которых с отображением HTML/JS все на очень высоком уровне.



Что же это за «зверь» гибридное приложение? Это нативное мобильное приложение с набором определенных функций и использованиям в качестве верстки окно браузера, который отображает сверстанную страницу. Нативное приложение обеспечивает доставку web-страниц, написанных на HTML5/JS, а также их хранение. В случае, если данные на сервере не изменялись, приложение отобразит сохраненную версию, та же логика и при отображении при отсутствии интернета. Можно называть это гибридным приложением, можно нативным, но главное это ощущение от пользования приложением. По большому счету это нативное приложение с версткой на HTML/JS. Прибавьте к этому знания гайдов верстки Apple и Google и опыт нативной разработки мобильных приложений и результат будет отличный.



С чего все началось.



Первым проектом на базе полуфабриката нативных приложений был интернет-магазин «Артлавка», старт был легким, но Нам пришлось голопом доделывать все фишки 1С-Битрикс редакции бизнес в нативном виде и в офф-лайн. О трудностях переписывания php/js на Objective-C/Java рассказывать не буду, это очень тернистый путь, но Нам казалось в этом будет изюминка. Отрезвев от гордости за написанное, осознали что появились две очень существенные проблемы: дальнейшее развитие и офф-лайн.



Развитие проекта по всем канонам необходимо было организовать двумя программистами на Objective-C и Java, но с партнерами-студиями разработчиков мобильных приложений все оказалось не так радужно и откровенно говоря почти невозможно.



Оффлайн работа приложения с локальной базой данных с товаром свыше 20 тысяч тоже проявила себя на старте приложения не так как Мы планировали. Все дело в том что при выгрузке остатков товаров из 1С в 1С-Битрикс база данных фактически стирается и загружается заново, что мешало Нашим механизмам определить на самом деле измененные данные и отправить в приложение только изменения. Таким образом сейчас при старте приложения обновляется вся база целиком, что отражается на длительной загрузке.



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



Анализируя все трудности реализации проекта, Мы приняли решение что крайне необходимо подключить к процессу модернизации и совершенствованию Нашего полуфабриката именно 1С-Битрикс программистов, которых очень много.



Естественно Мы рассматривали новомодные технологии React Native и Xamarin, но с ними та же проблема, малое количество специалистов. Да и при реализации на подобных инструментах, опять же нет совместимости с наработками 1С-Битрикс специалистов.



Главное преимущество на котором Мы сконцентрировались, это возможность одним специалистом развивать сайт и мобильное приложение на 1С-Битрикс. Естественно стоимость такой работы сконцентрированной на одном типе специалистов положительно сказывается на стоимости.



Чтобы сохранить концепцию работы в оффлайн приложения при мало ассортиментом и редко меняющимся товаре (доставка цветов, воды и прочее), есть пакетный менеджер загрузки данных, с помощью которого можно при старте загрузить все данные и пользоваться приложением в офф-лайн, т.е. без интернета. Эту опцию например можно использовать на избранные товары или из раздела лучшие, которые очевидно будут востребованы для просмотра.



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



Какие же проблемы на сегодняшний день с гибридными приложениями?



Первая и ключевая. Создатели гибридных приложений относятся к таким приложениям как к чему-то очень дешевому, соответственно и результат какой-то тяп-ляпный. Отсутсвие понимания что на смену страницам и ссылкам пришли окна и кнопки, а также отстраненность от гайдов Apple и Google по дизайну приложений, получаются какие-то мобильные сайты запущенные внутри приложения. Про Push-уведомления отдельная история, т.к. для web-разработчиков, это всего лишь СМС в телефон, а не инструмент для нотификации обновления конкретных данных например. Вебщик проще сделает оттягивалку или кнопку обновить и перезагрузит всю страницу, как он это привык делать с сайтом на компьютере.



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



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



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



Перейдем к практике



Хочу познакомить Вас с третьей версией Нашего полуфабриката для интернет-магазина на 1С-Битрикс, чтобы уже понимать о чем же вообще речь, Мы выкатили промежуточную версию. Есть еще временные недоработки: отсутствует фильтр товаров и возможность заказать товар не на физ. лицо и так по мелочи.



Сервер у Нас сейчас самый минимальный и даже не на SSD, чего требует 1С-Битрикс. И в запасе есть возможности по ускорению приложений, но может данной скорости будет достаточно, чтобы не жертвовать возможностями по сопровождению и развитию мобильных проектов партнерами 1С-Битрикс.



Демонстрация полуфабриката мобильного интернет-магазина


Для Android: play.google.com/store/apps/details?id=net.malahovsky.appforsale



iOS еще не опубликован, для тестирования напишите мне на evgeny@malahovsky.net



Буду очень признателен за заполнение простенького опроса: goo.gl/forms/u02YZpl84hgVAEj02



Позже можно будет развернуть на своем действующем или тестовом интернет-магазине 1С-Битрикс демо версию.



Решение располагаться будет по адресу: marketplace.1c-bitrix.ru/solutions/mlab.appforsale



Промосайт: promo.malahovsky.net/mobileappshop
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/310750/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Победители Google Device Lab: исследуем Project Tango

Четверг, 22 Сентября 2016 г. 16:57 (ссылка)

Здравствуйте, коллеги! Наша небольшая компания Vizerra разрабатывает заказные проекты и собственные продукты в области дополненной и виртуальной реальности (далее ARVR) для самых разных заказчиков. Почти на каждом проекте нам требуется придумывать какое-то новое и неожиданное решение. ARVR рынок очень юн и многие решения создаются во время проектов. Таким образом происходит его развитие.



Статья-победитель автора Александра Лаврова, в рамках конкурса «Device Lab от Google».




В связи с этим мы постоянно пробуем новое оборудование с прицелом на его использование в проектах. Сегодня мы хотим рассказать о таком уже знаменитом, но малоосвещенном в русскоязычном интернете устройстве как Project Tango. Совсем недавно он стал просто Tango ознаменовав переход в коммерческий этап своей жизни и начали появляться устройства для конечных пользователей.

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



Оказалось, что заполучить устройство для экспериментов очень непросто. Нам помог фонд Сколково познакомив с русским офисом Google. Ребята оказались очень отзывчивыми и выдали столь желаемое устройство на руки.

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



Пару месяцев назад мы узнали, что стартовал Google Device Lab, и мы решили, что нужно отплатить добром за добро — поделиться нашим опытом с другими разработчиками и сели писать данную статью. В процессе написания статьи её концепция несколько раз менялась. Хотелось как обычно сделать что-то полезное, а не описать наш очередной проект. В итоге посовещавшись мы решили, что наиболее полезным будет написать русскоязычный полный обзор по Project Tango с учетом всех набитых нами шишек. Тогда мы начали объединять разрозненные источники, что бы у читателя создалась достаточно полная картина по прочтении данной статьи.

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







Аппаратная часть



Для начала давайте посмотрим что же представляет из себя само устройство.



На момент тестирования существовало 2 доступные модификации:




  1. Планшет «Yellowstone». Обычно когда люди говорят про Tango, то подавляющее большинство представляет себе именно его.

  2. Телефон «Peanut». Честно говоря не знаем никого из тех, кто реально его держал в руках.







Нам достался для экспериментов 7 дюймовый планшет «Yellowstone», входящий в состав Project Tango Tablet Development Kit.



Сам базовый планшет в принципе удивления не вызывает. Устройство содержит 2.3 GHz quad-core Nvidia Tegra K1 processor, 128GB flash memory, 4 мегапиксельную камеру, сенсорный экран разрешением 1920x1200 и 4G LTE.



В качестве операционной системы используется Android 4.4 (KitKat). Мы уже порядком отвыкли от систем младше 5.0. Последний год минимальным требованием клиентов была поддержка устройств с Android 5.0.



Следует помнить, что устройство является частью Development Kit, а не устройством для конечного пользователя. Для прототипа оно выглядит отлично и даже удобно в использовании! Начинка устройства далеко не самая современная, но устройство отлично функционирует. Очевидно, что в серийных устройствах конечные производители, использующие платформу Tango, легко смогут использовать новейшее железо и ОС.



Значительно интереснее выглядит набор встроенных сенсоров. Похоже, что на данный момент это самый «прокаченный» планшет. Как именно они используются мы рассмотрим далее.




  • Fisheye камера для отслеживания движения

  • 3D датчики глубины

  • Акселерометр

  • Датчик окружающего света

  • Барометр

  • Компас

  • GPS

  • Гироскоп



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







Для любителей посмотреть «что там на самом деле у него внутри» прилагаем фотографию устройства в разобранном виде. Разбирали не сами. Спасибо, коллегам с портала slashgear.com за интересное фото.







Google предупреждает, что Tango и Android не являются аппаратными системами реального времени. Основной причиной является то, что Android Linux Kernel не может предоставить гарантий времени исполнения программы на устройстве. По этой причине Project Tango можно считать программной системой реального времени.



Прицип действия устройства



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



Во-первых следует понимать, что Tango — это не просто экспериментальный планшет, который демонстрируется повсеместно, а новая масштабируемая платформа, которая использует компьютерное зрение, чтобы дать устройствам возможность понять их положение по отношению к окружающему их миру. То есть предполагается, что к привычным сенсорам в смартфоне или планшету будут добавлены сенсоры компьютерного зрения.



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



Tango дает мобильным устройствам возможность определения их положения в окружающем мире с использованием трех основных технологий: Motion Tracking (отслеживание движения), Area Learning (изучение областей пространства) и Depth Perception (восприятие глубины). Каждый из них по отдельности имеет свои уникальные возможности и ограничения. Все вместе же они позволяют достаточно точно позиционировать устройство в окружающем мире.





Motion Tracking



Данная технология дает возможность устройству отслеживать свое собственное движение и ориентацию в 3D-пространстве. Мы можем походить с устройством как нам будет нужно и оно покажет нам, где оно находится и в каком направлении происходит движение.

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



Ключевым термином в технологии Motion Tracking является Pose (поза) — сочетание позиции и ориентации устройства. Термин звучит, честно говоря, довольно специфически и, вероятно, Google решил подчеркнуть им свое стремление к совершенствованию человеко-машинного интерфейса. Обычно под позой подразумевается положение, принимаемое человеческим телом, положение тела, головы и конечностей по отношению друг к другу.



Tango API предоставляет положение и ориентацию устройства пользователя с шестью степенями свободы. Данные состоят из двух основных частей: вектор в метрах для перемещения и кватернион для вращения. Позы указываются для конкретной пары точек траектории. При этом используется система отсчёта — совокупность тела отсчёта, связанной с ним системы координат и системы отсчёта времени, по отношению к которым рассматривается движение каких-либо тел







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



Танго реализует Motion Tracking с помощью визуально-инерционной одометрии (visual-inertial odometry или VIO).

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







Изображения являются собственностью NASA.



Визуально-инерциальная одометрия дополняет визуальную одометрию инерциальными датчиками движения, способными отслеживать вращение устройства и его ускорение в пространстве. Это позволяет устройству рассчитать его ориентацию и движение в 3D-пространстве с еще большей точностью. В отличие от GPS, отслеживание движения с помощью VIO работает и в закрытом помещении. Что стало поводом для появления большого количества идей по созданию относительно недорогих indoor навигационных систем.



Визуально-инерциальная одометрия предоставляет улучшенное определение ориентации в пространстве по сравнению со стандартным Android Game Rotation Vector APIs. Она использует визуальную информацию, которая помогает оценить вращение и линейное ускорение более точно. Таким образом мы наблюдаем удачное комбинирование известных ранее технологий для устранения их известных проблем.



Все вышеперечисленное нужно для того, чтобы при объединении вращения и отслеживания положения в пространстве, мы смогли использовать устройство в качестве виртуальной камеры в соответствующем 3D-пространстве вашего приложения.







Motion tracking является базовой технологией. Она проста в использовании, но имеет ряд проблем:




  • Технология не разбирается сама по себе, что именно находиться вокруг пользователя. В Tango за эту задачу отвечают другие технологии: Area Learning и Depth Perception.

  • Motion Tracking не «помнит» предыдущие сессии. Каждый раз, когда вы начинаете новый сеанс отслеживания движения, отслеживание начинается снова и сообщает свою позицию по отношению к её стартовой позиции в текущей сессии.

  • Так же, судя по экспериментам, тряска устройства приводит к потере трэкинга. Это очень явно проявлялось при его использовании в автомобиле.

  • При перемещении устройства на большие расстояния и в длительные периоды времени происходит накопление мелких ошибок, что может привести в итоге к большим ошибкам в абсолютном положении в пространстве. Произойдет так называемый «drift» (дрейф). Это еще один термин заимствованный из реального мира. Обычно под этим требованием подразумевается отклонение движущегося судна от курса под влиянием ветра или течения, а также движение льдов, несомых течением. Для борьбы с дрейфом Tango использует Area Learning для коррекции данных ошибок. Этот аспект мы подробно рассмотрим в следующей части статьи.







Area Learning



Люди умеют распознавать, где они находятся, заметив известные им признаки вокруг себя: дверной проем, лестницу, стол и т.д. Танго предоставляет мобильному устройству ту же способность. С помощью одной лишь технологии motion tracking, устройство через камеру «видит» визуальные особенности района, но не «помнит» их. С помощью area learning, устройство не только «помнит», что оно «увидело», но может также сохранять и использовать эту информацию. Результатом работы данной технологии являются абсолютные позиция и ориентация устройства в уже известном ему пространстве.



Tango использует метод одновременной локализации и построения карты (SLAM от англ. Simultaneous Localization and Mapping) — метод, используемый в мобильных автономных средствах для построения карты в неизвестном пространстве или для обновления карты в заранее известном пространстве с одновременным контролем текущего местоположения и пройденного пути.



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



В контексте Tango Area learning решает 2 ключевые задачи:




  1. Повышение точности траектории полученной с использованием motion tracking. Данный процесс получил название «Коррекция дрейфа».

  2. Ориентация и позиционирование самого устройства внутри ранее изученной области. Данный процесс назван «Локализация».



Давайте рассмотрим подробнее как именно решаются эти задачи.



Коррекция дрейфа



Как уже было сказано ранее, area learning запоминает визуальные признаки в областях реального мира, которые устройство «видело» и использует их, чтобы исправить ошибки в его позиции, ориентации и движении. Когда устройство видит место, которое оно видел ранее в вашей сессии, то оно понимает и корректирует свой путь, чтобы он соответствовал его предыдущим наблюдениям.

На приведенном ниже рисунке показан пример коррекции дрейфа.







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




  • Путь по которому вы идете («Реальная траектория»)

  • Путь вычисляемый устройством («Вычисляемая траектория»)



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



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



Локализация



После того, как мы прошли через нужную вам область с включенным area learning, мы можем сохранить в Area Description File (ADF) то, что устройство «увидело».

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







Существует два способа создания ADF. Проще всего использовать приложение TangoExplorer, а затем уже ваше приложение загружает полученный ADF.







Также мы можем использовать Tango API, для изучения пространства, сохранения и загрузки ADF в пределах нашего приложения.

Следует отметить ряд особенностей, о которых следует помнить при использовании area learning:




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

  • Среда может выглядеть совершенно иначе с разных точек зрения и позиций, а также может меняться с течением времени (мебель можно перемещать, освещение будет отличаться в зависимости от времени суток). Локализация имеет больше шансов на успех, если условия локализации аналогичны условиям, которые существовали, когда был создан ADF.

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





Depth Perception



С помощью данной технологии устройство может понять форму нашего окружения. Это позволяет создавать «дополненную реальность», где виртуальные объекты не только является частью нашей реальной среды, они могут также взаимодействовать с этой средой. Например, многие уже пророчат компьютерные игры в реальном пространстве.







Tango API обеспечивает получение данных о расстоянии до объектов, которые снимает камера, в виде облака точек. Этот формат дает (х, у, z) координаты максимальному количеству точек в сцене, которое можно вычислить.







Каждое измерение представляет собой значение с плавающей точкой записывающее позицию каждой точки в метрах в системе отсчета камеры сканирующей глубину сцены. Облако точек ассоциировано с цветовой информацией, получаемой с RGB камеры. Эта ассоциация дает нам возможность использовать Tango в качестве 3D сканера и открывает много интересных возможностей для разработчиков игр и творческих приложений. Степень точности сканирования конечно нельзя сравнивать со специальными 3D сканерами, дающими точность в доли миллиметра. По опыту коллег максимальная точность Intel RealSense R200 (используется в Tango) составляет 2 миллиметра, но может быть значительно хуже, т.к. сильно зависит от расстояния до предмета, от условий съёмки, от отражающих свойств поверхности, от движения. Так же нужно понимать, что увеличение точности изображения глубины приводит к увеличению шумов в сигнале, это неизбежно.



Однако следует отметить, что для построения коллизий в игре, расстановки виртуальной мебели в реальной квартире, измерения расстояний текущей точности получаемого 3D облака точек вполне достаточно.







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







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



Structured Light



Структурированный свет осуществляет проецирование известного паттерна (обычно решетки или горизонтальных полос) на реальные объекты. Таким образом, что деформация этого известного паттерна при наложении на поверхность позволяет системе компьютерного зрения получить информацию о глубине и поверхности объектов в сцене относительно устройства. Широко известный пример использования структурированного света — это 3D-сканеры.







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



Time of Flight



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







Stereo



Мы не нашли точной информации как именно устроена данная технология в Tango. Видимо реализация достаточно стандартная и разработчики не стали заострять внимание на этом. В один момент времени производиться 2 снимка, так называемая стереопара. На их основе при помощи фотограмметрии определяется расстояние до поверхностей. Таким образом, например, производится спутниковая съемка высоты рельефа Земли.







Важно иметь в виду, что Structured Light и Time of Flight требуют наличия в устройстве одновременно инфракрасного (ИК) излучателя и ИК-камеры. Stereo технологии достаточно 2х камер и не требуется ИК-излучатель.



Отметим, что текущие устройства фактически предназначены для работы в закрытом помещении при умеренных расстояниях до объекта сканирования (от 0,5 до 4 метров). Такая конфигурация дает достаточно большую глубину на среднем расстоянии, при этом не предъявляет излишних требований к питанию для ИК-излучателя и производительности самого устройства при обработке глубины. По этой причине не рассчитывайте на сканирование очень близких объектов и распознавание жестов.



Следует помнить, что для устройства, которое воспринимает глубину с помощью ИК-камеры есть некоторые ситуации, когда точная работа затруднена.




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

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

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





Наш проект с Tango



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



Танго предоставляет SDK для игрового движка Unity3D и поддерживает OpenGL и других 3D-системах через C или Java. Мы используем в своей работе в основном Unity3D и все примеры далее будет создаваться именно в его среде разработки.



Интерграция с unity3D



Для разработки приложений в Unity3D для Project Tango нам потребуются:


  • Установленный Android SDK 17+


  • Unity (5.2.1 или выше), со средой настроенной для Android разработки.


  • Tango Unity SDK.


  • Для ОС Windows следует установить Google USB Driver если устройство не было распознано автоматически.




Описание проекта



Мы решили реализовать расстановку миниатюр военной техники с использованием Tango. Была запланирована следующая не замысловатая последовательность действий:


  • Пользователь берет в руки планшет Tango;


  • На экране в тех местах, где возможно расставить технику — рисуется зеленый маркер, там, где невозможно — красный:


  • Предлагается следующий выбор военной техники:


  • Расставленную технику можно перемещать в плоскости экрана с помощью touch интерфейса, и она будет перемещаться по физической поверхности.


  • Можно удалить расставленную технику.


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




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







Реализация



За основу мы взяли ресурсы из TangoSDK/Examples/AugmentedReality с github и наши модели из уже реализованного проекта.







Описание реализации



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



— Вывод изображения из камеры устройства на экран, в этом нам поможет Tango AR Camera







— Далее необходимо обеспечить повторение реального перемещения устройства в виртуальной сцене. За это отвечает технология Motion Tracking и в сцене юнити необходимо настроить Tango Application, включить галочку Enable Motion Tracking.







Так как мы хотим, чтобы технику можно было расставлять по реальной поверхности, имеющей представление в виртуальной сцене, можно предположить, что должны присутствовать данные, описывающие виртуальное пространство. В Tango за это отвечает Tango Point Cloud, поэтому разместим его на сцене.







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








  1. Нам потребуется интерфейс, поэтому разместим и настроим структуру интерфейса — объект UI, и для корректной работы интерфейса добавим EventSystem.


  2. Также нам понадобятся данные, которые мы будем расставлять, то есть непосредственно модели техники. Шаблоны мы разместили в сцене, в объекте Prefabs.


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



    ViecleSpawnScript 


    и сделали ссылку в скрипте на модель. Теперь наши кнопки «знают» какая модель с ними связана.



    — Теперь нам необходимо реализовать логику, которая позволит расставлять объекты, их перемещать, удалять. Логику мы реализовали в классе



    VehicleSpawnRoot


    Ниже вы можете увидеть его настройки:







    Instances Limit — максимальное количество расставленных моделей;

    Model Scale — масштаб моделей при расстановке;

    Point Cloud — ссылка на объект Tango Point Cloud;

    Placing Mark — ссылка на префаб маркера;

    Trace Layer Mask — настройка слоев, по которым возможна расстановка;

    Selection Info — ссылка на элемент интерфейса для отображения названия техники, которую выделили.



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



    — Нам необходимо иметь данные — точку пересечения луча и результат пересечения. Получение координаты и результата трейса мы сделали через асинхронное получение, запущена Coroutine с функцией



    LazyUpdate


    В этой функции происходит определение пересечения луча с облаком точек Point Cloud Tango. Point Cloud Tango перестраивает сам Tango, поэтому мы имеем актуальное облако точек и можем брать из него данные.




Результат трейса может иметь следующие значения:



enum ETraceResults
{

Invalid, // результаты трейса недоступны

NotFound, // результаты трейса доступны, но пересечения с плоскостью не найдено

NotGround, // плоскость не выровнена по горизонтали.
ExistingObjectCrossing, // обнаружено пересечение с расставленным объектом дополненной реальности

Valid, // подходящее положение для расстановки
}



Чтобы модель по нажатию на кнопку ставилась на поверхность в классе



VehicleSpawnRoot


создадим функцию



public void Spawn( GameObject prefab )


В функцию передается префаб с моделью для расстановки.

В функции проверяется возможность расстановки и в случае успеха — создается модель в заданных координатах.



В целом все готово, можно запускать!



Более подробно можно ознакомиться с кодом проекта на gitHub.



Публикация приложения в Google play



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




...






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



Резюме



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

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



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

Единственная ложка дегтя в большой бочке мёда — это проблемы при работе устройства на ярком освещении. Очень хочется верить, что эту задачу Google и Intel будут решать в следующие годы или возможно уже решают.

Спасибо за внимание и надеемся, что статья оказалась для вас интересной.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/309876/

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Удобный REST для Xamarin-приложений

Четверг, 22 Сентября 2016 г. 15:30 (ссылка)

Разработчикам на Xamarin доступен богатый выбор компонентов для работы с сетью, и в сегодняшней нашей статье мы рассмотрим набор модулей, которые также могут быть использованы в PCL-проектах на Xamarin.Forms.



Все статьи из колонки можно найти и прочитать по ссылке #xamarincolumn, или в конце материала под катом.







Refit для удобного описания клиента REST API



Самым популярным в настоящее время протоколом для общения мобильных приложений с сервером является REST в связке с Json. Поэтому наше сегодняшнее знакомство начнем с библиотеки Refit.



Refit позволяет описать спецификации для работы с REST-сервисом в виде простого Interface с понятным набором входных и выходных параметров, включая возможность манипулировать HTTP-заголовками для отдельных запросов. Для примера возьмем демо-API сервиса httpbin.org:



    [Headers("Accept: application/json")]
public interface IHttpbinApi
{
[Get("/basic-auth/{username}/{password}")]
Task BasicAuth(string username, string password, [Header("Authorization")] string authToken, CancellationToken ctx);

[Get("/cache")]
Task CheckIfModified([Header("If-Modified-Since")] string lastUpdateAtString, CancellationToken ctx);

[Post("/post")]
Task FormPost([Body(BodySerializationMethod.UrlEncoded)] FormData data, CancellationToken ctx);
}


После описания данного интерфейса, он подается на вход для Refit:



            var client = new HttpClient(new NativeMessageHandler())
{
BaseAddress = new Uri("http://httpbin.org")
};
_httpbinApiService = RestService.For(client);


Сами данные можно при необходимости (конвертации camel case или snake eyes, преобразование из множества в строковые значения) можно расширить аттрибутами из библиотеки Json.net, так как именно она используется в Refit:



      public class AuthResult
{
[JsonProperty("authenticated")]
public bool IsAuthenticated { get; set; }

[JsonProperty("user")]
public string Login { get; set; }
}


В Refit в качестве выходного значения можно получить уже преобразованные объекты DTO или HttpResponseMessage. Последний позволяет получить информацию о запросе и ответе, что может быть полезно при отладке. При желании также может использоваться ModernHttpClient при создании HttpClient. В целом, Refit — достаточно удобный и универсальный инструмент для Xamarin-разработчиков в том числе.



Примечание 1: для установки Refit 3.0 в PCL-проект Xamarin.Forms потребуется перевести проект на .NET Standard.



Примечание 2: в документации Refit нет упоминания на использование CancelationToken для отмены активных операций, но данный механизм работает и описан в тикете.



Polly



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



Интересный подход по использованию Refit и Polly описал Rob Gibbens в своем блоге (дополнительно там показан пример приоретизацией сетевых запросов с помощью Fusillade).



Вот так мы совершаем запрос:



protected async Task MakeRequest(Func> loadingFunction, CancellationToken cancellationToken)
{
Exception exception = null;
var result = default(T);

try
{
result = await Policy.Handle().Or()
.WaitAndRetryAsync(3, i => TimeSpan.FromMilliseconds(300), (ex, span) => exception = ex)
.ExecuteAsync(loadingFunction, cancellationToken);
}
catch (Exception e)
{
// Сюда приходят ошибки вроде отсутствия интернет-соединения или неправильной работы DNS
exception = e;
}
//TODO: Обработать исключения или передать их дальше
return result;
}


Вместо loadingFunction необходимо передать ваш код обращения к Refit:



   var authToken = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"));
return await MakeRequest(ct => _httpbinApiService.BasicAuth(username, password, authToken, ct), cancellationToken);


Итак, мы интегрировали Refit, Polly и ModernHttpClient.



Кэш



И в завершении статьи можно рассмотреть использование кэша при работе с сетью. Xamarin-разработчику доступны все возможности целевых платформ, поэтому для реализации кэша можно использовать различные СУБД. Одним из самых популярных кэшеров выступает Akavache, работающий поверх SQLite.



    var cache = BlobCache.LocalMachine;
var cachedObjects = cache.GetAndFetchLatest("objects", GetRemoteObjectAsync,
offset =>
{
TimeSpan elapsed = DateTimeOffset.Now - offset;
return elapsed > new TimeSpan(hours: 0, minutes: 30, seconds: 0);
});


Также можно использовать для реализации кэша очень удобную мобильную СУБД Realm. Ниже представлен пример кэшера на базе Realm:



 public static class LocalCache
{
private class CachedObject : RealmObject
{
[PrimaryKey]
public string Key { get; set; }
public string Value { get; set; }
public DateTimeOffset UpdatedAt { get; set; }
}


private static readonly RealmConfiguration Configuration = new RealmConfiguration("cache.realm", true);
private static Realm Db => Realm.GetInstance(Configuration);


public static async Task WriteToCache(string key, T data, DateTimeOffset timeStamp)
{
if (String.IsNullOrEmpty(key) || data == null || timeStamp == DateTimeOffset.MinValue) return;

var currentValue = Db.All().Where(o => o.Key == key).ToList().FirstOrDefault();
if (currentValue == null)
await Db.WriteAsync(db =>
{
var newValue = db.CreateObject();
newValue.Key = key;
newValue.UpdatedAt = timeStamp;
newValue.Value = JsonConvert.SerializeObject(data);
});
else
using (var transaction = Db.BeginWrite())
{
currentValue.Value = JsonConvert.SerializeObject(data);
currentValue.UpdatedAt = timeStamp;
transaction.Commit();
}
}

public static DateTimeOffset CacheLastUpdated(string key)
{
if (String.IsNullOrEmpty(key)) return DateTimeOffset.MinValue;

var currentValue = Db.All().Where(o => o.Key == key).ToList().FirstOrDefault();
return currentValue?.UpdatedAt ?? DateTimeOffset.MinValue;
}

public static void RemoveCache(string key)
{
if (String.IsNullOrEmpty(key)) return;

var currentValue = Db.All().Where(o => o.Key == key).ToList().FirstOrDefault();
if (currentValue == null) return;


using (var transaction = Db.BeginWrite())
{
Db.Remove(currentValue);
transaction.Commit();
}
}

public static T GetFromCache(string key)
{
if (String.IsNullOrEmpty(key)) return default(T);

var currentValue = Db.All().Where(o => o.Key == key).ToList().FirstOrDefault();
return currentValue?.Value == null ? default(T) : JsonConvert.DeserializeObject(currentValue.Value);
}

public static void ClearCache()
{
Realm.DeleteRealm(Configuration);
}
}




Заключение



Итак, сегодня мы рассмотрели использование Refit, Json.net, ModernHttpClient, Polly и Realm при интеграции с REST API. В следующей статье мы рассмотрим вопросы интеграции Xamarin с внешними сервисами и Azure.



Об авторах





Вячеслав Черников — руководитель отдела разработки компании Binwell. В прошлом — один из Nokia Champion и Qt Certified Specialist, в настоящее время — специалист по платформам Xamarin и Azure. В сферу mobile пришел в 2005 году, с 2008 года занимается разработкой мобильных приложений: начинал с Symbian, Maemo, Meego, Windows Mobile, потом перешел на iOS, Android и Windows Phone.



Предыдущие части



1. Быстрое создание MVP (minimum viable product) на базе Microsoft Azure и Xamarin.Forms.

2. Готовим Xamarin.Forms: настройка окружения и первые шаги.

3. Повышаем эффективность работы в Xamarin.Forms.

4. Работаем с состояниями экранов в Xamarin.Forms.



Полезные ссылки




Original source: habrahabr.ru.

https://habrahabr.ru/post/310704/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<разработка мобильных приложений - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda