Русский
Русский
English
Статистика
Реклама

Xamarin

Мигель де Икаса от Midnight Commander до Mono в .NET 5

01.12.2020 12:23:05 | Автор: admin


Мигель де Икаса создал целый ряд громких проектов: GNOME, Mono, Xamarin, Midnight Commander Для одних айтишников это человек-легенда, сделавший поразительно много для опенсорса и .NET-экосистемы. Другие ничего не знают о нём, но постоянно пользуются плодами его трудов.


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


Как человек, создавший GNOME, мог оказаться в Microsoft? СЕО какого ключевого IT-проекта современности долго был его главным сподвижником? Почему Ричард Столлман назвал Мигеля предателем сообщества свободного ПО, а некоторые другие говорят, что он всю жизнь занимается клонированием?




Начало


Де Икаса родился в Мехико в 1972-м. Он получал высшее математическое образование, но так и не завершил обучение: поворотной точкой в его судьбе стал момент, когда он наткнулся на манифест GNU.


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


Повод вскоре возник. Ранее при использовании DOS он успел привыкнуть к Norton Commander, и в UNIX-среде ему страшно не хватало такого двухпанельного файлового менеджера. Он написал Ричарду Столлману, засучил рукава, и в 1994-м первым его заметным вкладом стал Midnight Commander вариация на тему Нортона.



Midnight Commander на современном 5K-экране


Сейчас, спустя десятилетия, этим продуктом по-прежнему ежедневно пользуется множество людей, включая самого Мигеля. Как говорит он сам, если смотреть на соотношение затраченных усилий и полученной отдачи, то mc самый успешный проект за всю его жизнь.


Можно назвать Midnight Commander клоном, но вряд ли его автора это заденет. Де Икаса и не претендовал на оригинальность, а вместо этого решал практическую задачу: если есть две хороших вещи из разных миров, как их совместить и пользоваться преимуществами обеих сразу? По сути, этот же подход проявился и во всей его дальнейшей деятельности. Пока многие люди привязаны к одной платформе и считают остальные вражескими, Мигель видит хорошее в разном и охотно приносит чьи-то идеи с одной платформы на другую, став своеобразным королём портирования.


Следующей его заметной задачей после Midnight Commander стала работа над переносом Linux на SPARC. И благодаря этому опыту в 1997-м его позвали на собеседование в Microsoft (там тогда хотели принести Internet Explorer в том числе на SPARC). Казалось бы, для ценителей свободного софта эта компания на тот момент была обителью зла, как в принципе можно было задумываться о работе там? Но Мигель отправился на собеседование и утверждает, что уговаривал тогда сотрудников Microsoft освободить исходный код IE.


Вот это опередил время компания полюбила опенсорс парой десятков лет позже. И получила Мигеля в качестве сотрудника парой десятков лет позже. А в 1997-м устроиться ему не удалось по формальным причинам: с неоконченным высшим образованием мексиканцу было не получить американскую рабочую визу.




GNOME


После выхода Windows 95 стало очевидно, что Linux на десктопе очень уступает проприетарному конкуренту. В 1996-м появился проект KDE, призванный сделать так, чтобы в Linux всё наконец выглядело консистентно и приятно. Он стал набирать популярность казалось бы, можно только порадоваться. Но когда де Икаса обратил внимание Ричарда Столлмана на этот проект, тот заметил, что зависимость от Qt делала KDE несвободным. Попытка Мигеля связаться с авторами Qt (чтобы для этого случая было отдельное лицензирование) не увенчалась успехом. И возникла новая практическая задача для GNU: сделать среду с преимуществами KDE, но свободную. Получается, что и здесь во многом был перенос чужого опыта на новые рельсы.


В 1997-м де Икаса и другой мексиканский разработчик Федерико Мена с благословения Столлмана взялись за задачу. И в 1999-м была выпущена первая версия GNOME (поначалу название означало GNU Network Object Model Environment). Интересно, что важным достижением GNOME Мигель считает не только сам продукт, но и организационную структуру с советом директоров по его словам, впоследствии это повлияло на многие другие опенсорсные проекты, включая .NET Foundation.


А про первую версию GNOME он иронично замечал, что она опередила моду на градиенты и виджеты (в панели задач могли выполняться самые разные процессы, вот на скриншоте рыбка, она просто плавала и всё):



В связи с GNOME Мигель писал ещё и программу Gnumeric. Здесь тоже был прямой аналог чужой работы: автор и сам сравнивает этот проект с Excel (с уточнением, что кое-что у него тогда получилось лучше, чем у Microsoft). Мигель вложил в Gnumeric немало сил, но позже прекратил его развивать (и за дело взялись другие люди). По его словам, это произошло не по собственной воле: когда шли переговоры с Sun Microsystems об открытии исходного кода StarOffice (так появился OpenOffice), Sun поставили это условием.


Открытый код это прекрасно, но надо было на чём-то и зарабатывать. Мигель объединил усилия с Нэтом Фридманом, которого к этому моменту уже давно знал по IRC-сети LinuxNet. Вместе они создали компанию, которая поначалу называлась International GNOME Support, позже переименовалась в Helix Code, а затем стала называться Ximian.


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


Но через пару лет Мигель представил новый проект, который был уже совсем не просто поддержкой GNOME...




Mono


На дворе самое начало нулевых. Microsoft стандартизовали свою новую платформу .NET, тем самым открыв дорогу независимым имплементациям, но компания всё ещё никак не ассоциируется со словом открытая. Что в такой ситуации могло заставить линуксоидов, зарабатывающих на GNOME, обратить внимание на .NET? Зачем притаскивать на свою платформу что-то настолько далёкое от неё?


Мигель объясняет это так. В Ximian ощущали, что неудобно писать всё на С/С++, и согласились с дихотомией Аустерхаута: если для основополагающих вещей хорошо подходят системные языки, то вот для высокоуровневого склеивания этих вещей лучше подойдут языки попроще и поудобнее. Но какой именно язык для этого взять?



Сам Аустерхаут для этого создал Tcl, но Столлман велел не использовать Tcl в рамках GNU Project (породив тем самым большой холивар). Альтернативы вроде Python и Scheme оказались недостаточно производительными (вспомним, что в те времена компьютеры были куда менее мощными, чем сейчас). И вот тут-то новая платформа от Microsoft обратила на себя внимание.


Казалось бы, линуксоидам должна была оказаться ближе Java, чем враждебный .NET: она ведь изначально про запуск на любых платформах (write once, run anywhere), а не только на майкрософтовских. Но интересно, что в этом её преимуществе и оказалась подстава. Java была доступна на Linux бесплатно, но не была свободной и для GNU-формата не подходила. Теоретически можно было создать свободную реализацию но это было не сделать скромными силами Ximian, это должен был быть большой опенсорсный проект с участием сообщества. А сообществу было непонятно, зачем тратить силы на освобождение Java, когда имеющаяся несвободная и так бесплатно работала. Вот с .NET история другая: его на платформе не было вообще, если мы не сделаем значит, никакого не будет.


И в 2001-м де Икаса представил на конференции O'Reilly новый проект Mono, призванный принести .NET на Linux. То есть, по сути, снова пошёл по излюбленному пути: увидел крутую штуку на одной платформе и понёс на другую.



Поддержка со стороны сообщества оказалась достаточной для развития проекта, но была совсем не единодушной. Ситуация, когда на Linux имплементируют технологию от Microsoft, закономерно вызывала опасения: в том же 2001-м была описана стратегия компании Embrace, extend and extinguish (поддержать, расширить и уничтожить). Что, если Microsoft пока позволяет Mono существовать, но когда линуксовая экосистема окажется плотно завязана на C#, патентными судами выбьет почву у всех из-под ног?


И когда в 2009-м де Икаса принял участие в опенсорсной инициативе Microsoft CodePlex Foundation, Ричард Столлман человек, текст которого в начале 90-х изменил весь курс жизни де Икасы назвал его предателем сообщества свободного ПО. Мигель ответил сдержанно: Я думаю, есть целый мир разных возможностей, и если Ричард хочет обсудить, как мы можем улучшить опенсорсный/свободный софт, он знает мою почту.


Как бы то ни было, Mono развивался, и его стала использовать маленькая компания (всего из нескольких человек), которая тогда называлась Over the Edge Entertainment. Она в 2005-м выпустила игровой движок может, вы когда-нибудь слышали, он называется Unity В 2007-м эта компания спросила: тут Apple выпустила телефон, сможете запустить Mono на нём? И в итоге благодаря айфону всего лишь за год выросла на порядок. Похоже, успеху C# в геймдеве мы в значительной степени обязаны де Икасе.


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


Зато из бурного успеха Unity на iPhone он извлёк идею для своего следующего шага...




Xamarin


Раз эта айфонная штука явно взлетает, и там есть спрос на C# для игр, почему бы и обычные iOS-приложения не писать на C#? Изначально у Mono появились мобильные направления MonoTouch и Mono for Android, но позже всё изменилось по организационным причинам.


Компания Ximian ещё в 2003-м была куплена другой компанией Novell, но тогда это принципиально не поменяло ситуацию де Икаса и Фридман продолжили работать в том же направлении. А вот в 2011-м сама Novell была поглощена компанией The Attachmate Group, новые владельцы решили не развивать часть направлений и устроили сокращения. В том числе эта судьба постигла команду Mono и самого де Икасу.


Конечно, безработица ему не грозила, такого специалиста наверняка хотели бы заполучить многие компании. Но он не пошёл ни в одну из них. Вместе с тем же самым Нэтом Фридманом, с которым он 12 годами ранее основал Ximian, теперь де Икаса создал Xamarin и туда перешла большая часть его прежней команды из Novell. Первым делом новая компания выкупила у Attachmate разработки, которыми эта команда раньше и занималась: вы ведь всё равно не собираетесь их развивать.


