![](https://habrastorage.org/web/338/941/036/3389410364644f5ab659bc8a4b0b7044.png)
В прошлых главах мы строили архитектуру приложения на Xamarin таким образом, чтобы отдельные контролы можно было переиспользовать самым простым образом в других приложениях. В этой части мы обернем эти контролы в отдельный NuGet-пакет, опубликуем его на сайте nuget.org и попробуем переиспользовать их в другом приложении, при этом написав минимальное количество кода.
В первой и во второй главах мы разработали приложение, которое состояло из 3 основных контролов: авторизация, каталог товаров, корзина. Это, пожалуй, типичный набор для любого интернет-магазина. Структура приложения была следующей:
Авторизация > Каталог товаров > Корзина.
Первоначально пользователь видит окно авторизации, далее добавляет товары из каталога в корзину. Представим себе ламповую ситуацию, когда ВНЕЗАПНО заказчик хочет поменять эту структуру на следующую: на первом экране показывать сразу каталог товаров, которые можно смотреть, но нельзя добавлять в корзину до тех пор, пока в отдельном окне пользователь не авторизуется, для наполнения корзины.
![](https://habrastorage.org/web/8b7/ca2/2f8/8b7ca22f8a84405b9b507f67fe5a79b6.png)
… лирическое отступление
В условиях Agile такая ситуация может происходить очень часто и мы, разработчики, должны быть готовы к таким изменениям требований. К сожалению, я все чаще сталкиваюсь с ситуациями, когда для реализации такого рода требований заказчика команда занимается вкручиваем костылей, чтобы выпустить новую версию приложения как можно скорее. Постепенно количество костылей увеличивается, они могут порождать новые баги и проект становится сложно поддерживать. В результате необходимо тратить недели, а то и месяцы на рефакторинг запутавшихся связей между модулями. С другой стороны, можно было потратить это время при старте проекта на создание архитектуры, готовой к таким изменениям. Основная идея этой архитектуры в том, что элементы управления (самодостаточные контролы) не должны зависеть от других элементов управления, чтобы их можно было изолировано менять, комбинировать между собой и т. д. Но их взаимодействие должно осуществляться по модели подписок в одном определенном месте. Получается что-то вида микросервисной архитектуры, но на фронтенде. :)
Немного повозмущались, приступим к выполнению поставленной задачи.
Глава 1. Создание NuGet пакета и публикация его в nuget.org.
Для поставленной выше задачи создавать nuget пакеты, конечно, не обязательно, но почему бы попутно не разобраться с тем, как это все работает. А работает оно и в правду очень просто. Возьмем проект, который мы создавали на протяжении предыдущих 2 статей, он состоит из 3 модулей: Android, IOS и, так называемый, Portable Class Library. Мы будем создавать пакеты в Visual Studio for Mac.
1) Заходим в свойства проекта PCL (правая кнопка мышки по названию проекта -> Options)
2) Ищем вкладку NuGet Package > Metadata
![](https://habrastorage.org/web/b87/a11/b93/b87a11b9327840e19990d7d89f0833f1.png)
Заполняем поля в General. Они обязательные. Тут рекомендуется сразу придумать какой-то уникальный ID. Можно зайти на сайт nugget.org и попробовать найти библиотеку с вашим ID. Если такой нет – можете его занимать. К сожалению, проверки на уникальность прямо в VS нет. Версия: 1.0.0. Версию надо указывать именно такой, чтобы потом было проще обновлять сборку. Закрываем окно, делаем Build проекта.
3) Кликаем по названию проекта правой кнопкой мыши, выбираем пункт “Create NuGet Package»
![](https://habrastorage.org/web/e50/f71/df6/e50f71df6d3042709325f0617364debc.png)
Пакеты создадутся, и сохранятся в папке <название проекта>/<название проекта>/bin/debug/<ID пакета>.<Версия>.nupkg.
В моем случае это …/test5/test5/bin/debug/my_test_nuget.1.0.0.nupkg
Этот пакет мы и будем загружать на сайт nuget.org
4) Заходим на сайт nuget.org. Авторизуемся/Регистрируемся. Заходим во вкладку Upload, и загружаем файл с разрешением .nupkg из пункта 3.
![](https://habrastorage.org/web/f26/2bc/cd8/f262bccd81fa49759693c9bcb6729143.png)
Можем дополнить какой-то дополнительной информацией и нажимаем Submit. Этот пакет в поиске NuGet, мы пока не найдем (в нем он появится после индексации – обычно это час), однако этот пакет можно добавлять в любые проекты через консоль…
![](https://habrastorage.org/web/846/cdb/c39/846cdbc3903747738d53d2d6f0b0eb9e.png)
Если вы видите такое сообщение, значит вы все сделали правильно.
Глава 2. Использование самодостаточных контролов в других проектах
Итак, я создал и опубликовал контролы из предыдущих глав (авторизация, каталог товаров и корзина)
Создадим новый проект и добавим в него опубликованную сборку. Я назвал ее shop_controls_toolkit. Добавить её можно несколькими путями:
1) Из Nuget консоли (Install-Package shop_controls_toolkit -Version 1.0.8)
2) Или найти его в поиске NuGet (Packaged -> Add Package)
Добавим необходимые контролы в MainPage.xaml
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:testapp2" x:Class="testapp2.testapp2Page"
xmlns:controls="clr-namespace:testcontrols;assembly=testcontrols">
<Grid>
<controls:ProductsListing x:Name="listing"></controls:ProductsListing>
<Grid x:Name="menu">
<controls:AuthorizationView x:Name="auth"></controls:AuthorizationView>
<controls:BasketView x:Name="basket"></controls:BasketView>
</Grid>
<Button Clicked="Handle_Clicked"
Image="burger.png">
</Button>
</Grid>
</ContentPage>
Необходимо прописать xmlns, чтобы на этом уровне были видны контролы из добавленной библиотеки
xmlns:controls="clr-namespace:testcontrols;assembly=testcontrols"
Для соответствующего визуального эффекта так же нужно указать контролам их расположение Vertical и Horizontal Options.
В code-behind надо проинициализировать использование всех контроллов и сервисов из библиотеки testcontrols, сделать это можно, например, в конструкторе App.cs
testcontrols.Core.DI.Bootstrapper.RegisterIoC();
Так же нужно подписаться на соответствующие сервисы, как это было описано во 2 части.
public testapp2Page()
{
InitializeComponent();
_authService = Container.GetInstance<IAuthorizationService>();
_authService.AuthorizationChanged += AuthService_AuthorizationChanged;
listing.AddProductRequest += Listing_AddProductRequest;
}
void AuthService_AuthorizationChanged(bool isAuth)
{
if(isAuth)
{
basket.IsVisible = true;
auth.IsVisible = false;
}
else
{
basket.IsVisible = false;
auth.IsVisible = true;
}
}
Т.е. показываем корзину или авторизацию в зависимости от того, авторизован ли человек.
Точно так же можно подписаться на события в листинге товаров. Например, мы хотим ограничить добавление товаров в корзину так, чтобы их можно было бы добавлять только при авторизованом клиенте.
Подписываемся в конструкторе на Action контрола каталога товаров AddProductRequest
async void Listing_AddProductRequest(string sku)
{
if(_isAuth)
{
_basketService.StartAddingProduct(sku);
return;
}
await DisplayAlert("Авторизуйтесь", $"Для того, чтобы добавить товар в корзину необходимо авторизоваться", "Хорошо");
}
Ну и далее можно подписываться на все event не вникая в саму реализацию контролов. Также у сервиса BasketService есть такие поля, как TotalCount или TotalPrice…
![](https://habrastorage.org/web/168/247/5c3/1682475c3d7b4bb3a33aefcfc8caa7de.gif)
Обновление Nuget пакетов
Если вдруг мы хотим обновить что-то в библиотеке контролов, нам необходимо в проекте увеличить версию в Options проекта, и загрузить на сайте nuget.org .ngpkg файл с увеличенной версией, как будто это новая сборка (повторить действия из первой части этой статьи). Сам nuget поймет что это просто новая версия уже существующей библиотеки, и обновит ее версию.
Через некоторое время (обычно это до 10 минут) в проекте, который использует эту библиотеку, появится лэйбл рядом с названием сборки, который и будет означать то, что версию можно обновить. Обновляем…
![](https://habrastorage.org/web/f0d/7f3/ee5/f0d7f3ee5cf84197b1c0ba71f88d4fa9.png)
Вот и всё.
Благодаря такому подходу мы можем создавать различные контролы, оборачивать их в отдельный NuGet пакет и переиспользовать его во всех приложениях.
Можно сделать перегрузку метода инициализации пакета, где будет доступна настройка дополнительных параметров, например: URL back-end API приложения, время хранения кэша данных и т.д., чтобы делать контролы еще более универсальными. В самом приложении мы не будем вникать в реализацию этих контролов – главное их правильно использовать. Скорость разработки увеличится, кол-во костылей уменьшится, а наши менеджеры будут радоваться скорости внесения изменений необходимых бизнесу.
> Проект доступен в GitHub
Интересно, что думают пользователи Хабра о таком подходе – оставляйте комментарии. В планах создание универсальной библиотеки для любого интернет магазина, чтобы упростить создание подобного рода B2C или B2B приложений.
Предыдущие статьи цикла читайте здесь и здесь.
Rambalac
А редактор там уже появился? Или так же всё только текстом писать?
sprodan8
Вы имеете в виду верстку UI?
Rambalac
Да. Последний раз, что я пробовал, приходилось постоянно перезапускать всё в эмуляторе просто чтобы посмотреть влезло ли всё на экран.
sprodan8
По факту существует так называемый Xamarin.Forms Previewer. (View > Other Windows > Xamarin.Forms Previewer), но на данный момент пользоваться им, я, конечно, бы не стал :)
Во 1 — сильно грузит комп, Во 2 — он очень «нежный». Может внезапно выдать «An exception occured while rendering the control», причем нет кнопки rerender или перезапустить…
Но вообще, в xaml никогда не было хорошо с preview. После нескольких месяцев верстки, развивая воображение, кол-во перезапусков приложения, чтобы посмотреть влезло ли, сводится к 0.