Статьи

APIMASH: портирование на Windows Phone 8

Возможно, вы помните, что в мае мои коллеги-евангелисты и я организовали серию семинаров, посвященных целому ряду начальных наборов API, предназначенных для того, чтобы побудить разработчиков HTML5 / JS и C # создать собственные уникальные приложения для Windows 8. С тех пор мы видели, как некоторые из ваших усилий появились в Магазине Windows, включая « Потому что Чак Сказал Так» и мой собственный Eye on Traffic (использующий API TomTom Traffic Cameras API ).

Потому что Чак Норрис так сказал  Глаз на трафик

Совсем недавно я работал над переносом моего Windows 8 Starter Kit (который использует и Bing Maps, и TomTom API) на Windows Phone, и я решил поделиться своим опытом в этом.

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

Уровень услуг

Из моего обзора архитектуры вы помните, что здесь задействованы две первичные библиотеки классов:

  • APIMASH, который включает в себя соединительный код для выдачи HTTP-запроса, анализа ответа и сериализации полезной нагрузки в требуемые форматы, и
  • APIMASH_APIs, который включает в себя объектные модели и специфичный для API код для получения желаемых данных из API-интерфейсов BEST и TomTom REST

Изменения APIMASH

Для базового уровня APIMASH потребовались два заметных изменения.

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

В классе для десериализации полезных нагрузок HTTP-ответа у меня был метод, который берет двоичный ответ из запроса GET для изображения jpg и превращает его в BitmapImage . В этом отношении между Windows 8 и Windows Phone все обстоит несколько иначе.

Как и следовало ожидать, пространства имен различаются ( Windows.UI.Xaml.Media.Imaging для Windows 8 и System.WIndows.Media.Imaging для Windows Phone), но для создания такого же поведения требуется чуть больше, чем изменение пространства имен. ,

Дело в Windows Phone не представляет особой сложности:

        public static T DeserializeImage(Byte[] objBytes)

        {

            try

            {

                BitmapImage image = new BitmapImage();

                using (var stream = new MemoryStream(objBytes))

                {

                   image.SetSource(stream);

                }

 

                return (T) ((object) image);

            }

            catch (Exception e) { throw e; }

        }

Но я не слишком горжусь, чтобы сказать, что версия Windows 8 заняла у меня некоторое время, чтобы придумать.
Основная проблема заключалась в том, что аргументом
SetSource является
IRandomAccessStream по сравнению с хорошим ole
System.IO.Stream Ниже приведено то, что вы найдете в текущей реализации Windows 8, хотя я подозреваю, что могу немного это исправить, используя
WindowsRuntimeStreamExtensions .

        public static T DeserializeImage(Byte[] objBytes)

        {

            try

            {

                BitmapImage image = new BitmapImage();

 

                // create a new in memory stream and datawriter

                using (var stream = new InMemoryRandomAccessStream())

                {

                    using (DataWriter dw = new DataWriter(stream))

                    {

                        // write the raw bytes and store synchronously

                        dw.WriteBytes(objBytes);

                        dw.StoreAsync().AsTask().Wait();

                        

                        // set the image source

                        stream.Seek(0);

                        image.SetSource(stream);

                    }

                }

 

                return (T) ((object) image);

            }

            catch (Exception e) { throw e; }

        }

HTTPClient

В Windows 8 есть классный класс HttpClient, который обеспечивает очень простой интерфейс, основанный на REST (методы, такие как GetAsync , PostAsync и т. Д.). К сожалению, это не доступно в Windows Phone … ну вроде.

Существует портативный HttpClient, который помогает перенести легкий и просторный класс HttpClient как в Windows Phone, так и в .NET 4, и это, безусловно, кажется самым легким подходом для моих усилий по переносу. Это требует добавления нескольких зависимостей, таких как библиотеки базовых классов , но пакет NuGet делает это действительно простым для включения.