Если ранее у Mono мобильные начинания были пристройками к появившемуся до них, то новая компания в своей работе над Mono-based products сразу ставила мобильную разработку во главу угла. В анонсе первыми пунктами её деятельности сразу оказывались new commercial .NET offering for iOS/Android. А в интервью тех лет Мигель сказал, что в Novell ограничивали мобильное развитие Mono, так что увольнение в чём-то оказалось даже к лучшему, можно стало развернуться как следует.



Название Ximian отсылало к латинскому simian (обезьяна), Mono к испанскому обезьяна, а Xamarin к обезьяньему роду тамаринов.


Вероятно, вы в курсе, чем это кончилось. Компания Microsoft со временем становилась всё больше за кроссплатформенность и открытый исходный код, так что ей всё ближе оказывались идеи де Икасы, которые он пропагандировал ещё с 90-х. В 2014-м она анонсировала .NET Core, идущий в эту сторону. А в 2016-м купила Xamarin со словами теперь дадим всем его возможности бесплатно. И, например, IDE Xamarin Studio позже была перебрендирована в Visual Studio for Mac.


Так Мигель де Икаса и Нэт Фридман, долго работавшие с технологиями Microsoft снаружи компании, в итоге оказались внутри неё. И Фридман сейчас возглавляет другую крупную покупку Microsoft GitHub. А что теперь де Икаса? Проект Mono появился в 2001-м как сторонняя реализация .NET для Linux, которую Microsoft никогда не сделает а как он вписывается в мир .NET спустя 19 лет, когда Microsoft сам уже кроссплатформеннее некуда?


В целом вписывается так: если раньше Mono был отдельным проектом, то сейчас его наработки влились в свежий .NET 5. Например, там соседствуют две виртуальные машины, подходящие для разных случаев: CoreCLR и MonoVM.


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

Эстетика XAML конвертеры значений

04.11.2020 16:22:09 | Автор: admin

В статье представлены обобщённые подходы применения конвертеров значений при написании XAML-кода.

IValueConverterData BindingXAMLWPFUWPXamarin FormsUISwitchConverterKeyToValueConverterInlineConverterAggregateConverterResourceDictionary

Конвертеры значенийсовместно с механизмом привязки данных являются важными компонентами в разработке пользовательских интерфейсов на основеXAML. Конвертеры значений подразумевают наличие логики, помещенной в отдельный класс, реализующий интерфейсIValueConverter. Обычно имя класса отражает функциональное назначение, а сами экземпляры декларируются в разметке.

Switch Converter & Key To Value Converter

На практике многие конвертеры значений имеют тривиальную логику схожую по структуре стернарным оператором (?:)или конструкциямif-else,switch-case-default. Однако существуют обобщенные шаблоныKeyToValueConverterиSwitchConverter, которые позволяют избежать добавления в проект однотипных по структуре классов путём декларирования логических значений и ветвлений непосредственно в разметке.

Концепция

<KeyToValueConverterKey="KeyForMatching"Value="ValueIfKeyMatched"ByDefault="ValueIfKeyNotMatched" /><SwitchConverterByDefault="ValueZ"><CaseKey="KeyA"Value="ValueA" /><CaseKey="KeyB"Value="ValueB" /><CaseKey="KeyC"Value="ValueC" /></SwitchConverter>

Применение

<KeyToValueConverterx:Key="TrueToVisibleConverter"Key="True"Value="Visible"ByDefault="Collapsed" /><ProgressBarVisibility="{Binding IsBusy, Converter={StaticResource TrueToVisibleConverter}}" />
<SwitchConverterx:Key="CodeToBackgroundConverter"ByDefault="White"><CaseKey="R"Value="Red" /><CaseKey="G"Value="Green" /><CaseKey="B"Value="Blue" /></SwitchConverter><ControlBackground="{Binding Code, Converter={StaticResource CodeToBackgroundConverter}}" />

KeyToValueConverter- проверяет входное значение на соответствие со значением из свойстваKey, если соответствие выполнено, то в качестве выходного берётся значение из свойстваValue, в противном случае из свойстваByDefault.

SwitchConverter- выполняет поиск первого соответствующегоCaseиз списка по его ключу из свойстваKey, если соответствующийCaseнайден, то берётся заданное в нём значение из свойстваC31C, в противном случае из свойстваC90CC32C, заданного в самом конвертере значений.

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

Также уKeyToValueConverterиногда полезно задавать ключ вConverterParameterчерез свойствоKeySource

<KeyToValueConverterx:Key="EqualsToHiddenConverter"KeySource="ConverterParameter"Value="Collapsed"ByDefault="Visible" /><ControlVisiblity="{Binding Items.Count, ConverterParameter=0, Converter={StaticResource EqualsToHiddenConverter}}" /><TextBlockVisiblity="{Binding Text, ConverterParameter='Hide Me', Converter={StaticResource EqualsToHiddenConverter}}" />

Для особых случаев уKeySourceвозможны четыре режима работы:

Manual(by default) - в качестве ключа при проверке соответствия всегда используется значение из свойстваKeyлибо выполняется проброс значения, когда оно не задано

ConverterParameter- в качестве ключа всегда используется значение из свойства привязкиConverterParameterлибо выполняется проброс значения, когда оно не задано

PreferManual- еслиmanual Keyявно задан, то он имеет приоритет передConverterParameter

PreferConverterParameter- еслиConverterParameterявно задан, то он имеет приоритет перед manualKey

Стоит также отметить, что уSwitchConverterпомимо обычныхCaseдоступны такжеTypedCase, основное отличие которых в проверке на соответствие по типу значения

<SwitchConverterByDefault="Undefined value"><TypedCaseKey="system:String"Value="String value" /><CaseKey="0"Value="Zero" /><CaseKey="1"Value="One" /><TypedCaseKey="system:Int32"Value="Int32 value" /></SwitchConverter>

Иногда возникает необходимость продебажить работу конвертера значений. Для этой цели уSwitchConverterпредусмотрено свойствоDiagnosticKey, если оно задано, то при срабатывании привязки данных вTraceбудут выводится диагностические сообщения следующего формата

var diagnosticMessage = matchedCase.Is()? $"{DiagnosticKey}: '{matchedValue}' matched by key '{matchedCase.Key}' for '{value}' and converted to '{convertedValue}'": $"{DiagnosticKey}: The default value '{matchedValue}' matched for '{value}' and converted to '{convertedValue}'";Trace.WriteLine(diagnosticMessage);
<SwitchConverterDiagnosticKey="UniqDiagnosticKey"x:Key="CodeToBackgroundConverter"ByDefault="White">...</SwitchConverter>

Dependency Value Converter

Также свойства Key, Value и ByDefault полезно объявлять в качестве свойств зависимости (Dependency Properties), то есть наследовать конвертеры и Cases от класса DependencyObject. Хотя конвертеры значений обычно не являются элементами визуального дерева, что отчасти ограничивает работу механизма привязки данных, тем не менее остаётся возможность производить привязку к статическим ресурсам или наследникам класса Binding, например

<KeyToValueConverterKey="AnyKey"Value="{Binding MatchedValue, Source={StaticResource AnyResource}}"ByDefault="{Binding DefaultValue, Source={StaticResource AnyResource}}" /><KeyToValueConverterKey="AnyKey"Value="{Localizing MatchedTitle}"ByDefault="{Localizing DefaultTitle}" />

Inline Converter

Встраиваемый конвертер позволят перенести логику по преобразованию значений из отдельного класса, реализующего интерфейс IValueConverter, в code-behind класс конкретного представления на основе событийной модели.

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

Для этого необходимо добавить декларацию конвертера в разметку, а code-behind классе определить обработчики для соответствующих событий Converting и ConvertingBack

