Xamarin Forms в действии. Medchest Assistant

  • Tutorial

Автор: Константин Марс

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

Мы долго колебались с выбором платформы между популярной и престижной iOS и модным, современным и приятным в разработке Android. Поэтому я предложил использовать Xamarin, который, между прочим, использует C# как основной язык разработки (и это главный язык, на котором в повседневной жизни пишет организатор нашей команды Арсений). Таким образом мы подошли к началу путешествия в мир кроссплатформенной разработки с Xamarin.

Отмечу, что Xamarin изначально базировался на фреймворке Mono, и поэтому несколько отличается от оригинального .NET-фреймворка Microsoft. Но эти отличия обсудим немного позднее.

В статье не станем обсуждать подробности хакатона и не будем углубляться в профессиональные секреты разработки с помощью Xamarin. Эта статья — базовая вводная в мир кроссплатформенной разработки с помощью Xamarin Forms. Цель материала — дать общее представление, как быстро разрабатывать с помощью Xamarin, подсказать, где в будущем искать ответы на более конкретные вопросы.

Архитектура проекта. PCL


Xamarin Forms строится вокруг общего кросс-платформенного кода, и может быть построен по одному из архитектурных подходов — PCL (Portable Class Library) или SAP (Shared Assets Project). Платформо-зависимые проекты — неотъемлемая часть солюшн Xamarin, называются соответственно и размещены в солюшне наравне с проектом общего кода.

Например, в нашем приложении мы имеем такой набор проектов:



Как видите, присутствуют проекты для Android (Droid) и iOS, отдельный проект для AndroidWear (он корректно инсталируется вместе с Android-приложением на смарт-часы, но пока не выполняет заметную полезную работу, кроме демонстрации возможностей фреймворка  Xamarin для создания AndroidWear проектов). Еще есть проект библиотеки VuforiaBindings library (Java wrapper, который был задуман как интегратор Java-библиотеки Vuforia для распознавания образов и текста). Это примеры ключевых видов проектов, наиболее часто встречающихся при разработке c помощью Xamarin.

Xamarin Forms. XAML


Главное преимущество разработки приложений с помощью Xamarin для меня — возможность создавать UI для нескольких платформ одновременно. Xamarin позволяет создавать отдельные XML-формы для платформо-зависимых проектов и делать UI разным для разных платформ, но все же основной подход — стартовать с Xamarin Forms, создавать XML пользовательского интерфейса, который будет одинаково работать на всех поддерживаемых платформах.

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

global::Xamarin.Forms.Forms.Init (this, bundle); 


В iOS проекте:

global::Xamarin.Forms.Forms.Init (); 


В то же время, если вы заглянете в MainActivity проекта для AndroidWear – вы не найдете там ничего связанного с Xamarin Forms. Это потому что проект для этой платформы пока не поддерживается Xamarin Forms и является “чистым” платформо-зависимым проектом, написанным на C#.

Разметка UI в Xamarin Forms наывается XAML. Здесь все очень похоже на “классический” .NET (WPF):



Внутри XAML выглядит тоже вполне привычно для тех, кто имеет опыт работы с .NET:

<StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand">
            <Label x:Name="label" Text="List of medicines" HorizontalOptions="Center" />
            <StackLayout Orientation="Horizontal">
                <Entry x:Name="nameEntry" HorizontalOptions="FillAndExpand" />
                <DatePicker x:Name="datePicker" HorizontalOptions="End"/>
                <Button x:Name="addButton" Text="Add" Clicked="add" HorizontalOptions="End" />
                <Button x:Name="scanButton" Text="Scan" Clicked="scan" HorizontalOptions="End" />
            </StackLayout> 



Ключевой функционал Bindings работает по тем же принципам, что и биндинги в WPF:

<ListView x:Name="list" VerticalOptions="FillAndExpand">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <TextCell Text="{Binding Name}" Detail="{Binding ExpireDate, StringFormat='Expires: {0:MM-dd-yy}'}">
                            <TextCell.ContextActions>
                                <MenuItem Clicked="onDelete" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" />
                            </TextCell.ContextActions>
                        </TextCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>



Мы просто размещаем “{Binding <VARIABLE NAME>}” в XAML вместо хардкода значений.

Основной проблемой для разработчиков Xamarin, которые работают в Xamarin Studio (например на Mac OS) является отсутсвие адекватного визуального редактора UI. Странно, что при этом студия обеспечивает разработчикам визуальные редакторы для конкретных платформ, таких как Android и iOS, но, увы, не для Xamarin Forms.





DependecyService. Платформо-специфичные возможности и Xamarin Forms


Когда приходит время реализовать что-то специфичное для платформы (например, нотификации), нам уже не обойтись без платформо-зависимого кода.
Это неизбежно — ведь те же нотификации реализуются совсем по-разному для Android и iOS, и эта разница выражается во многих нюансах поведения функционала. Но как тогда вызывать подобный платформо-зависимый код из UI, общего для всех платформо-зависимых проектов?

Здесь нам на помощь приходит DependencyService.
Как обычно в кросс-платформенной разработке, нужно объявить интерфейс в общем проекте и реализовать его в платформо-зависимых проектах. Единственным вопросом будет «как определить, какую реализацию вызвать в каждом конкретном случае?». И тут за работу берется DependencyService, магический деятель фреймворка Xamarin. В зависимости от того, для какой платформы мы собираем проект, DependencyService подставляет необходимую реализацию вместо интерфейса.
Также стоит отметить, что для того чтобы эта магия заработала, нужно использовать аннотацию Xamarin.Forms.Dependency:

