Перенос и обновление старых проектов Xamarin Native MvvmCross
6 шагов, предпринятых для выполнения миграции, и некоторый ретроспективный анализ
Xamarin Native был чрезвычайно популярен как кроссплатформенное решение, а MVVMC - самый популярный фреймворк, используемый с ним, в первую очередь благодаря его надежности и надежным возможностям. К счастью, Xamarin Native и MVVMCross часто получают обновления, но большинство компаний не обновляют регулярно свои приложения или платформы приложений, потому что в этом нет необходимости. По-прежнему существует масса приложений, написанных с использованием Xamarin Native и MVVMCross, как видно из пакета MvvmCross nuget, который по-прежнему получает ~ 1,5 тыс. Загрузок в день. Так что я надеюсь, что это руководство для всех, кто хочет перейти на новейшие фреймворки! Обязательно ознакомьтесь с этой статьей, прежде чем решать, нужно ли выполнять миграцию приложения.
Для людей, которые не используют MvvmCross, но пытаются перейти на AndroidX, вы можете перейти к шагу 5, и это может быть полезно. И если вы хотите изучить Xamarin Native, чтобы быть сверхпривлекательными для 10% опубликованных приложений Xamarin, которые все еще используют Xamarin Native (специальность первого прототипа), вы можете взглянуть на это мини-руководство.
Рассказ о трех миграциях
Перенесенное нами решение Xamarin было создано в 2017 году, поэтому оно использовало PCL вместо .NET Standard для двух основных проектов - одного для служб, а другого для ViewModels. Большинство зависимостей решения больше не поддерживают PCL в последних версиях и требуют .NET Standard 2.0. Таким образом, помимо обновления инфраструктуры MVVMCross с 4.4 до 7.1.2, мы также внесем это изменение. У нас был выбор остановиться на этом, но я принял вызов и решил также перейти на новейшие библиотеки AndroidX.
Методология: я сделал быстрый всплеск, чтобы увидеть, смогу ли я просто отключить все, используя только существующее решение, но у меня было слишком много проблем, было слишком много изменений, и в конце концов я достиг контрольно-пропускной пункт. Так что казалось более разумным начать со свежего решения .NET Standard Xamarin Native и добавлять к нему по одному проекту за раз. Я решил начать с основных проектов (ViewModels & Services), затем с iOS, а затем с Android (поскольку Android также требует миграции AndroidX).
Инструменты: я начал использовать Visual Studio, но Jetbrains Rider лучше подходит для миграции, потому что он вычисляет общее количество ошибок сборки и обновляет его на лету, без необходимости каждый раз нажимать кнопку восстановления. Как ни странно, когда у меня было ›15000 ошибок сборки, Visual Studio показывала только ~ 50. Также в Rider одним щелчком мыши вы можете волшебным образом добавить недостающее использование во все файлы вашего проекта и сэкономить массу времени.
Контроль версий: я создал для этого новый репозиторий, так как знал, что это займет у меня несколько дней, и я хочу иметь возможность сохранять свою работу по ходу. Я бы зафиксировал и продвинул проект только после того, как смогу построить. После внесения всех изменений я удалил все старые файлы из старого репозитория и вставил на его место новый код.
Шаг 1 - базовый проект MVVMCross Xamarin Native
- Создайте новое решение, используя пустой шаблон Xamarin Native. Убедитесь, что у него точно такое же имя.
- Переименуйте проект Core в свое старое имя проекта, так что
.ViewModels
в моем случае. Обновите файлыSLN
иCSPROJ
, чтобы они также указывали на переименованный проектViewModels
. - Перейдите к параметрам проекта
ViewModels
и обновите параметры проекта - ›Target Framework до.NetStandard2.0
. (Переход на .NETStandard2.1 дал мне некоторые проблемы с зависимостями).
Примечание. Поскольку вы переходите с PCL на .NETStandard, вам не нужныproject.json
,app.config
,AssemblyInfo.cs
файлы, аCSProj
может просто автоматически включать все в папки без необходимости указывать каждый файл. - Добавьте последнюю версию MvvmCross (7.1.2) и убедитесь, что вы можете собрать iOS и Android с изменениями, запрошенными MvvmCross, для ViewModel и проектов пользовательского интерфейса. Я внес изменения из репозитория MvvmCross TipCalc и убедился, что приложение работает на обеих платформах (iOS и Android).
Шаг 2 - Перенос основных моделей представлений и проектов служб
- Щелкните правой кнопкой мыши решение ViewModel и выберите «Добавить› файлы из папки »и добавьте все элементы из каталога ViewModels старого решения, используя существующую структуру папок.
- Добавьте необходимые пакеты Nuget, такие как настройки ACR, AppCenter, MvvmCross, MvvmCross Plugins-Email / Messenger / Phone / WebBrowser, MvvmValidation, Plugin MediaManager, Newtonsoft.Json, Xamarin essentials. Xamarin Essentials может предотвратить потребность в некоторых других плагинах, таких как Connectivity и DeviceInfo.
- Добавьте второй Core project-Services (при необходимости) и убедитесь, что у него правильное имя, Target framework, и убедитесь, что проект ViewModel использует его в качестве ссылки.
- В проект Services добавьте необходимые пакеты Nuget (настройки ACR, AppCenter, MvvmCross, MvvmCross Messenger, Newtonsoft.Json)
- Не забудьте перейти с PCL на .NETStandard 2.0. Опять же, вам не понадобятся файлы project.json, app.config, AssemblyInfo.cs, и CSProj может просто автоматически включать все в папки без необходимости указывать каждый файл. Таким образом, вы можете просто щелкнуть правой кнопкой мыши и «Добавить› файлы из папки », чтобы добавить все оставшиеся файлы из старого каталога Services.
- Если где-либо используется старый `Plugin.Connectivity`, вы можете преобразовать
CrossConnectivity.Current.IsConnected
вXamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.Internet
- Замените
using MvvmCross.Platform
толькоusing MvvmCross
- Заменить
using MvvmCross.Binding.ExtensionMethods
наusing MvvmCross.Binding.Extensions
- Заменить
using MvvmCross.Plugins.Messenger
наusing MvvmCross.Plugin.Messenger
- Заменить
Settings.Current.x
наCrossSettings.Current.x
- При необходимости замените
using MvvmCross.Core.ViewModels
наusing MvvmCross.Commands
илиusing MvvmCross.ViewModels
.
Шаг 3 - Некоторые конкретные ошибки основного проекта:
- Скорее всего у вас будут ошибки в Навигации из-за отсутствия некоторых функций (Close, ShowViewModel) для начала использования Navigator.Close и Navigator.Navigate
- Способ передачи данных в модель представления изменился из-за отсутствия использования «MvxBundle», чтобы вместо этого начать использовать параметры, которые требуют переопределения функции жизненного цикла подготовки.
- Всем IMvxCommands и MvxCommands потребуется
using MvvmCross.Commands
в файле или просто добавьтеMvvmCross.Commands.
перед каждым упоминанием. Функциональность Rider по добавлению всех необходимых операторов using может решить эту проблему наилучшим образом. - В одной из моих ошибок говорилось, что мне нужно добавить CSharp DLL, поэтому я добавил C # nuget, и он устранил ошибку.
- Любые страницы, использующие медиа, - это намного больше работы, потому что события изменились, а некоторые свойства недоступны. Все суффиксы статуса изменились на State. Я оставил кое-что из этого, чтобы исправить после того, как закончу с остальной частью миграции, чтобы я мог работать над этим, пока команда QA тестировала оставшуюся работу.
Mvx.Trace
перестало работать, поэтому я просто перешел наDebug.WriteLine
. А во всем остальном, в чем я не был уверен, я бы прокомментировал код вместе с комментарием//TODO: Fix later
.- Выполнив все 5000+ ошибок и вы сможете создать основной проект, вы еще не сможете строить на iOS, потому что вам нужно будет добавить туда пакеты Nuget (настройки ACR, AppCenter, MvvmCross, MvvmCross Plugins-Email / Messenger / Phone / WebBrowser, Newtonsoft Json, MvvmValidation, Plugin Mediamanager, Xamarin Essentials).
- Исправление некоторых ViewModels также может занять больше времени в зависимости от того, как информация была передана, когда мы перешли на страницу.
Шаг 4 - изменение проекта iOS:
- Взял старые файлы напрямую из старых, используя «Добавить файлы из папки», аналогично шагу, упомянутому выше.
- Заменить
using MvvmCross.Binding.iOS.Views
наusing MvvmCross.Platforms.Ios.Binding.Views
- При необходимости замените
using MvvmCross.Core.ViewModels
наusing MvvmCross.Commands
илиusing MvvmCross.ViewModels
. - Заменить
using MvvmCross.iOS.Support.Views
наusing MvvmCross.Platforms.Ios.Views
- Заменить
using MvvmCross.Platform.Converters
наusing MvvmCross.Converters
- Заменить
using MvvmCross.Binding.ExtensionMethods
наusing MvvmCross.Binding.Extensions
` - Удалено
using MvvmCross.Platform.Core
и добавлены недостающие использования с помощью Rider:MvvmCross.Binding.BindingContext
для IMvxBindingContext,MvvmCross.ViewModels
для IMvxInteraction иMvvmCross.Base
для MvxValueEventArgs и IMvxDataConsumer - Заменить
using MvvmCross.Platform
наusing MvvmCross
- Заменить
using MvvmCross.Core.Navigation
наusing MvvmCross.Navigation
- Удалены файлы Bootstrap, поскольку они больше не нужны, и удалены ссылки на них.
- Обновил тонкий файл
AppDelegate
для работы с обновленнымAppStart
. Также обновил файлSetup.cs
по мере необходимости - Обновлен DebugTrace.cs для наследования от IMvxLog вместо IMvxTrace и исправлен.
- Поскольку мы нигде не используем старую
Plugin.Connectivity
, конвертируемCrossConnectivity.Current.IsConnected
вXamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.Internet
- К счастью, никаких изменений в проигрывателе мультимедиа со стороны пользовательского интерфейса iOS не потребовалось, за исключением операторов using.
- Если вы используете настраиваемый презентатор представлений iOS (использующий класс, унаследованный от
MvxIosViewPresenter
), вы можете столкнуться с трудностями. Особенно, если вы используете `view` из этого переопределения:Show(IMvxIosView view, MvxViewModelRequest request)
, потому что это переопределение больше не доступно. У вас есть доступ только кShow(MvxViewModelRequest request)
. Я смог использовать это новое переопределение вместоCreateOverridePresentationAttributeViewInstance(Type viewType)
, просто сказавvar view = base.CreateOverridePresentationAttributeViewInstance(viewType);
для обновления атрибутов в UIViewController - У вас также могут возникнуть проблемы с расширением заголовка раздела с TableSources, унаследованными от MvxExpandableTableViewSource. После отладки я понял, что MvvmCross автоматически добавляет скрытую кнопку, которая знает, что нужно нажать, чтобы развернуть. Я заметил, что этот класс использовал контейнер UIView для размещения внутри него ярлыков и изображений. После снятия контейнера он снова заработал.
- Некоторые из ваших TableViewSources могут использовать вариант
ItemsSource.ElementAt(i).IsExpanded = false;
, который больше не доступен. Вы можете исправить это, используя вместо этогоvar group = (ItemsSource as IList)[i] as DocumentListGroup; if (group != null) group.IsExpanded = false;
Шаг 5 - Обновление MvvmCross и Android- ›AndroidX
- Взял файлы, используя ту же структуру файлов и папок, используя «Добавить файлы из папки». Затем просто добавьте отсутствующие операторы using, и у вас возникнут некоторые из проблем, которые мы видели на шагах выше для iOS.
- Замените `MvvmCross.Binding.Droid.Target;` на `using AndroidX.AppCompat.Widget`
- Замените
using Android.App
иusing Android.Widget
наusing AndroidX.AppCompat.Widget
. Но для атрибута[Activity
вы можете преобразовать его в[Android.App.Activity
- Замените
using MvvmCross.Droid.Support.V7.AppCompat
наMvvmCross.Platforms.Android.Views.AppCompat
- Заменить
using MvvmCross.Droid.Views
наusing MvvmCross.Views
- Заменить
Android.Support.V4.Content.Res
наusing AndroidX.Core.Content.Resources
- Замените
Application.Context.x
наCrossCurrentActivity.Current.AppContext.x
, используя Plugin.CurrentActivity в нескольких местах - Заменить
using Toolbar = Android.Support.V7.Widget.Toolbar
наusing Toolbar = AndroidX.AppCompat.Widget.Toolbar
- При необходимости замените
using Android.Support.V4.Widget
иusing Android.Support.V4.View
наusing AndroidX.Core.View
,using AndroidX.DrawerLayout.Widget
илиusing MvvmCross.Platforms.Android.Views
- При необходимости замените
using MvvmCross.Core.ViewModels
наusing MvvmCross.Commands
илиusing MvvmCross.ViewModels
. - Заменить
using MvvmCross.Platform.Converters
наusing MvvmCross.Converters
- Заменить
using MvvmCross.Binding.ExtensionMethods
наusing MvvmCross.Binding.Extensions
- Удален
using MvvmCross.Platform.Core
и добавленusing MvvmCross.Binding.BindingContext
для IMvxBindingContext,using MvvmCross.ViewModels
для IMvxInteraction иusing MvvmCross.Base
для MvxValueEventArgs и IMvxDataConsumer - Замените
using MvvmCross.Platform
наusing MvvmCross
для Mvx.Resolve - Заменить
using MvvmCross.Core.Navigation
наusing MvvmCross.Navigation
- Заменить
using Plugin.MediaManager.ExoPlayer
&using Plugin.MediaManager
наusing MediaManager
- Заменить
using MvvmCross.Binding.Droid.BindingContext
наusing MvvmCross.Platforms.Android.Binding.BindingContext
- Заменить
using MvvmCross.Binding.Droid.Views
наusing MvvmCross.Platforms.Android.Binding.Views
- Замените
using MvvmCross.Droid.Support.V7.RecyclerView
наusing MvvmCross.DroidX.RecyclerView
, для которого необходимо установить nuget MvvmCross.DroidX.RecyclerView. - Заменить
using MvvmCross.Droid.Views.Attributes
наusing MvvmCross.Platforms.Android.Presenters.Attributes
- Замените
using MvvmCross.Droid.Support.V4
наusing MvvmCross.Platforms.Android.Views.Fragments
для фрагментов или иногда наusing MvvmCross.DroidX
- Большинство моих действий требовало добавления
using AndroidX.Lifecycle
- Мне также нужно было добавить
using Google.Android.Material.BottomSheet
иusing Google.Android.Material.Snackbar
в некоторые классы - По своему личному выбору я преобразовал
MvxAppCompatSpinner
вMvxSpinner
, и этот макет также нуждался в исправлении. - Страницы с вкладками могут быть немного сложными. Вам необходимо обновить
MvxViewPagerFragmentInfo
, поскольку теперь для него требуется передачаMvxViewModelRequest
, а не толькоViewModel
. Передача параметров теперь немного отличается. Я как бы застрял там, глядя на документы. Я нашел пример и ответ на переполнение стека, но это не сильно помогло. Благодаря подсказке MvvmCross Tomasz я обнаружил, чтоMvxViewModelInstanceRequest
- это типMvxViewModelRequest
, который позволит вам передать экземпляр ViewModel, что упрощает процесс. - Некоторые страницы с вкладками могут по-прежнему сломаться, что может вызвать сбой
System.Reflection.AmbiguousMatchFound
исключения, а поиск источника сбоя может быть затруднен - Удалены файлы Bootstrap, поскольку они больше не нужны, и удалены ссылки на них.
- Преобразование стартапа в новый стиль
- Преобразование журнала в debugtrace
- Поскольку мы везде используем более старый Plugin.Connectivity, конвертируем CrossConnectivity.Current.IsConnected в Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.Internet.
- Изменено более 70 файлов фрагментов, действий и макетов, но я давно перестал считать. Обновлен пользовательский клиент WebView.
- Со стороны пользовательского интерфейса Android потребовалось внести несколько изменений в аудиоплеер.
- Обновите все диалоговые окна, включая AlertDialog, которые потребовали некоторой работы из-за изменений AndroidX. Вместо этого преобразуйте классы, которые наследуются от
DialogFragment
, чтобы они начали наследовать отMvxDialog
. Теперьdialog.Show()
потребуетсяSupportFragmentManager
. Этот шаг может вызвать у вас несколько неприятных проблем. Для ваших диалогов, если вы используете EnsureBindingContextSet (savedState), вы можете использовать это вместо this.EnsureBindingContextIsSet ();
Шаг 6 - XML-файлы макета и меню для Android, отличные от Csharp
android.support.v4.widget.DrawerLayout
toandroidx.drawerlayout.widget.DrawerLayout
android.support.v4.view.ViewPager
toandroidx.viewpager.widget.ViewPager
android.support.v4.widget.NestedScrollView
toandroidx.core.widget.NestedScrollView
MvvmCross.Droid.Support.V4.MvxSwipeRefreshLayout
toMvvmCross.DroidX.MvxSwipeRefreshLayout
MvvmCross.Droid.Support.V7.RecyclerView.MvxRecyclerView
toMvvmCross.DroidX.RecyclerView.MvxRecyclerView
android.support.v7.widget.AppCompatButton
toandroidx.appcompat.widget.AppCompatButton
android.support.v7.widget.SwitchCompat
toandroidx.appcompat.widget.SwitchCompat
android.support.v7.widget.SearchView
toSearchView
android.support.v7.widget.Toolbar
toandroidx.appcompat.widget.Toolbar
android.support.v7.widget.CardView
toandroidx.cardview.widget.CardView
android.support.design.widget.CoordinatorLayout
toandroidx.coordinatorlayout.widget.CoordinatorLayout
android.support.design.widget.AppBarLayout
tocom.google.android.material.appbar.AppBarLayout
android.support.design.widget.TextInputLayout
tocom.google.android.material.textfield.TextInputLayout
android.support.design.widget.TextInputEditText
tocom.google.android.material.textfield.TextInputEditText
android.support.design.widget.TabLayout
tocom.google.android.material.tabs.TabLayout
android.support.design.widget.FloatingActionButton
tocom.google.android.material.floatingactionbutton.FloatingActionButton
android.support.design.widget.NavigationView
tocom.google.android.material.navigation.NavigationView
- layout_behavior = от
android.support.design.widget.BottomSheetBehavior
доcom.google.android.material.bottomsheet.BottomSheetBehavior
- Убедитесь, что вы нацелены на последнюю версию фреймворка и можете правильно скачивать и выгружать файлы. Вы можете временно исправить проблемы, включив разрешения на хранилище устаревших приложений при ориентации на платформу Android 10. Обновить его до новых API не так уж сложно.
- Странно то, что если вы используете
MvxFrameControl
, у вас могут быть проблемы. Вы должны переключить его сMvvmCross.Binding.Droid.Views.MvxFrameControl
наMvvmCross.Platforms.Android.Binding.Views.MvxFrameControl
- В любом меню, если вы используете actionViewClass = «_ 164_», измените это значение на
androidx.appcompat.widget.SearchView
. - Это было не так уж и сложно, мне пришлось поискать в Google. Как вариант, вы также можете взглянуть на это небольшое руководство.
Были и другие проблемы, которые я, возможно, не задокументировал в процессе, но я надеюсь, что это даст вам и вашей команде хорошую отправную точку для понимания работы и сложности, связанной с процессом миграции. Как всегда, не стесняйтесь обращаться ко мне, если у вас есть какие-либо вопросы. Не забывайте обращаться к руководствам по миграции, предоставленным MvvmCross и StackOverflow для любых препятствий.