<Grid><Grid.Resources><InlineConverterx:Key="ComplexInlineConverter"Converting="InlineConverter_OnConverting"ConvertingBack="InlineConverter_OnConverting" /></Grid.Resources><TextBlock Text="{Binding Number, Converter={StaticResource InlineConverter}}"/></Grid>
private void InlineConverter_OnConverting(object sender, ConverterEventArgs e){// e.Value - access to input value// this.DataContext - access to Data Context or another properties of the view// access to child visual elements of this root viewe.ConvertedValue = // set output value$"DataContext: {DataContext}, Converter Value: {e.Value}";}private void InlineConverter_OnConvertingBack(object sender, ConverterEventArgs e){// ...}

Aggregate Converter

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

<AggregateConverter><StepAConverter /><StepBConverter /><StepCConverter /></AggregateConverter>

App.xaml

Обобщённые конвертеры значений полезно помещать в отдельный Resource Dictionary, а затем мержить их в качестве глобальных ресурсов в файл App.xaml. Это позволяет переиспользовать конвертеры значений в различных представлениях без их повторного декларирования.

<Applicationxmlns="http://personeltest.ru/away/xamarin.com/schemas/2014/forms"xmlns:x="http://personeltest.ru/away/schemas.microsoft.com/winfx/2009/xaml"x:Class="Any.App"><Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="AppConverters.xaml" />...</ResourceDictionary.MergedDictionaries></ResourceDictionary></Application.Resources></Application>

Ace Framework

Примеры реализации представленных конвертеров можно найти в библиотеке Ace Framework gitlab bitbucket

С благодарностью за внимание и интерес!

Подробнее..

Кроссплатформенная мобильная разработка история вопроса

04.03.2021 12:16:30 | Автор: admin

Когда речь заходит о разработке сразу для Android и iOS, начинаются холивары и гадания на кофейной гуще. Что перспективнее, Flutter или Kotlin Multiplatform? За этими технологиями будущее, или завтра их обе забудут?

Уверенно делать прогнозы по принципу я так вижу занятие весёлое, но бессмысленное. Как подойти конструктивнее? Как известно, кто забывает об истории, обречён на её повторение. Поэтому я решил вспомнить, какими были предыдущие решения Android+iOS, и посмотреть, что с ними стало. Тогда вместо голых спекуляций будут суровые факты. И эти факты из прошлого полезны для понимания будущего: они показывают, где разложены грабли.

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

Оглавление


Web / PWA

В 2007-м, представляя разработчикам первый iPhone, Стив Джобс объяснял, что нативные приложения не нужны: В iPhone есть полный движок Safari. Так что можете писать потрясающие Web 2.0 и Ajax-приложения, которые выглядят и действуют на iPhone именно как приложения.

Android на тот момент ещё даже не был анонсирован. Но получается, что исторически первым единым решением для iOS и Android стал веб.

Вот только разработчики тогда не разделили энтузиазма Джобса (неудивительно, учитывая тогдашнее состояние мобильного интернета). И годом позже всё-таки появился App Store для нативных приложений. А его комиссия в 30% стала новым денежным потоком для компании. В итоге её позиция сменилась на противоположную: теперь Apple считает, что правильный подход это натив (и предпочитает не вспоминать, что там её лидер говорил в 2007-м, Океания всегда воевала с Остазией).

Однако идея веб-приложений не исчезла, а продолжила развиваться. И в 2015-м новое поколение таких приложений назвали Progressive Web Apps. Они могут хранить данные локально, работать в офлайне, а ещё их можно установить на домашний экран смартфона. Чем это тогда не настоящие мобильные приложения? Что ещё для счастья надо?

Ну, например, для счастья нужны push-уведомления. По состоянию на 2021-й iOS не поддерживает их у PWA, и это мощнейший стопор для распространения подхода. Получается, компания, которая первой хвалила веб-приложения, позже сама поставила главное препятствие на их пути. На change.org есть даже петиция, обращённая к Apple: мы всё понимаем, вы дорожите своими 30%, но эта ситуация должна измениться.

Что в итоге: подход жив, но не стал общепринятым во многом из-за ограничений Apple. В будущем что-то может измениться, стоит следить.


PhoneGap/Apache Cordova

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

PhoneGap появился в 2009-м благодаря компании Nitobi, а в 2011-м Adobe купила её и создала также опенсорсный вариант Apache Cordova. У проекта модульная архитектура, позволяющая подключать плагины. И в сочетании с опенсорсностью это означает, что если Cordova не умеет чего-то нужного (например, взаимодействовать с акселерометром смартфона), сообщество может научить. Вроде как прекрасно, да?

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

Почему так? Среди главных причин называют UX, уступающий нативным приложениям. Всё хуже и с производительностью, и с плавностью. Но основное отличие даже не измерить числами: пользователю попросту заметна разница между гибридным приложением и нативным, они производят разное впечатление. Для людей через WebView ощущения не те.

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

Интересно, что авторы проекта сами предвидели такое развитие событий и ещё в 2012-м написали, что итоговая цель PhoneGap прекратить своё существование. И недавно эта цель была достигнута: в 2020-м Adobe заявили о прекращении разработки, ссылаясь на то, что нишу закрыли PWA.

Что в итоге: разработка прекращена.


Qt

Проект Qt помогал людям заниматься кроссплатформенной разработкой ещё с 90-х, когда речь шла о десктопных ОС, а не мобильных. При этом он завязан на C++, который для Android и iOS не совсем чужой: даже нативные разработчики на этих платформах могут обращаться к плюсам. Так что, казалось бы, поддержка iOS/Android со стороны Qt просто напрашивалась.

Но поначалу дело осложнялось тем, что в 2008-м проект купила Nokia. Компания тогда делала ставку на Symbian и не горела желанием помогать конкурентам. В 2010-м возможностью запускать Qt-приложения на Android занимались энтузиасты, и на Хабре об этом писали:

В 2011-м Nokia отказалась от Symbian в пользу Windows Phone, а часть проекта Qt продала компании Digia. И тогда началась работа над поддержкой одновременно Windows 8, Android и iOS. Ну вот теперь-то счастье? Спустя 10 лет ясно, что тоже нет.

Вакансии по мобильной разработке на Qt сейчас единичные. Хабрапосты о ней появляются очень редко и не свидетельствуют об успехе: в одном причиной использования Qt стала ОС Аврора (экс-Sailfish), в другом попросту у меня уже был большой опыт с ним.

Что помешало? Я встречал жалобы на то, что недостаточно было использовать сам Qt и писать на С++/QML. Потому что средствами Qt многое было не реализовать, и приходилось-таки иметь дело с конкретной платформой (например, на Android работать с Java, увязывая это с плюсовой частью через JNI). Всё это очень неудобно и подрывает исходную идею бодренько запилим два приложения по цене одного.

При этом здесь пользователь тоже ощущает не-нативность. А к IDE Qt Creator есть нарекания, рантайм Qt увеличивает размер приложения, бесплатный вариант Qt подходит не всегда и может понадобиться недешёвый коммерческий. Кроме того, мне лично кажется, что ещё сказался язык. Кроссплатформенной разработке желательно быть такой, чтобы нативным разработчикам было попроще перекатиться туда, а с языком C++ слово попроще не ассоциируется.

И хотя случаи использования Qt встречаются до сих пор, это скорее исключения из правил, у которых могут быть какие-то особые исходные условия: например, хотим перетащить на телефоны с десктопа уже имеющуюся кодовую базу на C++.

Что в итоге: крайне нишевое решение, которое не умерло полностью, но используется очень узкой прослойкой.


Xamarin

Мигель де Икаса ещё в проекте Mono занимался тем, что притаскивал .NET на несвойственные ему платформы (начав с Linux). А когда в 2011-м он вместе со всей командой Mono попал под сокращение, основал новую компанию Xamarin, собрал прежних коллег там, и сосредоточился на мобильных платформах: мол, давайте писать мобильные приложения для них на C#, вот инструмент для этого.

Надо понимать контекст того времени. Годом ранее компания Microsoft выпустила Windows Phone и стремилась стать третьим большим игроком на мобильном рынке. И даже большая Windows лезла на мобильный рынок: готовилась к выходу Windows 8, оптимизированная для планшетов.

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

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

Ещё порой вызывали недовольство и то, что после появления новых фич в Android/iOS приходилось ждать их поддержки в Xamarin, и стоимость лицензии, и общее состояние экосистемы (документация, поддержка, библиотеки).

А тем временем компания Microsoft возлюбила опенсорс и сторонние платформы вроде Linux, так что идеи де Икасы оказались ей близки, и в итоге она купила Xamarin. Теперь его наработки вошли в .NET 5, и в прошлом году представили .NET MAUI (Multi-platform App UI) развитие тулкита Xamarin.Forms. В общем, не забросили купленное.

Что в итоге: пока всё остаётся в странноватом статусе, когда и масштабного взлёта не получилось, и полностью не прекращено.


React Native

Наконец, самое свежее. В 2013-м в Facebook выпустил React, ставший очень успешным во фронтенде, а в 2015-м за ним последовал React Native, приносящий подход в мобильную разработку.

Писать предлагается на JavaScript, поэтому кому-то может показаться, что это реинкарнация PhoneGap и его HTML-подхода, но нет. Когда-то Facebook действительно полагался для мобильных устройств на HTML, но ещё в 2012-м Цукерберг назвал это ошибкой. И у React Native идея не в том, чтобы с помощью HTML/CSS городить что хочешь, а в том, чтобы с помощью JSX использовать нативные элементы UI так что пользователь ощущал себя прямо как с нативным приложением.

Насколько это получилось? Шероховатости и срезанные углы существуют с ними сталкиваются и разработчики, и пользователи. Для кого-то они оказываются критичными: особенно нашумел пост Airbnb, где после React Native решили вернуться к нативной разработке. Но какие-то другие компании (вроде самой Facebook) эти ограничения не остановили, использование в индустрии есть.

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

Если зайти на HeadHunter и сравнить число вакансий по React Native с нативной разработкой, то их немного. Но вот если сравнивать с Qt/Xamarin/PhoneGap то вакансий окажется больше, чем у них всех, вместе взятых, это наиболее успешный вариант.

Что в итоге: React Native не стал так успешен, как его фронтендовый старший брат, но определённую нишу занял.


Выводы

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

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

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

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

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

А вот про Kotlin Multiplatform сделать выводы по прошлому у меня не получилось, потому что у него нетипичная ситуация, отличающаяся от предшественников. Во-первых, идея кроссплатформа годится не для всего тут заложена прямо в фундамент: а мы и не предлагаем объединять всё, реализуйте общую бизнес-логику, а остальное на Android и iOS делайте раздельно. А во-вторых, тут играет на руку родной для Android язык: он уже знаком половине мобильных разработчиков, и такого в кроссплатформе раньше не возникало. Так что опыт предыдущих технологий тут непоказателен остаётся смотреть, что покажет время.

На последнем Mobius было сразу несколько кроссплатформенных докладов (три про Flutter, один про Kotlin Multiplatform) мы уже выложили все видеозаписи конференции на YouTube, так что можете сами их посмотреть. А мы тем временем вовсю работаем над следующим Mobius: он пройдёт 13-16 апреля в онлайне, и там без освещения кроссплатформы тоже не обойдётся. Так что, если вас заинтересовал этот пост, то вам будет интересно и там.

Подробнее..

Xamarin.Forms. Личный опыт использования

25.06.2020 14:15:14 | Автор: admin
В статье речь пойдет о Xamarin.Forms на примере живого проекта. Кратко поговорим о том, что такое Xamarin.Forms, сравним с похожей технологией WPF, увидим, как достигается кроссплатформенность. Также разберём узкие места, с которыми мы столкнулись в процессе разработки, и добавим немного реактивного программирования с ReactiveUI.
image

Кроссплатформа что выбрать?


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

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

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

А теперь к сути


Не так давно нашей команде пришлось лицом к лицу столкнуться с кроссплатформенной разработкой. Задача от заказчика звучала так:
  • Создать iOS-приложение, работающее на iPad;
  • Разработать такое же приложение с расширенным функционалом под Windows 10;
  • Всё это при условии, что правки в дальнейшем могут вноситься как в оба приложения одновременно, так и по отдельности;
  • Сделать приложение максимально гибким, поддерживаемым и расширяемым, потому что техническое задание, как обычно, менялось со скоростью света.

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

Xamarin это инструмент для создания приложений на языках семейства .NET (C#, F#, Visual Basic), который позволяет создавать единый код, работающий на Android, iOS и Windows (UWP-приложения). Это xaml-подобная технология, то есть интерфейс описывается декларативно в формате xml, вы сразу видите, как элементы расположены на форме и какие свойства имеют. Такой подход очень удобен, в отличие, например, от Windows.Forms, в котором, если бы не графический редактор, разрабатывать и редактировать пользовательские интерфейсы было бы крайне сложно, так как все элементы и их свойства создаются динамически. У меня был опыт разработки подобных интерфейсов без декларативных описаний в среде, не имеющей удобного графического редактора, и я не хочу его повторять. В Xamarin.Forms сохранена возможность динамического создания элементов интерфейса в программном коде, но для чистоты кармы и благодарности от последователей вашего кода всё, что можно описать декларативно, лучше так и описывать.

Xamarin.Forms и WPF


Еще одной известной xaml-подобной технологией является WPF (Windows Presentation Foundation). Это потрясающий инструмент для создания красивых интерактивных пользовательских интерфейсов. На мой взгляд, это один из лучших инструментов, созданных Microsoft, имеющий, правда, серьезный недостаток такие приложения можно разрабатывать только под Windows.

Xamarin.Forms включает в себя урезанную версию WPF, агрегируя лишь те компоненты, которые имеют аналоги на других платформах. С одной стороны, это даёт разработчикам, имеющим опыт работы с WPF, неплохую фору для входа в Xamarin.Forms. С другой же, познав всю прелесть и возможности WPF, программисту будет трудно то тут, то там натыкаться на отсутствие всех этих преимуществ в Xamarin.Forms. Мне было крайне грустно осознать, что я не могу использовать шаблоны для элементов управления, которыми так привыкла жонглировать в WPF, в Xamarin.Forms их попросту нет. Или удобный и мощный ItemControl компонент WPF, позволяющий разместить на форме список элементов, задавая каким угодно образом их внешний вид и расположение. С помощью одного только этого компонента как основного можно написать, например, простенький прототип игры в бильярд. В Xamarin.Forms существуют аналоги ItemControl, но все они имеют конкретную реализацию внешнего вида списка, что лишает их необходимой гибкости и вынуждает разработчиков идти на GitHub за велосипедами.

Кроссплатформенность в Xamarin.Forms


Однако не бывает худа без добра. Своими ограничениями Xamarin.Forms платит за кроссплатформенность, которая действительно легко и удобно достигается средствами этого инструмента. Вы пишете общий код для iOS, Android и Windows, а Xamarin сам разбирается, как связать ваш код с родным для каждой платформы API. Кроме того, есть возможность писать не только общий, но и платформозависимый код, и Xamarin тоже поймет, что и где вызывать. Одним из главных механизмов достижения кроссплатформенности является наличие умных сервисов, способных осуществлять кросс-зависимые вызовы, то есть обращаться к той или иной реализации определённого функционала в зависимости от платформы. Платформозависимый код можно писать не только на C#, но и добавлять его в xaml-разметку. В нашем случае iOS версия была урезанной и часть графического интерфейса нужно было скрыть, размеры некоторых элементов также зависели от платформы.

Для большей наглядности приведу небольшой пример. В нашем проекте мы использовали библиотеку классов, предоставленную заказчиком, которая была написана на C++. Назовём её MedicalLib. MedicalLib собиралась в две разные сборки в зависимости от платформы (статическая MedicalLib.a для iOS и динамическая MedicalLib.dll для Windows). Кроме того, она имела различные wrapper-классы (классы-переходники) для вызова неуправляемого кода. Основной проект (общая кодовая база) содержал описание API MedicalLib (интерфейс), а платформозависимые проекты для iOS и Windows конкретные реализации этого интерфейса и ссылки на сборки MedicalLib.a и MedicalLib.dll соответственно. Из основного кода мы вызывали те или иные функции абстракции, не задумываясь, как именно они реализованы, а механизмы Xamarin.Forms, понимая, на какой платформе запущено приложение, вызывали необходимую реализацию и подгружали конкретную сборку.

Примерно так это можно изобразить схематично:
image

Среда разработки


Для написания программ с Xamarin.Forms используется Visual Studio. На MacOS Visual Studio for Mac. Многие разработчики считают это больше недостатком, ссылаясь на тяжеловесность этой IDE. Для меня Visual Studio является привычной средой разработки и на высокопроизводительных компьютерах не доставляет каких-либо неудобств. Хотя Mac-версия этой IDE пока еще далека от идеала и имеет на порядок больше недочетов, чем её Windows-собрат. Для мобильной разработки имеется целый ряд встроенных эмуляторов мобильных устройств, а также возможность подключить реальный девайс для отладки.

Reactive UI и реактивная модель


В основу любого проекта Xamarin.Forms отлично ложится паттерн проектирования MVVM (Model View View Model), главным принципом которого является отделение внешнего вида пользовательского интерфейса от бизнес-логики. В нашем случае мы использовали MVVM, что действительно оказалось удобно. Важным моментом реализации MVVM является механизм оповещений View о том, что какие-то данные изменились и это необходимо отобразить на интерфейсе. Думаю, многие разработчики на WPF слышали об интерфейсе INotifyPropertyChanged, реализуя который во вью-моделях, мы получаем возможность оповещать интерфейс об изменениях. Этот способ имеет свои плюсы и минусы, но главным недостатком является запутанность и громоздкость кода в случаях, когда во вью-моделях есть вычисляемые свойства (например, Name, Surname и вычисляемое FullName). Мы выбрали более удобный фреймворк ReactiveUI. Он уже содержит реализацию INotifyPropertyChanged, а также много других преимуществ например, IObservable.

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

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

Реализовано это было следующим образом: на бэкэнде постоянно крутился некий генератор данных, которые поступали в несколько IObservable. На каждый IObservable во вью-моделях были подписаны соответствующие свойства, которые с помощью механизмов ReactiveUI выводили данные на интерфейс в нужном виде.
image
Взаимодействие с интерфейсом в обратном направлении (т.е. обработка действий пользователя), было реализовано с помощью так называемых Interaction взаимодействий, которые инициировались при работе пользователя с UI (например, при нажатии на кнопку), а обрабатывались в любом месте приложения. Что-то наподобие интерфейса ICommand и команд в WPF, только интеракции в нашем случае назначались на интерфейсные элементы не декларативно (как с командами в WPF), а программно, что показалось не очень удобным.

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

Сложности в процессе разработки


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

Наиболее сложные моменты были связаны с разработкой UWP приложения, Windows добавила немало головной боли из-за некоторых особенностей и ограничений в отношении этих программ.

При сворачивании окна приложение переходит в состояние Suspended, и Windows выделяет ему меньше ресурсов. Это было критично, так как в одной из вариаций наш Data Generator работал, интегрируясь с внешними источниками и получая данные через сокеты. При сворачивании окна сокеты продолжали получать данные, заполняя свой внутренний буфер пакетами. А при выходе из режима Suspended все эти пакеты тут же помещались в буфер приложения, начиная обрабатываться только в этот момент. Из-за этого происходила задержка в отображении данных после развертывания окна, которая была пропорциональна времени, проведенному в свёрнутом виде. Всё решилось грамотной обработкой событий Suspending и Resuming, при наступлении которых мы сохраняли состояние приложения и закрывали сокеты, открывая их снова при восстановлении штатного режима работы.

Ещё одной непростой задачей стало добавление второго окна приложения (это было необходимо в рамках технического задания). Сейчас я не могу сказать, были ли это ограничения UWP, Xamarin.Forms или же наша собственная ошибка краш происходил в конструкторе одного из представлений из-за UI-потоков. Позже выяснилось, что библиотека, предоставленная заказчиком и являющаяся ядром обработки данных, однопользовательская и хранит в себе состояние. Таким образом, два независимых окна требовали двух независимых экземпляров библиотеки, что добавило нам одну большую низкоуровневую задачу, решение которой не было бы тривиальным. Мы решили, что овчинка выделки не стоит и проще не открывать отдельное окно, а создавать новый экземпляр приложения со своими настройками и адресным пространством. В итоге со стороны пользователя это выглядело в точности как второе окно (даже при закрытии главного окна второе тоже завершало свою деятельность), и разницу можно было заметить, только заглянув в диспетчер задач и увидев второй процесс.

Ну, и главный недостаток UWP, с которым пришло немало повозиться, это политика его распространения. Чтобы установить приложение, его либо необходимо загрузить в Microsoft Store и скачивать оттуда, либо поставлять дистрибутив другим способом с одним ограничением тогда при его установке необходимо дать операционной системе соответствующие разрешения (Sideloaded Apps в настройках Windows). Техническое задание требовало реализации второго подхода, однако политика безопасности заказчика запрещала сотрудникам компании менять подобные настройки. В итоге нам пришлось написать инсталлер, который перед установкой включал Sideloaded Apps, устанавливал пакет и в конце выключал эту настройку (естественно, по согласованию с заказчиком).

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

Что касается архитектуры и каких ошибок можно было бы избежать?

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

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

Еще стоит отметить, что достаточно много времени наша команда потратила на адаптацию визуальной части пользовательского интерфейса под Windows-приложение. Сжатые сроки и приоритеты заказчика поставили разработку iOS-версии на первое место, поэтому к UWP мы приступили, имея уже наполовину готовый проект, работающий на iOS. Изначально не предполагалось изменение разрешения, и приложение оказалось не готовым к свободному масштабированию окна, не имея достаточной гибкости в расположении элементов, что привело нас к довольно объемному рефакторингу всех визуальных компонентов. Поэтому не могу не отметить, что разработка кроссплатформенного проекта всё-таки должна вестись параллельно на всех предполагаемых платформах.

Итог


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

Благодаря архитектуре и выбранным решениям, со всеми их достоинствами и недостатками, проект уже полтора года наращивает функционал без какого-либо глобального рефакторинга и чувствует себя твёрдо стоящим на ногах. Инструмент работает и со своими основными задачами справляется. Кроме того, он не является новым для IT-сообщества, поэтому документации, которая помогает разобраться в тонкостях, достаточно. То, что теперь кроссплатформенную разработку можно вести на платформе .NET и удобном С#, которые предпочитают многие программисты, является неоспоримым преимуществом и может стать финальным аккордом в решении использовать Xamarin.Forms и на вашем проекте.
Подробнее..

Оживляем деревья выражений кодогенерацией

02.01.2021 00:07:07 | Автор: admin

Деревья выражений System.Linq.Expressions дают возможность выразить намерения не только самим кодом, но и его структурой, синтаксисом.

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

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

(бенчмарк)

Действие

Время, нс

Cached Compile Invoke

0.5895 0.0132 ns

Compile and Invoke

83,292.3139 922.4315 ns

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

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

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

  • Встроенную интерпретацию.
    Необходимость использования интерпретатора вместо компилятора указывается соответствующим флагом:

    Expression.Compile(preferInterpretation: true)
    

    Происходит через рефлексию, но с накладными расходами на формирование стека инструкций.

    Для платформ Xamarin.iOS, Xamarin.watchOS, Xamarin.tvOS, Mono.PS4 и Mono.XBox стандартная компиляция через генерацию IL (System.Reflection.Emit) долгое время была недоступна и на данный момент под капотом всегда откатывается к этому варианту.

  • FastExpressionCompile от @dadhi.
    Ускоряет компиляцию за счет оптимизиpованной генерации IL и с меньшим количеством проверок совместимости.

    На платформах без поддержки JIT компиляции может использоваться только с включенным Mono Interpreter.

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

    Интерпретируя вручную, уже можно воспользоваться способами ускорения рефлексии. Самые эффективные из них, например Fasterflect, используют System.Reflection.Emit и на некоторых платформах так же могут требовать включения Mono Interpreter.

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

Компилировать выражения или какие-то их части во время написания кода (design-time) или сборки (compile-time).

Для compile-time компиляции делегатов к фрагментам деревьев выражений требуется сгенерировать соответствующий код.

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

От самого API требуется только давать нужный делегат по ключу, как в словаре. У интересующих нас фрагментов кода: методов, конструкторов и свойств на стыке run-time и compile-time естественный идентификатор это сигнатура. По ней генерируемый код будет класть делегаты в словарь, а клиенты забирать.

Например, для класса со свойством

namespace Namespace{  public class TestClass  {    public int Property { get; set; }  }}

используемым внутри System.Linq.Expressions.Expression<T> лямбды

Expression<Func<TestClass, int>> expression = o => o.Property;

делегатами чтения и записи в общем виде являются

Func<object, object> _ = obj => ((Namespace.TestClass)obj).Property;Action<object, object> _ => (t, m) => ((Namespace.TestClass)t).Property  = (System.Int32)m;

и генерируемый код для их регистрации будет примерно таким:

namespace ExpressionDelegates.AccessorRegistration{  public static class ModuleInitializer  {    public static void Initialize()    {      ExpressionDelegates.Accessors.Add("Namespace.TestClass.Property",        getter: obj => ((Namespace.TestClass)obj).Property,        setter: (t, m) => ((Namespace.TestClass)t).Property = (System.Int32)m);    }  }}

Генерация

Наиболее известные решения для кодогенерации, на мой взгляд, это:

Отдельная область применения есть у каждого решения, и только Roslyn Source Generators умеет анализировать исходный C# код даже в процессе его набора.

Кроме того, именно Roslyn Source Generators видятся более или менее стандартом для кодогенерации, т. к. были представлены как фича основного компилятора языка и используют Roslyn API, используемый в анализаторах и code-fix.

Принцип работы Roslyn Source Generators описан в дизайн-документе (местами не актуален!) и гайде.

Вкратце: для создания генератора требуется создать реализацию интерфейса

namespace Microsoft.CodeAnalysis{  public interface ISourceGenerator  {    void Initialize(GeneratorInitializationContext context);    void Execute(GeneratorExecutionContext context);  }}

и подключить ее к проекту как анализатор.

Метод Initialize пригодится для выполнения какой-либо единоразовой логики. GeneratorInitializationContext на данный момент может быть полезен только для подключения посетителя узлов синтаксиса кода.

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

Для каждого файла исходного кода Roslyn предоставляет синтаксическое дерево в виде объекта SyntaxTree:

GeneratorExecutionContext.Compilation.SyntaxTrees

а так же семантическую модель:

semanticModel =  GeneratorExecutionContext.Compilation.GetSemanticModel(SyntaxTree)

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

Среди всех узлов синтаксических деревьев сборки нам нужно найти только интересующие нас лямбда-выражения типа System.Linq.Expressions.Expression<T> и отобрать из их узлов-потомков выражения, описывающие доступ к членам классов, создание объектов и вызов методов:

По семантике узла, так называемому символу (Symbol), можно определять:

  • типы, используемые выражением;

  • область видимости;

  • IsStatic, IsConst, IsReadOnly и другие характеристики.

На основе такой информации и будем генерировать подходящий код.

В Roslyn API (Microsoft.CodeAnalysis) построить сигнатуру намного проще, чем c API рефлексии (System.Reflection). Достаточно сконвертировать символ в строку при помощи методаISymbol.ToDisplayString(SymbolDisplayFormat) c подходящим форматом:

Зная сигнатуры свойства/поля, его типа и обладателя формируем строки для добавления делегатов:

Оформляем код добавления делегатов в класс и отдаем компилятору:

var sourceBuilder = new StringBuilder(@"namespace ExpressionDelegates.AccessorRegistration{  public static class ModuleInitializer  {    public static void Initialize()    {");      foreach (var line in registrationLines)      {        sourceBuilder.AppendLine();        sourceBuilder.Append(' ', 6).Append(line);      }      sourceBuilder.Append(@"    }  }}");GeneratorExecutionContext.AddSource(  "AccessorRegistration",  SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));

Этот код обязательно будет добавлен в сборку ...если генератор сможет отработать :)