[assembly: Xamarin.Forms.Dependency (typeof (NotificationHelperImpl))]


Например, интерфейс нотификаций, объявленный в общем проекте Xamarin Forms выглядит так:

namespace MedChestAssistant
{
    public interface INotificationHelper
    {
        void notify(String message);
    }
}



А платформо-зависимая реализация в Android-проекте выглядит так:

[assembly: Xamarin.Forms.Dependency (typeof (NotificationHelperImpl))]
namespace MedChestAssistant.iOS
{
    public class NotificationHelperImpl: INotificationHelper
    {
        #region INotificationHelper implementation

        public void notify (string message)
        {
            var notification = new UILocalNotification();

            // set the fire date (the date time in which it will fire)
            notification.FireDate = NSDate.FromTimeIntervalSinceNow(5);

            // configure the alert
            notification.AlertAction = "Medical Chest Reminder";
            notification.AlertBody = "Lyrica will expire in 2 days. Don't forget renew it";

            // modify the badge
            notification.ApplicationIconBadgeNumber = 1;

            // set the sound to be the default sound
            notification.SoundName = UILocalNotification.DefaultSoundName;

            // schedule it
            UIApplication.SharedApplication.ScheduleLocalNotification(notification);
        }

        #endregion

        public NotificationHelperImpl ()
        {
        }
    }
} 




В целом все достаточно просто :).

Зависимости. Пакеты. Галерея NuGet


Xamarin имеет довольно богатую библиотеку пакетов, совместимых с поддерживаемыми платфорамами — NuGet. Например, тот, кому нужно распознавание и сканирование баркодов может воспользоваться пакетом Zxing, совместимым с Xamarin.



После добавления пакет появися в списке подключенных пакетов проекта.
Вот, например, кросс-платформенная часть пакета Zxing в нашем кросс-платформенном проекте Xamarin Forms:



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

Android:

ZXing.Mobile.MobileBarcodeScanner.Initialize (Application);


iOS:

ZXing.Net.Mobile.Forms.iOS.Platform.Init();


Также платформ-специфичная инициализация бывает нужна и для стандартного функционала.
Например, нотификции в iOS требуют декларирования поддерживаемых форматов на старте приложения (это делается всегда в нативном iOS, и Xamarin просто покрывает уже существующую специфику):

if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
                var notificationSettings = UIUserNotificationSettings.GetSettingsForTypes (
                    UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound, null
                );

                app.RegisterUserNotificationSettings (notificationSettings);
            }


Вот и весь краткий обзор возможностей разработки с Xamarin.

Исходный код нашего проекта с хакатона вы можете посмотреть здесь: https://github.com/DataArt/MedChestAssistant.git

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

Если вы хотите узнать больше про Xamarin, обратитесь к официальной книге от Microsoft https://developer.xamarin.com/guides/xamarin-forms/creating-mobile-apps-xamarin-forms/
и посетите Xamarin Portal для изучения самых актуальных рецептов кросс-платформенной разработки https://developer.xamarin.com/guides/xamarin-forms/creating-mobile-apps-xamarin-forms/

Удачи вам в мире кросс-платформа! И новых свершений с Xamarin! :)
  • +11
  • 11,5k
  • 7
DataArt
160,00
Технологический консалтинг и разработка ПО
Поделиться публикацией

Комментарии 7

    +2
    Из своего опыта работы с Хамарином, я бы добавил что Forms подходят только для приложений с простейшим UI, если пытаешься делать хоть сколько-нибудь сложный проект то быстро скатываешься к конструкциям типа «if (ios)/ if (android)». В итоге проще и быстрее делать два разных интерфейса под каждую платформу и общую кросплатформенную логику.
    И дальше уже начинаются ньюансы, например в большей части пользовательских приложений логики не так уж и много в итоге выигрыш в скорости разработки мизерный, а нативные приложения, как по мне, все же более качественное и поддерживаемое решение.
    Так что я бы рекомендовал Xamarin только тем кто уже работает с C# и для кого mobile проект временный либо одиночный, ради которого связываться с изучением натива не имеет смысла.
      0
      А где можно почитать что-то хорошее про Xamarin.Android? Интересует разработка исключительно под эту платформу.
      (Да, я знаю, что лучше нативное, но все же)
        0
        Я бы порекомендовал начать с документации самого хамарина, там все достаточно подробно и доступно.
        https://developer.xamarin.com/guides/android/
          0
          Официальная документация по Xamarin.Android — лучшее(на мой взгляд), что можно почитать по этой теме.
          developer.xamarin.com/guides/android/getting_started
          0
          Тогда берем Apache Cordova, один раз написал, поправил где надо и все. Да, скорость работы меньше чем натив или С#, но скорость разработки очень высокая, особенно если использовать дополнительные фреймворки типа Ionic.
            0
            Решения на Cordova заставляют так же желать лучшего(реализовывал на Cordova+Ionic+Crosswalk). UI-отклик и анимации далеко не совершенны… Увы =( Android API 16 при сериализации объекта в 10МБ отваливается(казалось бы браузер должен осилить объем сериализации в таком мизерном объеме). Опять же… Скролл на Android API 16(может только у меня так...) уходит в «Нидерланды»… Под WP8.1(его так же стоит брать в расчет, если говорим о Cross и Hybrid Apps) билдит изображения туда же в каталоги «Нидерландов», так что в итоге приходится править проект руками… Вот в принципе все с чем я нехорошим столкнулся от Cordova+Ionic. И да, как по мне, так сейчас неплох React Native.
            0

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

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

          Самое читаемое