|
|
|||||||||||||||||||||||||||||
|
Миграция приложения с Windows 8 на Windows 8.1Источник: habrahabr kichik
Миграция приложений на новую версию операционной системы - это всегда непростой вопрос. Ключевое значение имеет нахождение правильного баланса между внедрением новой функциональности, поддержкой кода и наличием целевой аудитории.
Все эти параметры индивидуальны для каждого проекта, и в определенном смысле зависят друг от друга.
На картинке выше приведены эти две условные стратегии - обе в предположении, что у вас уже есть какое-то приложение под Windows 8. Во многих случаях правильной будет верхняя стратегия: заморозить версию под Windows 8 - и начать развивать версию под Windows 8.1. Хотя, безусловно, могут быть сценарии, когда экономически выгоднее отложить заморозку на более поздний период. Тут надо оценивать, сколько пользователей вы успеете поймать за время миграции (график весьма условный):
Очевидно, что рано или поздно большинство пользователей перейдет с Windows 8 на Windows 8.1, но конкретная скорость перехода может зависеть от множества параметров: от доступности интернета в регионе до it-политик внутри организации. Соответственно, например, с точки зрения монетизации, вам нужно задаться вопросом: каков объем рынка внутри именно Windows 8 (без обновления), учитывая уменьшающуюся динамику. И еще: в зависимости от конкретной функциональности приложения, возможно, вам с лихвой хватает возможностей Windows 8…
Что важно учитыватьВ разрезе перехода от Windows 8 к Windows 8.1 нужно учитывать также следующие "нюансы":
Как мигрировать приложениеПрежде всего, для миграции вам понадобятся Windows 8.1 и Visual Studio 2013. Как только вы запустите свой проект для Windows 8 в новой студии, вам будет автоматически предложено обновить приложение под Windows 8.1:
Здесь же вам предложат почитать про новые возможности в Windows 8.1 и узнать о тонкостях миграции кода. Рекомендую обратить внимание на то, что часть API помечена как устаревшая и может перестать работать. Чтобы "ручками" перенацелить проекты вашего решения под Windows 8.1, достаточно выбрать соответствующий пункт в контекстном меню каждого из проектов:
После осуществления этой процедуры рекомендую попробовать собрать проект и убедиться, что все работает. Также стоит отметить, что по факту автоматически обновляются только файлы проектов и манифест приложения.
ПроизводительностьДля любопытствующих советую также провести эксперимент с тем, как приложение работает до и после перенацеливания. Для этого в VS2013 можно забраться в отладку и найти там пункт "Performance and Diagnostics", после чего можно выбрать подходящий тест:
Например, давайте сравним отзывчивость XAML-интерфейса. В качестве подопытного кролика я буду использовать приложение "Изучаем Windows 8". Результаты Windows 8 приложения на Windows 8.1:
Здесь значительно время вначале занимает как парсинг appx.xaml, так и собственно обработка страниц приложения. А вот результаты этого же приложения после перенацеливания на Windows 8.1 (и без изменения кода) в том же масштабе:
(На паузу между страницами можно не обращать внимания, кроме того, что небольшой всплеск в середине - это прокрутка GridView.) Неплохое улучшение, не правда ли?
Отображение приложения на экранеПриложения на Windows 8 могли работать в трех режимах: Fill, Full и Snapped.
В Windows 8.1 у приложений (точнее у пользователя) появилось намного больше гибкости в расположении на экране - и они могут занимать любую ширину вплоть до 500px (по умолчанию) или 320 (опционально). Однако, если приложение было собрано под Windows 8, при недостатке места оно будет отображаться в Snapped View с серыми полосками по бокам (режим совместимости):
Как только вы перенацелите приложение под Windows 8.1, оно сразу же начнет использовать общий (Full) вид отображения на ширине вплоть до 500px:
В этом месте вам стоит задуматься над тем, как ваше приложение ведет себя в таком достаточно узком пространстве! Обратите внимание, что оно должно оставаться полностью функциональным. Шаг назад: что стало с нашим Snapped View? По умолчанию после миграции (и для новых проектов) для приложений выставляется минимальная поддерживаемая ширина в 500px. Вы можете в манифесте указать, что ваше приложение хорошо справляется и с 320px:
В этом случае в промежутке от 320 до 500px ваше приложение будет переключаться в то, что раньше называлось Snapped view:
Здесь вам надо еще раз задуматься, перечитать инструкцию по миграции и понять, что у вас в проекте теперь оказался устаревший (deprecated) код. Пока что он работает, но может и сломаться - вам явно стоит его поменять/обновить. Например, в нашем проекте все страницы базируются на классе LayoutAwarePage, который входил раньше в стандартный шаблон. В нем вы можете найти такой код: public virtual void InvalidateVisualState() { if (_layoutAwareControls != null) { string visualState = DetermineVisualState(ApplicationView.Value); /* Это нужно обновить */ foreach (Control layoutAwareControl in _layoutAwareControls) { VisualStateManager.GoToState(layoutAwareControl, visualState, false); } } }
Строчка с извлечением состояния из ApplicationView теперь устарела - внутри DetermineVisualState из поля Value бралось строковое значение. В Windows 8.1 вам нужно переключать состояние в зависимости от доступной ширины приложения: protected virtual string DetermineVisualState() { var windowWidth = Window.Current.Bounds.Width; var windowHeight = Window.Current.Bounds.Height; string viewState; if (windowWidth < 500) { viewState = "Snapped"; } else if (windowWidth < windowHeight) { viewState = "FullScreenPortrait"; } else { viewState = "FullScreenLandscape"; } return viewState; } Здесь я убрал параметры у функции DetermineVisualState, а внутри нее пришлось добавить явный выбор состояния в зависимости от ширины и высоты окна. Кстати, так как обе функции виртуальные, возможно, где-то внутри вашего проекта, вы также дополнительно обновляли логику переключения режимов. Наверное, стоит воспользоваться поиском… либо прекрасной возможность VS2013 посмотреть, где еще в проекте используется конкретный метод:
Тестируем, убеждаемся, что все работает.
ПоискСледующий важный пункт нашей программы миграции - поиск. В Windows 8.1 мы учли две вещи:
Поэтому у нас есть теперь красивый поиск "powered by Bing", сочетающий поиск по файлам, вебу, магазину и приложениям:
… и рекомендация внедрять поиск внутрь приложения с использованием SearchBox. Возможно, вы как и мы, обновляя приложения, волнуетесь, что же стало с контрактом Поиска? Он по-прежнему присутствует и работает для вашего приложения, когда оно запущено:
Однако, как вы можете заметить на скриншоте выше, по умолчанию ищет везде, а не в вашем конкретном приложении. Из выпадающего списка можно переключиться на приложение:
Чтобы переключение происходило сразу автоматически, необходимо, чтобы контракт поиска, точнее SearchPane активировалась непосредственно из приложения. Для этого нужно приложить совсем немного усилий: добавить кнопку поиска и повесить на нее событие. Для удобства рекомендую сразу оборачивать кнопку в UserControl, так как вам нужно будет вставить ее практически на все страницы вашего приложения. Наша кнопка выглядит как значок поиска в кружочке:
Это обычная кнопка (Button) с нужным символом внутри (), правильным шрифтом (Segoe UI Symbol) и подобранными стилями. <UserControl x:Class="EventsApp.UserControls.SearchButton" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:EventsApp.UserControls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"> <Grid> <Button x:Name="searchButton" Content="searchIconCodeHere" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontFamily="Segoe UI Symbol" Margin="0" FontSize="24" Tapped="searchButton_Tapped" FontWeight="Normal"> ... </Button> </Grid> </UserControl>
По нажатию на кнопку срабатывает соответствующее событие: private void searchButton_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) { Windows.ApplicationModel.Search.SearchPane.GetForCurrentView().Show(); }
Осталось вставить кнопку на страницы приложения. Теперь при активации поиска из приложения SearchPane показывается с правильными настройками.
Кстати, рекомендую добавить такую кнопку даже для приложений, собранных под Windows 8 -> она продолжить правильно работать у пользователей под Windows 8.1, если вы им не предоставляете отдельную сборку.
SearchBoxЕстественно, вы можете сделать поиск еще ближе к пользователю. Для этого в приложение можно добавить элемент управления SearchBox, который будет позволять искать сразу внутри приложения, не переключаясь на дополнительную панель. Надо отметить, что API работы с SearchBox очень похоже на таковое для работы с SearchPane. Также, как и в случае с кнопкой для вызова панели поиска, проще всего будет, если вы обернете SearchBox внутрь собственного UserControl - в этом случае вы сможете легко интегрировать в него всю логику, а на страницы вставлять только элемент управления. <UserControl x:Class="EventsApp.UserControls.LearnSearchBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:EventsApp.UserControls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" > <Grid> <SearchBox x:Name="searchBox" Width="300" Height="48" QuerySubmitted="searchBox_QuerySubmitted" /> </Grid> </UserControl>
И далее в коде: private void searchBox_QuerySubmitted(SearchBox sender, SearchBoxQuerySubmittedEventArgs args) { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(SearchPage), args.QueryText); } Кстати, этот код почти никак не отличается от того, который используется при отправке запроса в SearchPane. Если быть точнее, я его именно оттуда и скопировал. Следующим шагом остается только вставить наш новый элемент управления во всех нужных местах:
Здесь ваш может подстерегать ошибка, в которой сходу трудно разобраться (особенно, если не читать документацию):
Все дело в том, что вы не можете одновременно использовать SearchPane и SearchBox. Вам нужно будет выбрать что-то одно. В моем случае я комментирую все строчки обращения к SearchPane. Одной из причин такого конфликта является безусловно дублирование функциональности, еще одной - то, что оба механизма поиска завязаны на один и тот же системный механизм подсказок (управляется в настройках ОС):
Аналогично работе с SearchPane, вы можете добавить свои собственные подсказки. Также вы легко можете добавить активацию поиска по началу набора с клавиатуры на экране: <SearchBox x:Name="searchBox" Width="300" Height="48" QuerySubmitted="searchBox_QuerySubmitted" FocusOnKeyboardInput="True" />
Пример использования можно найти на code.msdn.microsoft.com.
Живые плиткиЕще один момент, которому стоит уделить немного внимания, это живые плитки. В Windows 8 приложение могло реализовывать плитки двух размеров: квадратную 150x150px и широкую 310x150px. В Windows 8.1 к ним добавилось еще два квадратных размера: маленькая 70x70px и большая 310x310px. Чтобы добавить их поддержку в приложение, вам нужно сделать две ключевые манипуляции: 1. Подготовить статичные изображения:
и указать их в манифесте приложения:
Также, как и для Windows 8, при желании вы можете предоставить приложению изображения плиток для разных режимов масштабирования (в зависимости от DPI). 2. Обновить код генерации живых плиток, чтобы он включал новые шаблоны. Остановимся на этом немного более подробно. Как вы, возможно, знаете, для задания живых плиток используются готовые XML-шаблоны, доступные через соответствующие API. В некоторых случаях может быть сподручнее работать с ними как с текстом, особенно, когда нужно обновлять сразу шаблоны для нескольких размеров плиток как в нашем случае. Наше обновление плиток выглядит примерно вот так: public void UpdateImageTile() { var xml = new XmlDocument(); xml.LoadXml( string.Format( @"<?xml version=""1.0"" encoding=""utf-8"" ?> <tile> <visual branding=""none""> <binding template=""TileSquareImage""> <image id=""1"" src=""{0}"" alt=""{1}""/> </binding> <binding template=""TileWidePeekImage03""> <image id=""1"" src=""{0}"" alt=""{1}""/> <text id=""1"">{1}</text> </binding> </visual> </tile>", Entity.Thumbnails.OrderByDescending(x => x.Width).FirstOrDefault().Url, Entity.Title)); TileUpdateManager.CreateTileUpdaterForApplication().Update(new TileNotification(xml)); } В данном случае мы просто показываем на живой плитке превью-картинку одного из докладов. В случае широкой плитки мы используем шаблон с анимацией. Шаблоны для квадратной и широкой плиток собраны в одной строке. Чтобы добавить большую квадратную плитку, нам нужно:
В результате должно получиться примерно так: public void UpdateImageTile() { var xml = new XmlDocument(); xml.LoadXml( string.Format( @"<?xml version=""1.0"" encoding=""utf-8"" ?> <tile> <visual branding=""none"" version=""2""> <binding template=""TileSquare150x150Image"" fallback=""TileSquareImage""> <image id=""1"" src=""{0}"" alt=""{1}""/> </binding> <binding template=""TileWide310x150PeekImage03"" fallback=""TileWidePeekImage03""> <image id=""1"" src=""{0}"" alt=""{1}""/> <text id=""1"">{1}</text> </binding> <binding template=""TileSquare310x310ImageAndText01""> <image id=""1"" src=""{0}"" alt=""{1}""/> <text id=""1"">{1}</text> </binding> </visual> </tile>" , Entity.Thumbnails.OrderByDescending(x => x.Width).FirstOrDefault().Url, Entity.Title)); TileUpdateManager.CreateTileUpdaterForApplication().Update(new TileNotification(xml)); }
Готово! Кстати, в Windows 8.1 вы можете добавить отображение живых плиток также через манифест:
Подводим итоги
Итак, почему стоит обновлять приложение под Windows 8.1? Во-первых, это повышение производительности даже без обновления кода просто за счет того, что многие элементы управления были оптимизированы в Windows 8.1. Во-вторых, это все новые возможности, включая новые размеры плиток, новые элементы управления и новые API. В-третьих, это учет изменений в самой операционной системе: в особенности режимов отображения приложений на экране и поведения поиска. Что нужно сделать для обновления:
Дальнейшие улучшения - на ваше усмотрение. Успешной миграции! Ссылки по теме
|
|