Дело в том, что хоть Source Generators технически и не фича языка, поддерживаются они только в проектах с C# 9+. Позволить такую роскошь без костылей и ограничений на данный момент могут только проекты на .NET 5.

Совместимость

Поддержку Roslyn Source Generators API для .NET Standard, платформ .NET Core, .NET Framework и даже Xamarin поможет организовать Uno.SourceGeneration.

Uno.SourceGeneration предоставляет собственные копии интерфейса ISourceGenerator и атрибута [Generator], которые при миграции на С# 9 меняются на оригинальные из пространства имен Microsoft.CodeAnalysis простым удалением импортов Uno:

using Uno.SourceGeneration;using GeneratorAttribute = Uno.SourceGeneration.GeneratorAttribute;using ISourceGenerator = Uno.SourceGeneration.ISourceGenerator;
Для подключения достаточно добавить несколько строк в файл проекта.

В проект, где генератор будет использоваться:

<ItemGroup>  <SourceGenerator Include="PATH\TO\GENERATOR.dll" /></ItemGroup>

Например, распространяя генератор через nuget, подключение можно осуществлять вложением MSBuild props файла со следующим путём:

Инициализация

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

Для этих целей отлично подходит Module Initializer. Это конструктор сборки (а точнее ее модуля), который запускается сразу после ее загрузки и до вызовов к остальному коду. Он давно есть в CLR, но к сожалению, в C# его поддержка c атрибутом [ModuleInitializer] добавлена только в 9 версии.

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