Сначала все, казалось, работало хорошо, за исключением того, что мои изображения с камеры, казалось, не обновлялись по требованию; существующее изображение никогда не обновлялось, но другие изображения с камеры были просто отлично вытянуты. Это привело меня к погоне за обнаружением, что в Windows Phone есть эта полезная функция, называемая кешированием изображений ( читайте об этом здесь ), и какое-то время я был убежден, что это и есть преступник. Не было.

Кэширование действительно было основной причиной, но это было не кэширование изображений, а кэширование веб-ответов . Поскольку каждый запрос на данную камеру выполнялся по одному и тому же URI, а Windows Phone кэшировал результаты, я постоянно видел одно и то же изображение, полученное из кэша.

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

Решение, элегантное в своей REST-полноте, было однострочным, включенным до вызова GetAsync

                httpClient.DefaultRequestHeaders.IfModifiedSince = DateTime.UtcNow;

APIMASH_APIs Изменения

Как вы, возможно, знаете, предпочтительным вариантом сопоставления для Windows Phone является не элемент управления Bing Maps, а тот, который предоставляется Nokia как часть платформы (и доступен на всех устройствах Windows Phone 8). Зная, что я буду переделывать некоторый код пользовательского интерфейса карты (и быть немного ограниченным во времени), я решил полностью удалить слой API Bing Maps.

В приложении Windows 8 API-интерфейс Bing Maps способствовал поисковому опыту, который я очень хотел подчеркнуть, поскольку он является дифференциатором платформы Windows 8, но для версии Windows Phone я решил уменьшить масштаб и отбросить всю реализацию APIMASH_BingMaps.cs. Одной из случайных жертв этого решения (в сочетании с использованием карт Nokia) были два метода, которые больше не служили какой-либо цели для Windows Phone versioh.

Кроме того, изменения в реализации APIMASH_TomTom.cs были невероятно незначительными:

  • Изменения в пространстве имен изображений: System.Windows.Media.Imaging по сравнению с Windows.UI.Xaml.Media.Imaging .
  • Путь к источнику изображения: реализация включает в себя два стандартных изображения «сообщения об ошибке», если что-то пойдет не так при запросе изображения с камеры. В Windows 8 эти ресурсы предоставляются в виде свободного содержимого и доступны через схему URI ms-appx: ///. Для Windows Phone 8 мне нужно было пометить их как Resource при сборке и ссылаться через них через URsI, например /APIMASH_APIs;component/Assets/camera404.png.

    Можно создать реализацию, которая будет использовать потоки ресурсов и работать как в Windows 8, так и в Windows Phone без изменений, но для двух изображений, с которыми я здесь имею дело, это казалось излишним.

  • Путь к ресурсам приложения: для обеих целевых платформ мой код хранит ключ API разработчика для TomTom в качестве статического ресурса в файле App.xaml, но есть некоторая разница в способах ввода ресурсов. В Windows Phone класс ResourceDictionary может быть отключен от любого типа объекта; в Windows 8 ResourceDictionary немного ограничен, чтобы иметь дело именно с KeyValuePair , поэтому существуют семантические различия между методами Contains, и версия класса для Windows RT добавляет новый метод ContainsKey . Честно говоря, объяснение этого заняло больше времени, чем обращение к нему в коде!

Пользовательский опыт

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

Не существует единой формулы для изменения взаимодействия с пользователем для другого форм-фактора, и есть множество больших и малых решений, которые являются частью процесса, многие из которых очень специфичны для вашего приложения. Я скажу, что, несмотря на большой набор функций эмулятора Windows Phone, как только я начал сосредотачиваться на изменениях UX (в отличие от реализации сервисов), я очень быстро перенял рабочий процесс развертывания и отладки прямо с устройства. То, что казалось разумным при взаимодействии с эмулятором с помощью мыши — или даже касания, поскольку у меня ноутбук с сенсорным экраном — казалось неудобным, когда я держал устройство.

Я остановился на следующем UX для телефонной версии Starter Kit, и он, очевидно, не эквивалентен по функциональности версии Windows 8, но я не думаю, что это необходимо. Примечательно, что нет списка всех камер. Но для контекста пользователя Windows Phone (по сравнению с Windows 8) я не думаю, что этот список особенно полезен, и местоположение пользователя в контексте с представлением карты имеет первостепенное значение.

