Xamarin Forms в дії. Medchest Assistant


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

Коли ми прийшли на 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! :)

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.