Подключение Fody.ModuleInit через MSBuild свойства вместо FodyWeavers.xml исключит конфликты с другими Weaver-ами Fody в проекте клиента.

Использование

Таким образом, при сборке проекта:

  1. Source Generator добавит в сборку код, регистрирующий делегаты для деревьев выражений, в обертке класса ModuleInitializer.

  2. Fody.ModuleInit добавит ModuleInitializer в конструктор сборки.

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

Проверяем:

Expression<Func<string, int>> expression = s => s.Length;MemberInfo accessorInfo = ((MemberExpression)expression.Body).Member;Accessor lengthAccessor = ExpressionDelegates.Accessors.Find(accessorInfo);var length = lengthAccessor.Get("17 letters string");// length == 17

При декомпиляции сборки видно, что сгенерированный код и инициализатор модуля на месте:

Бенчмарки

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

Действие

Время, нс

Вызов простого делегата конструктора

4.6937 0.0443

Вызов сгенерированного делегата конструктора

5.8940 0.0459

Поиск и вызов сгенерированного делегата конструктора

191.1785 2.0766

Компиляция выражения и вызов конструктора

88,701.7674 962.4325

Вызов простого делегата доступа к свойству

1.7740 0.0291

Вызов сгенерированного делегата доступа к свойству

5.8792 0.1525