Скриншот Windows Phone Скриншот Windows Phone

Чтобы перейти к этому моменту в своей разработке, я начал с приложения File-> New Windows Phone 8 и поочередно извлек некоторые из существующих ресурсов из приложения Windows 8, включая:

  • Общие классы, такие как BindableBase.cs (без изменений) и несколько классов преобразователей, используемых в XAML. Это требует небольшой настройки, поскольку реализация IValueConverter отличается для двух платформ (в частности, последний параметр обоих методов преобразования).
  • Пользовательские классы контактов карты (CurrentLocationPin.xaml и PointOfInterestPin.xaml). требовалось одно изменение здесь, а именно интерпретация точки привязки (от абсолютных пикселей в случае Windows 8, по шкале относительной 0-1 в Windows Phone). Учитывая, что эти ресурсы используются в двух совершенно разных реализациях карт, я был приятно удивлен!
  • Учитывая изменение карт Nokia с элемента управления Bing Maps, я ожидал много изменений, но, поскольку я абстрагировал большую часть интеграции пользовательского интерфейса карты в класс BingMapsExtensions, изменения не были сложными и очень локализованными. (Я также решил изменить имя класса, так как Bing Maps больше не было на картинке!)

Переработка экранов была в значительной степени переписана с небольшим количеством вырезки и вставки; Вот некоторые вещи, к которым вы должны быть готовы:

  • Windows 8 и Windows Phone имеют похожие, но не совсем идентичные модели времени жизни и навигации,
  • В XAML есть (часто расстраивающие) нюансы различий. Например, Windows использует ссылки в пространстве имен, а Windows Phone использует пространство имен clr. И вы не всегда можете рассчитывать на четность функций аналогичных элементов пользовательского интерфейса. В общем, Windows Phone XAML кажется более многофункциональным, чем Windows 8, поэтому я подозреваю, что мой порт с Windows 8 на Windows Phone был более плавным, чем могло бы быть наоборот.
  • В Windows 8 их использование не так уж много (как светлых, так и темных), но в Windows Phone вы, как правило, захотите использовать стили, основанные на выбранной пользователем теме, используя ресурсы, такие как PhoneAccentBrush.
  • Обязательно ознакомьтесь с инструментарием Windows Phone для тех вещей, в которые вы не можете поверить, которых нет по умолчанию ?

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

Вау! Как насчет этих портативных библиотек классов, о которых я так много слышу?

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

Проект Portable Class Library позволяет создавать и создавать управляемые сборки, которые работают на нескольких платформах .NET Framework. Вы можете создавать классы, которые содержат код, который вы хотите совместно использовать во многих проектах, например разделяемую бизнес-логику, а затем ссылаться на эти классы из разных типов проектов.

Разве это не сэкономило бы мне кучу времени? Возможно, для реализации серверных сервисов, но на самом деле это был не проект с нуля, поэтому имел ли он (или вообще его) смысл исправлять то, что не сломалось: версию для Windows 8? Для реального приложения, которое я ожидаю развивать на обеих платформах, возможно, стоит вернуться и сделать это, чтобы уменьшить количество дублирующегося кода.

Но и здесь я немного неискренен, я знал, что вскоре перейду на Windows Phone после запуска версии для Windows 8, поэтому реальный ответ — немного более тактичный и связанный с работой. Переносимые библиотеки классов являются функцией Visual Studio Professional (и выше); с целью охвата как можно большей аудитории с помощью наших стартовых наборов мы хотели сделать ее такой же бесплатной и простой, как загрузка Visual Studio Express и использование F5.

Если вы хотите узнать больше о переносимых библиотеках классов и методах совместного использования кода между проектами Windows 8 и Windows Phone, есть ряд полезных ресурсов, в том числе:

Канал 9 JumpStart Series

Центр разработки (разработка приложений для Windows Phone 8 и Windows 8)

Real Talk: совместное использование кода между платформами Windows и Windows Phone (сборка 2013 г.)