- PVSM.RU - https://www.pvsm.ru -
[1]Мы в Контур.Эльбе обожаем мобильные приложения. У нас уже был опыт написания приложения под iOS, а также разработки и дальнейшей поддержки приложения под Android [2]. В этом году мы вновь выпустили версию под iOS [3], но на этот раз на базе Xamarin и Xamarin.Forms, и нам не терпится поделиться опытом. Пока что мы успели рассмотреть разработку только под iOS, но впечатлений уже море, да и про Android пару слов однозначно скажем.
Фреймворк для кроссплатформенной разработки мобильных приложений на базе .NET (точнее, на реализации Mono), поддерживает все основные ОС — Android, iOS и Windows Phone. Подробнее на Хабре писалось [4] неоднократно [5], повторяться нет нужды.
Фреймворк, позволяющий разрабатывать единую вёрстку интерфейса сразу под несколько указанных выше платформ. Идея такова: вёрстку вы делаете один раз на базе Xamarin-компонентов, а на целевой платформе для каждого из компонентов вызывается код-рендерер, рисующий уже родные компоненты. Саму вёрстку можно готовить как в коде, так и в XAML-формате. UI-утилиты для вёрстки и превью получающегося интерфейса, как и год назад [6], всё ещё нет, так что мы выбрали вариант создания UI из кода.
Причин было несколько.
Начало общения с платной версии началось с косяка системы активации: в личном кабинет на сайте Xamarin уже было видно, что оплата (999$ или 799$ для подписчиков MSDN [7]) произведена, а вот Xamarin.Studio упорно отказывалась билдить приложение, т.к. “платная версия не активирована”. Помогла только ручная активация оплаты технической поддержкой Xamarin. Ответили они быстро, но в любом случае это отличное начало, задавшее тон всему последующему проекту.
К слову, бесплатная ознакомительная версия не позволяет собрать приложение размером более 64 килобайт для скомпилированного кода. То есть подключаем, скажем, тот же json-сериализатор (Newtonsoft) – и собрать приложение уже нельзя. Мило.
Xamarin предоставляет собственную IDE Xamarin.Studio, основанную на базе MonoDevelop [8]. К сожалению, эта IDE имеет ряд проблем:
Но есть и хорошие новости! На тарифе business есть интеграция с Visual Studio, позволяющая писать код там. Работает очень хорошо, с частью проблем, например такими [9], мы не сталкивались, видимо потому, что пока не работали с Android и XAML. Но зато столкнулись с другими.
Дело в том, для сборки iOS приложения нужен компьютер или виртуалка с Mac OS X. И тут у вас два варианта:
Более того, плагин для интеграции долгое время работал нестабильно. У нас периодически возникала такая ситуация: три разработчика, у всех одна и та же версия ОС, студии, Xamarin'а и так далее. Подключаются по очереди к одному и тому же маку. В результате у одного всё работает нормально, у второго игнорируются break-point'ы, а у третьего не работает совсем.
Техническая поддержка посоветовала попробовать последние 4 версии под Mac и Windows, “может быть какое-нибудь сочетание заработает”. Установка занимает минут 20-30, т.к. инсталлятор скачивает даже те компоненты (например, библиотеки Android SDK), которые уже скачивал прошлый раз. Вот и думайте…
Но даже если плагин заработает нормально, при следующем открытии проекта в Visual Studio у вас будет отключена сеть или, например, выключен Mac – плагин с некоторой вероятностью сможет подвиснуть на поисках билдхоста. И «отмена» далеко не всегда срабатывает, один раз пришлось лезть в системный реестр и там удалять сохранённые параметры билд-хоста.
Поэтому мы долгое время работали так:
Ну и из мелких неприятностей: при каждом открытии проекта с iOS плагин будет предлагать подключиться к билд.хосту, блокируя дальнейшую загрузку проекта до ответа на вопрос.
К счастью, после многих месяцев мучений, команда Xamarin сжалилась над нами. Последнее обновление Xamarin.Studio эту проблему решила – теперь в окошке подключения к удаленному маку появилась галочка “не показывать окно подключения”.
А, ну и ещё удаленный билд теперь делает не через собственную Xamarin’овскую утилиту, а через обычных удаленных пользователей на Mac OS X:
Как результат — соединение стало довольно стабильным и отладка нормально запускается в 8 случаях из 10. Но в любом случае симулятор запускается на другом ПК, т.е. дебаг идёт на вашей машине, а приложение запущено где-то там, картинка не выводится на вашем ПК. Можно открыть удалённый сеанс или держать второй компьютер на том же столе.
Решение всё равно остаётся несколько костыльным, но оно позволяет полностью отказаться от использования Xamarin Studio! Поверьте, после нескольких месяцев жизни в ней можем сказать однозначно: оно того стоит.
Есть проблемы и с профайлингом. Xamarin.Profiler [10] (GUI обёртка над Mono log profiler [11]) для iOS приложения долгое время не показывал названия написанных вами классов, была только информация, что процессорное время и память занимают такие-то нативные объекты, но как их сопоставить с написанными вами классами — ни капли не очевидно. Сейчас с этим дела обстоят лучше – написанные классы наконец то появились в списке.
Также под профайлером приложение работает намного медленней, и, как следствие, оно порой может просто не успеть за отведённое на запуск время показать первый экран, и iOS его прибьёт. А если приложение таки запустится, то может вылететь в процессе работы на симуляторе под профайлером. В качестве слабого оправдания можно заметить, что профайлер уже давно находится на стадии альфа-версии, и за последний год так и не смог добраться даже до стадии “стабильной беты” – по крайней мере, для iOS.
Писать кроссплатформенный код нам предлагают одним из двух способов:
В теории вам предлагается выбрать что-то одно. На практике мы задействовали оба эти метода.
В PCL-проекте мы писали всю бизнес-логику, работу с БД, сетью и т.п. Основной плюс в том, что PCL не позволит использовать какой-нибудь системный класс, не реализованный на одной из платформ. Так что написанный и собранный в рамках PCL код гарантированно запустится на всех выбранных платформах.
Минус в том, что PCL-библиотека пишется исходя из пересечения возможностей всех выбранных ОС, не позволяя использовать то, что отсутствует в одной из них. Т.е., если мы планируем использовать только iOS и Android, а какой-то нужной фичи нет в Windows Phone – мы ей не сможем воспользоваться. При этом для PCL есть набор “профилей”, определяющих поддерживаемые платформы, но на момент написания статьи выбрать вариант “только iOS и Android, без Windows Phone и Windows” невозможно.
В результате мы помещали в shared-сборку код, гарантированно работающий на iOS и Android, но не способный собраться под PCL. Например, туда попала поддержка gzip-ответов и другая специфика работы с сетью или базой
В PCL может не быть банальных вещей, вроде работы с файлами и т.п. — в этом случае предполагается, что в PCL-сборке будут интерфейсы, а реализации — уже в проекте под конкретную ОС. В нашем случае часть таких реализаций как раз-таки попадало в shared-сборку.
К слову, если выбираете профиль для PCL – советуем выбрать профиль 259. Подходит лучше всех по имеющимся возможностям. Мы начали на другом, не имеющем в своём составе, например, мьютексов или потокобезопасных словарей — написать руками можно, но зачем? Так же отмечу, что выбор профиля гораздо удобнее и нагляднее делается в Xamarin.Studio, а не в Visual Studio:
Ну и на закуску — ещё одна особенность PCL: вы не можете добавить в зависимости одной PCL-библиотеки другую PCL-библиотеку с иным профилем. Точнее, добавить то можете, но не любой профиль уживётся с любым. В общем, идея PCL в целом юзабельна, но в частностях может довести до белого каления.
Базовая идея Xamarin в том, что вы можете писать код, используя те же классы, методы и структуры, что использовали бы при написании нативного кода, просто теперь он пишется на C#. Но есть нюансы…
В случае с iOS существует довольно занятная багофича с делегатами. Вот, скажем, компонент UIScrollView. Ему можно назначить либо делегат, обрабатывающий определённые события, либо подписаться на эти события напрямую.
var scrollView = new UIScrollView();
//вариант 1
class UIScrollViewDelegate1: UIScrollViewDelegate
{
public override void ScrollAnimationEnded(UIScrollView scrollView)
{
base.ScrollAnimationEnded(scrollView);
Debug.WriteLine("Yes, animation ended");
}
}
scrollView.Delegate = new UIScrollViewDelegate1();
//вариант 2
scrollView.ScrolledToTop += (_, __) => { Debug.WriteLine("Yes, scrolled to top"); };
scrollView.ScrollAnimationEnded += (_, __) => { Debug.WriteLine("Yes, animation ended"); };
Причем при подписке на событие ScrollAnimationEnded происходит автоматическая замена делегата на внутренний Xamarin’овский. И подписка на событие ScrolledToTop будет потеряна. Казалось бы – в чем проблема? Просто не смешивай в одном коде подписку на события и делегаты! Но порой встречаются проблемные ситуации:
Или вот, например, в Xamarin.iOS используется класс единый класс UITableViewSource, заменяющий два iOS-протокола UITableViewDataSource и UITableViewDelegate. Это может сбить с толку.
Так же иногда меняются сигнатуры методов и классов, тот же iOS конструктор fileURLWithPath превратился в Xamarin в CreateFileUrl [14].
Аналогичная ситуация встречается и в Android'е — скажем, в оригинале константа GONE находится в классе View, а в Xamarin’овском варианте для той же цели нас есть enum ViewStates со значением Gone. Подобная проблема имеется и с некоторыми другими методами и константами, что вносит некоторую путаницу при переходе с нативной платформы.
Для полного счастья, фреймворк не скрывает от вас часть особенностей конкретной ОС. Например – фоновая работа с сетью:
Вы скажете — это ведь просто особенности конкретной платформы? Именно. Но никто от разработчика эти особенности под абстракциями не прячет, так что повторяем, изучать каждую из платформ придётся.
В данный момент под Xamarin уже написано немало компонентов [15], но под iOS и Android их всё-таки написано больше. Если понадобится, то теоретически можно подключить бинарную библиотеку, написанную на Object-C или Java, но придётся писать проект-биндинг для связи между нативной библиотекой и Xamarin-приложением. Для iOS здорово поможет утилита Objective Sharpie [16], способная самостоятельно сгенерировать такой проект, но она тоже не всегда работает на 100% точно, приходится порой редактировать результат такой генерации руками, а местами даже задуматься, нужна ли вам данная библиотека вообще.
К тому же, подобные компоненты авторы часто обновляют с запозданием, по сравнению с нативной версии библиотеки. Мы стакивались с ситуацией, когда плагин TestFairy отставал на пару месяцев от нативной версии. На вопрос в тех.поддержку TestFairy нам ответили, что всё нормально, вы не теряете ничего, кроме пары мелких фич. Но при выходе новой версии Xamarin возникла проблема: приложения с данной библиотекой собранные в этой версии Xamarin начали падать в реалтайме.
После изучения тонкостей фреймворка выводы напрашиваются сами собой.
В статье также планировался рассказ про Xamarin.Forms, но тот раздел настолько растянулся, что мы решили выделить его в отдельную статью. В ней мы расскажем про различные проблемы UI-фреймвока Xamarin.Forms и о том, как мы их решили. Ну а пока – ставьте лайки и подписывайтесь на блог! Хотя нет, нафиг штамп…
Автор: СКБ Контур
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka-pod-ios/106221
Ссылки в тексте:
[1] Image: http://habrahabr.ru/post/273075/
[2] приложения под Android: http://habrahabr.ru/company/skbkontur/blog/234241/
[3] версию под iOS: https://itunes.apple.com/us/app/kontur.el-ba/id1004954700
[4] писалось: http://habrahabr.ru/post/188130/
[5] неоднократно: http://habrahabr.ru/company/icl_services/blog/270051/]
[6] как и год назад: http://habrahabr.ru/post/233395/
[7] для подписчиков MSDN: https://xamarin.com/msdn
[8] MonoDevelop: http://www.monodevelop.com/
[9] например такими: http://habrahabr.ru/company/icl_services/blog/270051/
[10] Xamarin.Profiler: https://xamarin.com/profiler
[11] Mono log profiler: http://www.mono-project.com/docs/debug+profile/profile/profiler/
[12] Shared Project: https://developer.xamarin.com/guides/cross-platform/application_fundamentals/shared_projects/
[13] PCL Library: https://developer.xamarin.com/guides/cross-platform/application_fundamentals/pcl/introduction_to_portable_class_libraries/
[14] CreateFileUrl: https://developer.xamarin.com/api/member/Foundation.NSUrl.CreateFileUrl/p/System.String/Foundation.NSUrl/
[15] немало компонентов: https://components.xamarin.com/
[16] Objective Sharpie: https://developer.xamarin.com/guides/ios/advanced_topics/binding_objective-c/objective_sharpie/
Нажмите здесь для печати.