Поиск и вызов сгенерированного делегата доступа к свойству

163.2990 1.4388

Компиляция выражения и вызов геттера

88,103.7519 235.3721

Вызов простого делегата метода

1.1767 0.0289

Вызов сгенерированного делегата метода

4.1000 0.0185

Поиск и вызов сгенерированного делегата метода

186.4856 2.5224

Компиляция выражения и вызов метода

83,292.3139 922.4315

Полный вариант таблицы, с бенчмарками интерпретации.

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

Flame-график бенчмарка поиска и вызова сгенерированного делегата доступа к свойствуFlame-график бенчмарка поиска и вызова сгенерированного делегата доступа к свойству

Идеи насчёт оптимизации построения сигнатур по System.Reflection.MemberInfo приветствуются. Реализация на момент написания.

Заключение

По итогу получилось современное решение для кодогенерации с актуальной совместимостью и автоматической инициализацией.

Полный код можно посмотреть на: github/ExpressionDelegates, а подключить через nuget.

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

  • Source Generator Playground (github).
    Позволяет экспериментировать с Roslyn Source Generators в браузере, онлайн.

  • Окно визуализации синтаксиса для Visual Studio.
    Удобный инструмент для знакомства с Roslyn Syntax API на собственном коде.

  • Отлаживается Source Generator вызовом отладчика из его кода. Пример.
    Для этого нужен компонент Visual Studio Just-In-Time debugger и включенная настройка Tools -> Options -> Debugging -> Just-In-Time Debugging -> Managed.

  • В сгенерированных *.cs файлах срабатывают брейкпоинты, проверено в Visual Studio16.8.
    При генерации через Uno.SourceGeneration файлы размещаются по пути: \obj\{configuration}\{platform}\g\.
    С Roslyn Source Generators их появление включается через MSBuild свойство EmitCompilerGeneratedFiles.
    Стандартный путь: \obj\{configuration}\{platform}\generated\, переопределяется в свойстве CompilerGeneratedFilesOutputPath.

  • Source Generators можно конфигурировать свойствами MSBuild.
    При использовании Uno.SourceGeneration значение получают вызовом

    GeneratorExecutionContext.GetMSBuildPropertyValue(string)
    

    Для Roslyn Source Generators требуемые свойства необходимо сперва отдельно обозначить в MSBuild группе CompilerVisibleProperty и только после вызывать:

    GeneratorExecutionContext.AnalyzerConfigOptions.GlobalOptions  .TryGetValue("build_property.<PROPERTY_NAME>", out var propertyValue)
    
  • Из генератора можно кидать предупреждения и ошибки сборки.

    //Roslyn Source GeneratorsGeneratorExecutionContext.ReportDiagnostic(Diagnostic)//Uno.SourceGeneration:GeneratorExecutionContext.GetLogger().Warn/Error().
    
Подробнее..

Экраны отсутствующего контента в мобильном приложении на примере Xamarin

08.01.2021 14:08:13 | Автор: admin

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

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

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

Первые шаги к улучшению ситуации

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

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

public class EmptyStateViewModel : ViewModel{    public EmptyStateViewModel(string image, string title, string description)    {        Image = image;        Title = title;        Description = description;    }    public string Image { get; }    public string Title { get; }    public string Description { get; }}

Следующим шагом на платформах(или в xaml в случае для Xamarin Forms) нужно прописать Bindings на проперти вью модели, в зависимости от того, какой mvvm-фреймворк используется.

А что дальше?

А далее возник вопрос - что делать, если по каким-то причинам наш запрос на бекенд фейлится. И тут пришла мысль - переиспользовать уже готовый EmptyStateView, но добавить внизу кнопку Retry, для возможности повторной отправки запроса. Потому мы просто наследовались от EmptyStateViewModel, но добавили поля с текстом кнопки, и командой на клик.

public class ErrorStateViewModel : EmptyStateViewModel{    public ErrorStateViewModel(string image, string title, string description, string actionTitle, Command actionCommand)        : base(image, title, description)    {        ActionTitle = actionTitle;        ActionCommand = actionCommand;    }    public string ActionTitle { get; }    public Command ActionCommand { get; }}

И как все это использовать?

После этого пришло время задуматься - как это менеджить. И тут неплохим показался вот такой вариант. Создаем фабрику, которая будет нам возвращать нужную вью-модель. А так же метод None, который будет возвращать null.

public static class OverlayFactory{    public static T None<T>()        where T : EmptyStateViewModel    {        return null;    }    public static EmptyStateViewModel CreateCustom(string image, string title, string description)    {        return new EmptyStateViewModel(image, title, description);    }    public static ErrorStateViewModel CreateCustom(string image, string title, string description, string actionTitle, Command actionCommand)    {        return new ErrorStateViewModel(image, title, description, actionTitle, actionCommand);    }}

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

public class SomeViewModel : BaseViewModel{    private IItemsLoadingService _itemsLoadingService;        public SomeViewModel(IItemsLoadingService itemsLoadingService)    {        _itemsLoadingService = itemsLoadingService;    }    public ObservableCollection<ItemViewModel> Items { get; } = new ObservableCollection<ItemViewModel>();    public EmptyStateViewModel EmptyState { get; protected set; }    public ErrorStateViewModel ErrorState { get; protected set; }    public override async Task InitializeAsync()    {        await base.InitializeAsync();        await LoadItemsAsync();    }    private async Task LoadItemsAsync()    {        try        {            var result = await _itemsLoadingService.GetItemsAsync();            var items = result.ToList();            ErrorState = OverlayFactory.None<ErrorStateViewModel>();            if (items.Count == 0)            {                EmptyState = OverlayFactory.CreateCustom("img_empty_state", "Title", "Description");            }            else            {                EmptyState = OverlayFactory.None<ErrorStateViewModel>();                // Add items to list            }        }        catch        {            ErrorState = OverlayFactory.CreateCustom("img_error_state", "Title", "Description", "Retry", new Command(() => LoadItemsAsync));        }    }}

На платформах же нам необходимо прописать кастомный Binding для EmptyState/ErrorState вьюх на соответствующие вью модели, в зависимости от используемого mvvm-фреймворка, и проверять, если у нас EmptyStateViewModel/ErrorStateViewModel null, то скрывать соответствующую вьюху. Для этого в нашем случае использовался простой метод SetViewModel.

Для андроида тут все просто, при задании для View ее ViewModel мы установим View уже существующий ViewState из коробки. Если ViewModel null - тогда попросту задаем ViewState Gone, если существует - то Visible:

public void SetViewModel(EmptyStateViewModel viewModel){    ViewModel = viewModel;    View.Visibility = viewModel != null ? ViewStates.Visible : ViewStates.Gone;}

Для iOS немного сложнее - необходимо деактивировать constraints для вьюхи, а только потом - прятать ее. Для начала добавим enum, аналогичный стандартному из Android.

public void SetViewModel(EmptyStateViewModel viewModel){    ViewModel = viewModel;    View.SetVisibility(viewModel != null ? ViewStates.Visible : ViewStates.Gone);}

Нам потребуется несколько extension методов

public static void SetVisibility(this UIView view, ViewVisibility visibility){    var constraints = GetViewConstraints(view) ?? new NSLayoutConstraint[] {};    if (visibility == ViewVisibility.Gone)    {        SaveViewConstraints(view, constraints);        NSLayoutConstraint.DeactivateConstraints(constraints);        view.Hidden = true;        return;    }      if (visibility == ViewVisibility.Visible)    {        SaveViewConstraints(view, null);        NSLayoutConstraint.ActivateConstraints(constraints);        view.Hidden = false;        return;    }}

Тут мы в случае установки ViewVisibility.Gone предварительно сохраняем constraints нашей view и деактивируем их, а при включении видимости - наоборот достаем предварительно сохраненные constraints, обнуляем сохранение, а затем активируем их.

private static NSLayoutConstraint[] GetViewConstraints(UIView view){    return view.GetAssociatedObject<NSMutableArray<NSLayoutConstraint>>(Key)?.ToArray() ??           view.Superview?.Constraints               .Where(constraint => (constraint.FirstItem?.Equals(view) == true) || constraint.SecondItem.Equals(view))               .ToArray();}private static void SaveViewConstraints(UIView view, NSLayoutConstraint[] constraints){    NSMutableArray<NSLayoutConstraint> viewConstraints = null;    if (constraints.Length > 0)    {        viewConstraints = new NSMutableArray<NSLayoutConstraint>();        viewConstraints.AddObjects(constraints);    }    view.SetAssociatedObject(Key, viewConstraints, AssociationPolicy.RetainNonAtomic);}

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

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

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

PS - первая статья на Хабре, потому не судите строго. Но нужно же с чего-то начать.

Подробнее..

WinUI 3 Новая эра разработки под Windows

11.03.2021 20:12:02 | Автор: admin

В календаре 8 марта, а я пишу эту статью.
Почему? - Потому, что WinUI 3 - это важно!

Предыстория

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

История развития десктопной разработки под WindowsИстория развития десктопной разработки под Windows
  • Итак, на дворе 1995 год, и мы начинаем писать наш калькулятор на C++ и Win32. Win32 - самый низкоуровневый системный API, для работы с визуальным интерфейсом. Ниже только Windows Driver Model для драйверов.

  • 2002 год - наш калькулятор уже может быть написан на более высокоуровневой оболочке - WinForms (Windows Forms). Она создаёт обёртку над Win32 для более простого и удобного взаимодействия с системой. А за счёт .NET Framework и CLR, которые так же вышли в 2002 году, мы можем использовать целый букет из различный языков для разработки. В их числе были C#, С++, VB.Net, J# и другие.

  • WPF - наш ответ устаревшим технологиям. В конце 2006 года Microsoft презентуют WPF - обширный API-интерфейс для создания настольных графических программ, имеющих насыщенный дизайн и интерактивность. Новый подход включал в себя совершенно другую модель построения пользовательских приложений, основывающуюся на .NET Framework и DirectX. Вместе с выходом WPF у нас появляются следующие возможности: WEB-подобная модель компоновки, богатая модель рисования, анимации, поддержка аудио и видео, стили и шаблоны, декларативный пользовательский интерфейс, подход MVVM, и язык разметки XAML.

  • 2012 год - выход Windows 8. Очень много споров и дискуссий было на тему свежей ОС. Но самое интересное изменение, которое с ней случилось - выход WinRT или же Windows Runtime. Это именно то, почему у Windows присутствует 2 меню настроек: новое и панель управления. WinRT по существу является API, основанное на технологии COM. COM, в свою очередь, предполагал использование одних и тех же компонентов системы во многих местах одновременно. Например, PrintDialog - теперь единый компонент, к реальному состоянию которого можно получить доступ из любого места системы. Нам теперь не нужно загружать информацию о нём каждый раз при использовании, как это было с Win32.

  • 2016 - Universal Windows Platform или же UWP. Апогей унификации Windows. Продолжающая идею WinRT, UWP активно объединяет системные функции и компоненты под единым программным интерфейсом, который теперь может работать на всех устройствах с Windows 10 без изменений в коде! Но, это касается не только программных функций, но и визуальных компонентов. Так и появляется на свет WinUI 2 - единый визуальный интерфейс для всех приложений на Windows.

Что мы в итоге получаем?

Как результат - у нас есть мощная платформа, с унифицированным программным и визуальным интерфейсом. Наш стандартный калькулятор уже построен как UWP приложение ( Исходный код Windows калькулятора можно найти в открытом доступе на github). Но, что-то всё равно не так

Предпочтения разработчиков по выбору платформы за 2016 годПредпочтения разработчиков по выбору платформы за 2016 год

Опрос от компании Telerik за 2016 год показал, что сообщество разработчиков без явного энтузиазма брались использовать UWP, как основную платформу в своих новых проектах. Что же не так? А всё дело в унификации приложений для Windows. За счёт оборачивания их в различные новые API и Windows Runtime, разработчики потеряли возможность работать со старыми добрыми Win32 напрямую. Они, в свою очередь, предоставляют огромнейшие возможности для тонкой работы с системой. И тот список системных API, которые сейчас доступны из UWP приложений, кажется просто смешным. Ознакомиться с ним более детально можно здесь: Список системных API, доступных через UWP приложение

WinUI 3

Именно проблему недоступности системных API и будет решать новая версия WinUI. WinUI 3 Preview 4 уже находится в пре-релизе, а официальный релиз намечен на март. Но каким образом удастся получить доступ к системным API приложению, которое изначально задумывалось как работающее на WinRT и UWP API?

Всё просто: Необходимо оделить визуальную часть и среду выполнения. Ключом к этому стала платформа .NET:

Из чего появился .NET 5Из чего появился .NET 5

Что такое .NET?

  • Из блока предыстории можно узнать, что в 2002 году вышла Windows-ориентированная платформа для разработки ПО - .NET Framework. Она развивалась в плоть до 2019 года, когда была выпущена последняя версия - 4.8

  • Параллельно, с 2016 года начала развиваться новая модульная платформа для разработки программного обеспечения с открытым исходным кодом - .NET Core. Кроме того, она была кроссплатформенная.

  • И наконец - .NET 5. Это, выпущенная в 2020 году, единая платформа для разработки ПО. Она объединила в себе все преимущества .NET Framework, .NET Core и некоторых похожих платформ.

По заявлениям Microsoft, теперь это единственная платформа, в сторону которой будет развиваться компания.

Планы на развитие и поддержку платформы .NETПланы на развитие и поддержку платформы .NET

И теперь, имея единую программную платформу - .NET 5, компания Microsoft может воплотить идею с использованием унифицированного интерфейса, но при этом оставить возможность использовать удобные API: будь-то UWP API или Win32.

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

Перспективы WinUI 3

По заявлениям самих Microsoft, на WinUI 3 и его последующие версии, у компании огромные планы. Для начала, уже в осеннем обновлении Windows мы сможем увидеть переход многих частей операционной системы на WinUI 3.

Xamarin, MAUI and WinUI 3?

MAUI (Multi-platform App UI) - кроссплатформенная библиотека графического интерфейса. Является эволюцией Xamarin.Forms. Для Windows она будет работать именно через компоненты WinUI 3. Больше информации о MAUI: devblog.microsoft, github.

Uno Platform and WinUI 3?

Uno Platform - это кроссплатформенный графический пользовательский интерфейс с открытым исходным кодом, который позволяет запускать код на основе WinUI и универсальной платформы Windows на iOS, macOS, Linux, Android и WebAssembly.

Команда разработчиков Uno Platform с первых дней анонсировала свою нацеленность на WinUI 3. А спустя 12 часов после выпуска WinUI 3 Preview 4, его поддержка уже была добавлена в Uno Platform. Больше информации об Uno Platform: platform.uno, github.

Будущее системных API

Что касается системных API, Microsoft не оставляют идею их унификации. Поэтому, сейчас в активной разработке находится Project Reunion. Это универсальная модульная оболочка, которая должно предоставить быстрый доступ ко всем Win32 и UWP API.

Project Reunion будет очень тесно связан с WinUI 3. И уже сейчас находится в превью версии.

Больше информации о Project Reunion: docs.microsoft.com, github

Подробнее..

Xamarin.Forms 5.0 уже здесь, уже доступен

12.01.2021 10:14:24 | Автор: admin
Сегодня мы публикуем финальный стабильный выпуск Xamarin.Forms версии 5.0. Этот основной выпуск содержит сотни улучшений качества и включает новые функции, включая темы приложений, кисти, CarouselView, RadioButton, Shapes and Paths и SwipeView.

Команда Xamarin хотела бы выразить огромное спасибо многим участникам и рецензентам, которые помогли сделать этот выпуск. Вы великолепны!

Под катом немного подробностей и много полезных ссылок, связанных с Xamarin.Forms 5.0.



Обновление до 5.0


Мы обновили все наши примеры и многие из наших собственных проектов с версий Xamarin.Forms, начиная с 3.5, и теперь все гладко. Есть некоторые вещи, которые помогут вам быстро выполнить миграцию. Вот краткий чек-лист для успеха:

  1. Убедитесь, что вы используете Visual Studio 2019. Это минимальная необходимая версия.
  2. UIWebView был удален в соответствии с обновленными рекомендациями Apple. Если вы намеренно не выбрали UIWebView, значит, вы уже используете более новую версию WKWebView, и вам не нужно делать что-либо дополнительно.
  3. Расширения разметки MediaElement, Expander и C# UI были перемещены в библиотеку Xamarin Community Toolkit.
  4. Пакеты DataPages и Theme должны быть удалены из ваших решений. Эти экспериментальные пакеты больше не выпускаются.
  5. (Необязательно) MasterDetailPage и связанные типы были переименованы в FlyoutPage и аналогичные. Это устаревшая версия, и ваши приложения пока будут работать без этого изменения, однако мы рекомендуем выполнить рефакторинг, прежде чем мы перейдем к .NET MAUI.

Ресурсы, документация, примеры и видео


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

Опубликована новая документация по новым функциям и многому другому, что вы можете отслеживать на странице Что нового.


Примеры Xamarin.Forms находятся в процессе публикации с Xamarin.Forms 5.0. Эти проекты нашей команды тоже могут быть вам интересны.


Блоги с превью многих из этих функций можно найти здесь:


Видео




Ознакомьтесь с короткими руководствами, посвященными этим новым функциям, на YouTube.

Кроме того, мы представили большую часть содержимого Xamarin.Forms 5.0 на Xamarin Show и .NET Conf 2020.





Начало работы


Обновите свои проекты до 5.0 с помощью диспетчера пакетов NuGet, очистите, перезапустите VS и перестройте. Дайте нам знать, как все проходит! Если у вас возникнут проблемы, отправьте нам отчет на GitHub.

Xamarin.Forms 5.0 продолжит получать служебные выпуски до ноября 2022 года. .NET MAUI станет следующим крупным выпуском функций с предварительными версиями .NET 6, которые будут доставлены в начале этого года. Приложения Xamarin.Forms 5.0 будут перенесены на .NET 6 и обновлены непосредственно до .NET MAUI. Мы с нетерпением ждем продолжения этой эволюции с вами в 2021 году!
Подробнее..

Перевод Как выбрать мобильную кросс-платформу в 2021 году

25.02.2021 20:10:38 | Автор: admin

Кросс-платформенные решения - тренд в мобильной разработке. Уже есть различные технологии от PWA до Flutter и Kotlin Multiplatform. Как выбрать среди них?

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

Познакомимся с Женей

Евгения солюшн-архитектор. Она должна решить, как построить новое мобильное приложение для изучения английского языка не носителями: людьми из Турции, Италии или России. Давайте посмотрим, как Женя подходит к этой задаче.

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

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

Прогрессивные веб-приложения

Женя начинает свои исследования. Она гуглит мобильные веб-приложения и находит статью. В ней упоминаются Прогрессивные веб-приложения (PWA). Что это такое?

Прогрессивные веб-приложения это, по сути, веб-сайты, которые используют специальные API для доступа к определенным возможностям устройства. Эти API позволяют получить доступ к памяти на устройстве, интегрируются с Push Notifications (на Android) и, что самое важное, работать в отдельной вкладке браузера. Еще их можно установить на устройство иконкой, как настоящее приложение. Звучит неплохо! Давайте посмотрим на плюсы и минусы PWA:

Плюсы:

  • Всем занимается одна команда.

  • Достаточно навыков веб-разработки.

  • Легко обслуживать.

  • Все работает сразу из коробки.

Минусы:

  • Нет пушей на iOS.

  • Неудобный UX.

  • Ограниченная поддержка.

  • Трудно найти пользователи скачивают приложение в сторах.

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

Гибридные приложения

Жене не нравится, что PWA обладают ограниченной поддержкой пушей. Поэтому она гуглит дальше.

Она обнаруживает гибридный подход: давайте поместим наш сайт в WebView в реальном нативном приложении. Оказывается, можно поместить свой мобильный сайт со всем его HTML, CSS и JS-кодом в ресурсы приложения. Затем вы помещаете WebView в корневой ViewController/Activity приложения и указываете на эти ресурсы.

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

Плюсы:

  • Высокая скорость работы.

  • Настоящая кросс-платформенность.

  • Можно пользоваться практически всеми преимуществами нативных приложений.

Минусы:

  • UX не очень (ведь перед нами по-прежнему сайт в шкуре приложения).

  • Небольшое сообщество разработчиков.

Архитектура гибридного приложенияАрхитектура гибридного приложения

Примеры таких приложений: Appcelerator, Ionic, Apache Cordova.

Нативные кросс-платформенные приложения

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

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

Xamarin

Xamarin это решение на основе .NET от Microsoft.

Xamarin (или NET 5.0) помогает кросс-платформенное приложение на C# и .NET в мобильном приложении. Xamarin Forms (или MAUI) это библиотека для построения пользовательского интерфейса в таких приложениях. Теперь они оба переименованы:

Плюсы:

  • Легко разрабатывать в компаниях с сильной экспертизой в технологиях Microsoft.

  • Полностью кросс-платформенное.

  • Потенциально можно сделать его и веб-приложением.

Минусы:

  • 2 виртуальные машины в приложении на Android - JVM и Mono

  • Мало инструментов и библиотек

  • Долгое время исправления багов в Xamarin

  • Растет размер бандлов

React Native

React Native создан для того, чтобы привнести React в мобильные технологии. И это действительно хорошо сработало! Согласно статистике Bitrise, React Native занимает 13% рынка. Его также используют более 500 тысяч репозиториев на Гитхабе.

React Native использует языки Javascript или TypeScript для разработки приложений и транслирует компоненты React Native в компоненты платформы. Так, превращается в TextView на Android.

Приложение включает в себя JavaScript VM для выполнения JS-кода логики и пользовательского интерфейса приложения. React Native также умеет работать с API платформы. С такой архитектурой можно создать любое приложение, даже мобильную игру.

Плюсы:

  • Большое сообщество.

  • Пользуются в Skype, Discord, Shopify, Tesla, Artsy.

  • Доступны нативные возможности приложений.

  • Можно писать на React.

Минусы:

  • Долгое время запуска.

  • Экстеншены и работа в фоне требует написания нативного кода.

  • Проходит ре-архитектуризацию.

Flutter

Flutter это кросс-платформенный фреймворк с открытым исходным кодом от Google, основанный на языке Dart. В отличие от React Native, Flutter использует свой собственный 2D-движок для отрисовки пользовательского интерфейса в нативном виде. Такой подход обеспечивает независимость от версии ОС, на которой работает приложение. Flutter приложение также компилирует Dart в нативный для платформы код в релизной сборке, таким образом в рантайме Dart VM становится не нужна. Советую нашей Жене мое подробное сравнение Flutter и React Native.

Flutter привлек к себе большое внимание, собрал более 100 000 звезд, а количество приложений, собранных с его помощью, продолжает стремительно расти. Согласно той же статистике Bitrise, уже 9% билдов в прошлом году собраны на Flutter. Это очень много для такой молодой технологии.

Плюсы:

  • Хорошая производительность

  • Декларативный UI

  • Поддерживает веб

Минусы:

  • Ненативный UI

  • Малопопулярный язык Dart.

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

Kotlin Multiplatform

Xamarin, Flutter и React Native позволяют вам написать практически весь код единожды и запускать его и на iOS, и на Android.

Kotlin Multiplatform делает иначе. KMP считает, что пользовательский интерфейс сильно зависит от платформы и самого устройства (скажем, планшета или веб-сайта). Однако бизнес-логика остается практически неизменной. Почему бы не переиспользовать прежде всего ее?

Итак, с KMP у вас все еще есть два нативных приложения, которые пользуются одной бизнес-логикой. Вы можете использовать все, что угодно в пользовательском интерфейсе: будь то родной Android Views, JetPack Compose или Swift UI для iOS. Вы даже можете использовать Flutter или React Native для вашего пользовательского интерфейса! Он все равно будет прекрасно работать с Kotlin Multiplatform. Вот несколько примеров.

Плюсы:

  • Родной язык для разработчиков Android.

  • iOS разработчикам нетрудно читать Kotlin код.

  • Единая среда разработки для Android и iOS.

  • Подходит для реализации веб-приложений.

Минусы:

  • Молодое решение, все еще в альфа-версии.

  • Нельзя переиспользовать UI.

Что же выбрать?

Итак, наша Женя собирается выбрать свое решение. Вот что мы ей посоветуем:

  • Согласна на мобильный сайт вместо приложения, несмотря на ограничения в UI? Тогда PWA.

  • В компании все пишут на .NET? Значит, Xamarin.

  • Основной стек это JS/TypeScript? Выбираем React Native.

  • Будем шарить между приложениями не UI, а только бизнес-логику? Значит, Kotlin Multiplatform.

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

Удачи, Женя!

Подробнее..

Создание прекрасных приложений с помощью Xamarin.Forms

09.06.2021 10:16:43 | Автор: admin

Есть вопрос, который мне постоянно задают в Твиттере: как создавать приложения с крутым дизайном с помощью Xamarin.Forms? Это отличный вопрос, ведь любой может создавать красивые приложения, немного вдохновившись и поработав над стилем. Я не дизайнер и не претендую на звание дизайнера, но есть много отличных источников вдохновения для дизайна приложений, включая Dribbble, Uplabs и другие. Эти дизайны от талантливых людей со всего мира могут повлиять на внешний вид ваших собственных приложений.

Приложение для ресторана от Oludayo AlliПриложение для ресторана от Oludayo Alli

Встроенные возможности Xamarin.Forms

В Xamarin.Forms есть несколько функций, которые можно использовать, чтобы воплотить важные проекты в жизнь. Зачем вам что-то, кроме нового Shapes API для рисования фигур, линий, многоугольников и многого другого. Хотите, чтобы ваши собственные элементы управления были единообразными? Как насчет добавления Material Design с помощью одной строчки кода. А еще сгруппируйте свои коллекции с помощью CarouselView в сочетании с IndicatorView и, конечно же, CollectionView.

Приложение "Галерея напитков" от Javier SurezПриложение "Галерея напитков" от Javier Surez

Пойдите дальше с кастомными элементами управления от сообщества

Xamarin Community Toolkit добавляет отличные элементы управления, включая DockLayout, Shield, TabView и другие. Но есть еще более потрясающие элементы управления от сообщества, включая потрясающие Magic Gradients, PancakeView, MaterialFrame, CardView, Shadows и многие другие. Наконец, мы не можем забыть SkiaSharp, систему 2D-графики общего назначения для .NET.

Компонентная экосистема

Переиспользуемые компоненты пользовательского интерфейса от ведущих поставщиков компонентов, таких как Telerik, UX Divers, GrapeCity и Syncfusion, помогут вам быстро повысить продуктивность. Обязательно ознакомьтесь с множеством вариантов, когда будете готовы начать работу.

Вдохновляйтесь

Наш коллега Хавьер уже несколько лет собирает интересные примеры крутых приложений с открытым исходным кодом, созданных с помощью Xamarin.Forms, которые вы можете изучить на GitHub. Выше вы уже видели несколько из этих приложений, но вот еще, чтобы вас вдохновить.

Кошелек карт от Altevir Кошелек карт от Altevir Приложение для авиаперелетов от Leomaris ReyesПриложение для авиаперелетов от Leomaris ReyesКнига рецептов от Steven ThewissenКнига рецептов от Steven ThewissenCake app от Shaw YuCake app от Shaw Yu

И есть еще очень много прекрасных дизайнов. Вы даже можете добавить свой собственный, просто создав pull request в репозитории Хавьера на GitHub.

Adobe XD Exporter

Многие дизайны, которые вы найдете в интернете или получите от вашего дизайнера, могут быть созданы с помощью таких инструментов, как Adobe XD. Вы можете легко импортировать цвета и стили в свое приложение Xamarin.Forms благодаря экспортеру XD в Xamarin.Forms (его автор -- наш коллега Kym Phillpotts).

Создавайте красивые приложения

Расскажите нам о своих приложениях, оставив комментарии ниже или отправив pull request в репозиторий Хавьера на GitHub.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru