Блог Сергея Байдачного

Мой блог о технологиях

Archive for Декабрь 2012

Использование карт (часть 2)

leave a comment »

Расширение возможностей по работе с картами

Очень много задач не только требуют отобразить карту и какие-то элементы на ней, но и реализовать поиск координат места по названию и наоборот, отобразить путь, посчитать расстояние до цели и др. Карты от Nokia позволяют реализовывать и все эти задачи. Для этого обратимся к пространству имен Microsoft.Phone.Maps.Services, где содержатся все утилитные классы.

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

Чтобы найти позицию по адресу, необходимо использовать класс GeocodeQuery. Этот класс содержит два свойства, которые позволяют установить начальные параметры для поиска, это SearchTerm и GeoCoordinate. Первое свойство SearchTerm позволяет задать параметры поиска. Тут не обязательно должен быть точный адрес, так как класс GeocodeQuery позволяет получить коллекцию результатов поиска. Поскольку результатов может быть несколько, то для правильной сортировки и оптимизации поиска задается свойство GeoCoodinate. Обычно это свойство задает текущую позицию устройства и позволяет не выдавать заведомо бесполезные результаты (например, адреса в США, когда Вы находитесь в Украине). При сложных сценариях GeoCoordinate можно устанавливать в любую позицию.

Создав объект типа GeocodeQuery и задав основные свойства, можно переходить к поиску. Для этого используется метод QueryAsync, который после своего завершения работы инициирует событие QueryCompleted. Поэтому, следует повесить обработчик события QueryCompleted и можно вызывать метод. Внутри обработчика события QueryCompleted следует проверить количество результатов и возможность возникновения ошибки. Вот небольшой пример кода, который выполняет поиск адреса:

 

 private async void OneShotLocation_Click()
 {
     GeocodeQuery MyGeocodeQuery = new GeocodeQuery();
     MyGeocodeQuery.SearchTerm = "Dnepropetrovsk, Marksa 101";
     MyGeocodeQuery.GeoCoordinate = new GeoCoordinate(50.4556, 30.5143);

     MyGeocodeQuery.QueryCompleted += MyGeocodeQuery_QueryCompleted;
     MyGeocodeQuery.QueryAsync();
 }

 void MyGeocodeQuery_QueryCompleted(object sender, 
          QueryCompletedEventArgs<IList<MapLocation>> e)
{
    if ((e.Error == null)&&(e.Result.Count>0))
    {
        Ellipse myCircle = new Ellipse();
        myCircle.Fill = new SolidColorBrush(Colors.Blue);
        myCircle.Height = 20;
        myCircle.Width = 20;
        myCircle.Opacity = 50;

        MapOverlay myLocationOverlay = new MapOverlay();
        myLocationOverlay.Content = myCircle;
        myLocationOverlay.PositionOrigin = new Point(0.5, 0.5);
        myLocationOverlay.GeoCoordinate =
            e.Result.First().GeoCoordinate;

        MapLayer myLocationLayer = new MapLayer();
        myLocationLayer.Add(myLocationOverlay);

        myMap.Layers.Add(myLocationLayer);
        myMap.SetView(e.Result.First().GeoCoordinate, 14);
    }
}

 

Обратите внимание на то, что QueryAsync не поддерживает возможность использовать подход await/async, а требует создания обработчика.

Используя коллекцию результатов можно предоставить пользователю выбор, а если более детально посмотреть на содержимое e.Result, то можно получить не только координаты, но и район города. Тут используются объекты классов MapLocation и MapAddress.

Если у Вас обратная задача и по GPS координатам необходимо найти адрес, то это также можно легко сделать с помощью класса ReverseGeocodeQuery:

 

ReverseGeocodeQuery MyGeocodeQuery = new ReverseGeocodeQuery();
MyGeocodeQuery.GeoCoordinate = new GeoCoordinate(50.4556, 30.5143);

MyGeocodeQuery.QueryCompleted += MyGeocodeQuery_QueryCompleted;
MyGeocodeQuery.QueryAsync();

 

Тут только один параметр для поиска – координаты места, адрес которого необходимо найти.

Остается еще одна задача, которую можно выполнить с помощью карт Nokia, это прокладка пути. При этом путь можно проложить как для пешехода, так и для автомобиля, получив все данные, которые дают современные GPS системы. Тут используется класс RouteQuery, который содержит три основных свойства:

· RouteOptimization – позволяет задать параметр, определяющий оптимальный для пользователя путь: экономный по расстоянию или по времени;

· TravelMode – позволяет указать, как будет передвигаться пользователь: пешком или на автомобиле;

· Waypoints – содержит коллекцию объектов типа GeoCoordinate, перечисляющую те места, где планирует побывать пользователь (в самом простом случае, это начало и конец пути).

Вот пример кода, который задает основные параметры для объекта класса RouteQuery:

 

private async void OneShotLocation_Click()
{
    RouteQuery query = new RouteQuery();
    query.RouteOptimization = RouteOptimization.MinimizeDistance;
    query.TravelMode = TravelMode.Driving;
    query.Waypoints = new List<GeoCoordinate>()
        {
            new GeoCoordinate(50.46,30.5303),
            new GeoCoordinate(50.4556,30.5143)
        };

    query.QueryCompleted += query_QueryCompleted;
    query.QueryAsync();
}

 

Обработчик события QueryCompleted содержит объект типа Route, который можно тут же добавить на карту:

 

void query_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
    MapRoute MyMapRoute = new MapRoute(e.Result);
    myMap.AddRoute(MyMapRoute);
    myMap.SetView(e.Result.BoundingBox);
}

 

Исследуя объект типа Route, можно получить всю необходимую информацию. Например, коллекция Geometry содержит набор объектов типа GeoCoordinate, из которых строится путь, а свойство Legs позволяет получить время пути, расстояние и список мест, где необходимо выполнить изменение пути (инструкций). Все это можно использовать для построения системы любой сложности.

Расширение возможностей с помощью Windows Phone toolkit

Если Вы используете в своем приложении Windows Phone Toolkit, который можно найти по адресу http://phone.codeplex.com/, то можете немного расширить возможности существующего API для карт дополнительными методами и классами.

Как Вы заметили, все асинхронные методы стандартного API требуют создания обработчика события. Windows Phone Toolkit расширяет эти существующие методы аналогами, работающими через async/await. Так, метод GetRouteAsync расширяет класс RouteQuery, а методом GetMapLocationsAsync расширяются классы GeocodeQuery и ReverseGeocodeQuery. Так, предыдущий пример будет выглядеть следующим образом:

 

private async void OneShotLocation_Click()
{
    RouteQuery query = new RouteQuery();
    query.RouteOptimization = RouteOptimization.MinimizeDistance;
    query.TravelMode = TravelMode.Driving;
    query.Waypoints = new List<GeoCoordinate>()
        {
            new GeoCoordinate(50.46,30.5303),
            new GeoCoordinate(50.4556,30.5143)
        };

    query.QueryCompleted += query_QueryCompleted;
    Route r=await query.GetRouteAsync();

    MapRoute MyMapRoute = new MapRoute(r);
    myMap.AddRoute(MyMapRoute);
    myMap.SetView(r.BoundingBox);
}

 

Кроме асинхронных методов, Windows Phone Toolkit расширяет возможности класса Map. Во-первых, тут появляется класс Pushpin, который был в Bing Maps SDK и представляет собой готовую метку для карт. Данные метки можно установить с помощью расширения Children, задающего коллекцию элементов на карте. Во-вторых, тут появился MapItemsControl, который также добавляется в коллекцию Children, но при этом сам является источником для коллекции данных, позволяя реализовать механизм связывания карты и данных.

Ниже пример инициализации коллекции Children и добавления в нее элемента PushPin:

 

ObservableCollection<DependencyObject> children = 
MapExtensions.GetChildren(myMap);

children.Add(new Pushpin() 
{ 
GeoCoordinate = new GeoCoordinate(50.46, 30.5303) 
});

 

А вот этот пример показывает, как можно определить связывание карты и данных в XAML:

 

<maps:Map x:Name="Map" Grid.Row="1" Hold="OnMapHold">
    <maptk:MapExtensions.Children>
        <maptk:Pushpin x:Name="RouteDirectionsPushPin"           
                       Visibility="Collapsed"/>
        <maptk:MapItemsControl Name="StoresMapItemsControl">
            <maptk:MapItemsControl.ItemTemplate>
                <DataTemplate>
                    <maptk:Pushpin GeoCoordinate="{Binding GeoCoordinate}" 
                                   Visibility="{Binding Visibility}" 
                                   Content="{Binding Address}"/>
                </DataTemplate>
            </maptk:MapItemsControl.ItemTemplate>
        </maptk:MapItemsControl>
        <maptk:UserLocationMarker x:Name="UserLocationMarker" 
                                  Visibility="Collapsed"/>
    </maptk:MapExtensions.Children>
</maps:Map>

 

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

Как видите, если у Вас используется связывание с данными, то Toolkit очень полезен. Более того, его можно использовать для миграции Ваших приложений с WP 7 на WP 8.

Written by Sergiy Baydachnyy

16.12.2012 at 11:18

Опубликовано в Windows Phone

Tagged with

Особенности регистрации в Windows 8 Store для студентов

7 комментариев

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

Действительно, чтобы зарегистрироваться как студент, теперь нет необходимости выбирать отдельный тип аккаунта, а достаточно выбрать тип Individual. Этот тип подходит как для разработчика, так и для студента. Вопрос лишь в том, как не платить 49 грн. (а потом и 49 долларов) за аккаунт. Ответ простой: необходимо ввести специальный промо-код в предназначенное для этого поле и пересчитать сумму, сбросив ее в ноль. В Microsoft решили, что вместо того, чтобы делать сложную интеграцию с программой DreamSpark, как это было для Windows Phone Store, достаточно наладить раздачу кодов со скидкой в 100% через сайт программы непосредственно.

Чтобы получить код, заходите на сайт DreamSpark под своим аккаунтом (или регистрируетесь). Для регистрации можно использовать ISIC, емейл в домене Вашего университета (если есть в списке) или специальный промо-код. Специальный промо-код можно получить у меня (Sergiy.Baydachnyy@microsoft.com), если: Вы украинский студент и вышлите мне копию своего студенческого.

Войдя на сайт программы под своим аккаунтом, перейдите вот по этой ссылке: https://www.dreamspark.com/Student/Windows-Store-Access.aspx

clip_image002

Жмете на ссылку Get code Now и получаете свой код со скидкой 100% для регистрации в Windows 8 Store.

Внимание. Для регистрации Вам все равно понадобится карточка Visa или MasterCard (можно взять чужие, например у родителей, но регистрацию проводить вместе с ними, так как нужно звонить в банк). Лучше сразу позвонить в банк и попросить снять CVV код и предупредить о нескольких транзакциях из сети. На карточке должно быть немного денег (до 100 грн.), так как в момент регистрации будут сделаны три транзакции (деньги потом вернут назад). Первая транзакция в размере около 9 грн. подтверждает работоспособность карточки и позволяет выполнить верификацию того, что Вы живете в Украине. Вторая транзакция заблокирует сумму случайным образом (у меня это было 17.07, у кого-то 20.50 и т. д.). Эту сумма нужна для того, чтобы завершить верификацию. Поэтому, как только регистрация завершена, пройдитесь по всем вкладкам на Вашем аккаунте и найдите форму для завершения верификации. Тут Вам нужно ввести сумму последней транзакции и трехзначный цифровой код, который есть в описании транзакции. Поэтому, либо идете в клиент-банк, либо опять звоните в банк и уточняете все данные, вводите в форму и завершаете верификацию.

Следуйте по инструкции и Вы выполните всю регистрацию минут за 5.

Written by Sergiy Baydachnyy

14.12.2012 at 10:10

Опубликовано в Windows 8

Tagged with

Использование карт (часть 1)

leave a comment »

 

Итак, разобравшись с определением местоположения, переходим к картам. Для многих разработчиков карты являются больной темой, так как во многих приложениях они являются желательным компонентом, но в Windows Phone 7 с ними было ряд существенных проблем. Во-первых, карты были исключительно в онлайн, что не позволяло строить приложения, подключающиеся к сети только тогда, когда это возможно сделать по Wi-Fi. Во-вторых, для прорисовки карт использовалась служба Bing Maps, которая хорошо работает в США и некоторых странах, но часто бесполезна для украинского пользователя. Все это сводило на нет реализацию многих сценариев по работе с картами.

В Windows Phone 8 ситуация с картами коренным образом изменилась. Карты теперь доступны в офлайн режиме, давай пользователю возможность загрузить карты для выбранных стран один раз, находясь в зоне подключения к Wi-Fi. Кроме того, все модели телефонов будут использовать карты от Nokia. А ведь именно Nokia является одним из крупнейших провайдеров картографической информации. Тут покупают данные и Microsoft для Bing и другие крупные компании. А если Вы пользовались навигатором на Nokia устройствах, то знаете, что карты содержат актуальные данные даже для Украины (где на картах заработать сложно). При этом пользователь не только может установить нужные карты, но и получать их обновления на регулярной основе. Если говорить о Bing Maps, то использование этих карт считается устаревшим подходом, хотя сам элемент еще и остался для совместимости.

Итак, давайте рассмотрим, как работают новые карты.

Загрузка карт

Естественно, чтобы использовать карты, пользователь должен иметь возможность загрузить их. Для этого есть два варианта, это использовать приложение Карты, где можно загрузить карты через настройки. Либо предоставить возможность загрузки карт прямо из приложения. Тут существует два готовых класса, это MapDownloaderTask и MapUpdaterTask. Оба класса позволяют запустить одну из задач в операционной системе Windows Phone 8. В первом случае, это приложение, позволяющее выбрать карты для загрузки, а во втором – другая часть того же приложения, позволяющая проверить наличие обновлений установленных карт и загрузить свежие. Оба класса находятся в пространстве имен Microsoft.Phone.Tasks и использование их довольно примитивно:

 

MapDownloaderTask mapDownloaderTask = new MapDownloaderTask();
mapDownloaderTask.Show();

 

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

Построение маршрута

Если говорить о встроенных возможностях, то тут приложениям доступно еще две задачи, представленными классами MapsTask и MapsDirectionsTasks. Первый класс позволяет запустить приложение Карты из Вашего приложения, а второй – запустить приложение Карты и построить маршрут между двумя заданными пунктами. Посмотрим на эти классы более детально.

Объект класса MapsTask имеет три свойства и может не просто отобразить карту, но и установить уровень приближения, центр карты или выполнить поиск по заданным критериям. Свойства имеют названия ZoomLevel, Center и SearchTerm соответственно. Рассмотрим вот такой код:

 

MapsTask map = new MapsTask();
map.SearchTerm = "Kyiv Zhylianskaya 75";
map.Show();

 

Чтобы заставить данный код работать в эмуляторе, необходимо загрузить карту Украины и Вы получите положение офиса Майкрософт в Киеве:

image

Использование класса MapsDirectionsTask аналогично. У него правда всего два свойства, это Start и End, которые определяют между какими точками нужно прокладывать маршрут. Если свойство Start не задано, то за начало пути будет браться текущее местоположение. Оба свойства имеют тип LabeledMapLocation, конструктор которого принимает заголовок местоположения и GPS координаты. Если координаты не заданы, то заголовок будет использоваться как текст для поиска позиции.

Вот этот кусочек кода позволяет построить путь для проезда в украинский офис Майкрософт:

 

MapsDirectionsTask map = new MapsDirectionsTask();
map.End = new LabeledMapLocation("Kyiv Zhylianskay 75", null);
map.Show();

 

Чтобы он работал в эмуляторе, нужно установить Ваше текущее положение на вкладке Location, а то путь будет строится от значения по умолчанию, а из Редмонда тяжело доехать в Киеве на машине, о чем приложение и сообщитJ

Вот как будет выглядеть экран с построенным маршрутом:

image

Использование элемента управления Map

Перейдем теперь к использованию карт непосредственно в приложении. Тут основным компонентом является класс Map, который можно разместить в виде элемента в XAML файле или добавить на страницу динамически. Правда, чтобы приступить к работе с классом Map, необходимо задекларировать соответствующую возможность в манифесте с помощью элемента с именем ID_CAP_MAP:

 

<Capabilities>
 <Capability Name="ID_CAP_NETWORKING" />
 <Capability Name="ID_CAP_LOCATION" />
 <Capability Name="ID_CAP_MAP" />
</Capabilities>

 

Подобную декларацию можно установить и в графическом редакторе манифеста.

Чтобы добавить карту на страницу приложения в XAML рекомендую воспользоваться панелью инструментов и просто перетащить элемент Map в нужное место. Тогда декларация необходимого пространства имен происходит автоматически. В любом случае, класс Map объявлен в пространстве имен и сборке, которые не декларируются по умолчанию, поэтому среди атрибутов страницы (элемент PhoneApplicationPage) должна появится следующая запись:

xmlns:Controls=
"clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"

 

Ну а сам элемент выглядит достаточно просто:

<Controls:Map Name="myMap" />
 

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

Естественно, тут не все так просто. Сборка Microsoft.Phone.Maps.dll содержит три пространства имен с большим количеством классов.

Первое пространство имен Microsoft.Phone.Maps включает всего два класса. Эти классы содержат внутреннюю информацию для картографической службы (когда идет к ней обращение), включая ID приложения и данные аутентификации. Видимо, данный механизм используется, чтобы убедиться, что карты отдаются «по адресу», то есть только пользователи Windows Phone получат эту уникальную возможность. Нам эти классы не пригодятся, в отличие от всех остальных.

Оставшийся набор классов был разделен на два пространства имен, это Microsoft.Phone.Maps.Controls и Microsoft.Phone.Maps.Services. В первом находятся все классы, которые связаны с построением самого элемента (карты) и его составляющих (дополнительных объектов). А во втором – утилитные классы, которые позволяют выполнить запросы для построения маршрутов, поиска данных по координатам и др. Мы рассмотрим большинством из них, но сначала закончим работать с классом Map.

Рассмотрим основные свойства, которые можно устанавливать у объекта типа Map. Тут можно выделить следующие:

· Center – позволяет отцентрировать карту по заданной позиции GPS. Свойство имеет тип System.Device.Location.GeoCoordinate, конструктор которого принимает в качестве параметров долготу и широту. Если разработчик хочет задать центр внутри XAML, то тут существует автоматический конвертер GeoCoordinateConverter, который позволяет записать долготу и широту в виде строки текста из двух значений, разделенных запятой;

· ZoomLevel – это свойство позволяет установить уровень приближения карты. По умолчанию значение равно 1 и позволяет показать на экране телефона всю карту. Максимальное значение равно 20;

· CartographicMode – карты от Nokia поддерживают четыре режима отображения, которые содержатся в перечислимом типе MapCartographicMode. Естественно, что разработчик может установить любой из них и предоставить пользователю переключать режимы в процессе работы. Вот список этих режимов: Road, Aerial, Hybrid и Terrain. Первый режим позволяет отобразить только графическую схему дорог и домов, во втором случае пользователь получает спутниковый снимок, а в третьем и четвертом случае можно увидеть дороги, наложенные на спутниковую карту или только на рельеф местности;

· ColorMode – если Вы пользовались GPS навигаторами, то знаете, что многие из них в ночное время могут автоматически или по запросу переходить в ночной режим, применяя отличную от дневного цветовую гамму. Подобная функциональность есть и у карт Nokia. Так свойство ColorMode способно принимать одно из двух значений перечислимого типа MapColorMode, это Dark и Light. Догадайтесь сами, какое значение отвечает за какой из режимовJ

· LandmarksEnabled – свойство позволяет включить отображение ориентиров, которые становятся видны при приближении 16 или больше. Самое удивительное, что включив ориентиры и просматривая карту Днепропетровска я нашел их аж две штуки, это Главпочтамт и Национальный горный университет. Это уже радует, хотя я ожидал увидеть хотя бы один памятник Владимиру Ильичу, но увы;

image

· PedestrianFeaturesEnabled – это свойство позволяет указать, нужно ли отображать специальные обозначения для пешеходов. Тут могут быть лестницы, переходы, пешеходные мостики и др. На самом деле я смог найти только немного обозначений для Киеве, а для моего любимого Днепропетровска таких обозначений не было. Может быть не очень и нужны, так как сложных развязок в «четыре этажа» у нас нет, а пешеход в основном ходит по землеJ Обозначения отображаются только при приближении карты 16 и больше.

· Pitch – данное свойство позволяет задать наклон карты в градусах (изображение выше с наклоном), придав карте эффект объемности;

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

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

 

private async void OneShotLocation_Click()
{
    //переменную следует выбрать откуда-то из хранилища настроек пользователя
    //и установить в реальное значение
    bool isAllow=true;

    Geolocator geolocator = new Geolocator();

    if (geolocator.LocationStatus == PositionStatus.Disabled)
    {
        if (MessageBox.Show(
            "Определение позиции заблокировано. Перейти к настройкам телефона?",
            "Ошибка настроек", MessageBoxButton.OKCancel)==MessageBoxResult.OK)
        {
            await Launcher.LaunchUriAsync(new Uri("ms-settings-location:"));
        }
        return;
    }

    geolocator.DesiredAccuracyInMeters = 50;

    if (!isAllow)
    {
        if (MessageBox.Show(
            "Разрешить определение позиции устройства для приложения?",
            "Настройки", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
        {
            //сохранить выбранное значение для дальнейшего использования
            //чтобы в следующий раз им заполнять isAllow
        }
        else
        {
            return;
        }
    }

    try
    {
        Geoposition geoposition = await geolocator.GetGeopositionAsync(
            TimeSpan.FromMinutes(5),
            TimeSpan.FromSeconds(10)
            );
                
        myMap.LandmarksEnabled = true;
        myMap.SetView(ConvertGeocoordinate(geoposition.Coordinate), 
16, 0, 45, MapAnimationKind.Parabolic);

        Ellipse myCircle = new Ellipse();
        myCircle.Fill = new SolidColorBrush(Colors.Blue);
        myCircle.Height = 20;
        myCircle.Width = 20;
        myCircle.Opacity = 50;

        MapOverlay myLocationOverlay = new MapOverlay();
        myLocationOverlay.Content = myCircle;
        myLocationOverlay.PositionOrigin = new Point(0.5, 0.5);
        myLocationOverlay.GeoCoordinate = 
            ConvertGeocoordinate(geoposition.Coordinate);

        MapLayer myLocationLayer = new MapLayer();
        myLocationLayer.Add(myLocationOverlay);

        myMap.Layers.Add(myLocationLayer);
    }
    catch (Exception ex)
    {
        MessageBox.Show("Что-то случилось странное!");
    }
}

public GeoCoordinate ConvertGeocoordinate(Geocoordinate geocoordinate)
{
    return new GeoCoordinate
        (
        geocoordinate.Latitude,
        geocoordinate.Longitude,
        geocoordinate.Altitude ?? Double.NaN,
        geocoordinate.Accuracy,
        geocoordinate.AltitudeAccuracy ?? Double.NaN,
        geocoordinate.Speed ?? Double.NaN,
        geocoordinate.Heading ?? Double.NaN
        );
}  

 

Несмотря на большой объем, код тут достаточно простой. Как и раньше, мы определили позицию устройства и получили объект типа Geoposition, который содержит полученную позицию внутри свойства Coordinate типа Geocoordinate. Тут проблема в том, что карты работают с более сложным объектом типа GeoCoordinate. Несмотря на схожее название (разница в одну букву), GeoCoordinate содержит больше информации, поэтому нам нужно написать специальный метод, который будет выполнять преобразование из одного типа в другой. Этот метод находится в самом конце и называется ConvertGeocoordinate.

Далее, чтобы добавить на карту любой UIElement (в нашем случае голубой кружок), необходимо его завернуть в объект типа MapOverlay, привязав последний к конкретным координатам и указав положение содержимого относительно заданной позиции (выбрав (0.5, 0.5) мы контент располагаем строго по центру.

Из объектов типа MapOverlay мы формируем слой карты, который накладываем на исходную карту. Слой карты описывается классом MapLayer и позволяет хранить любое количество объектов типа MapOverlay. Созданный слой мы добавляем в коллекцию Layers нашей карты. Ну и чтобы красиво переместить карту в нужную позицию, мы использовали метод SetView, о котором писали выше.

Written by Sergiy Baydachnyy

13.12.2012 at 20:12

Опубликовано в Windows Phone

Tagged with

Marmalade для Windows Phone 8

leave a comment »

Сегодня был сделан анонс доступности одного из популярных фреймворков для разработки игр Marmalade для Windows Phone 8. Ранняя бета стала доступна для владельцев пакетов Marmalade Professional и Marmalade Plus.

Учитывая то, что сегодня большинство игр разрабатывается с помощью фреймворков сразу на все платформы, и Marmalade один из популярных фремворков – ожидаем большое количество новых игр для платформы Windows Phone 8.

Осталось дождаться анонса для Windows 8. Но учитывая однотипность платформ (особенно для игр), ждать осталось совсем немного.

Анонс можно найти тут: http://www.madewithmarmalade.com/windows-phone-8

Written by Sergiy Baydachnyy

13.12.2012 at 17:53

Опубликовано в Windows Phone

Tagged with

Отслеживание местоположения

leave a comment »

 

Определение местоположения и интеграции с картами являются ключевыми элементами многих приложений. В этой части мы поговорим об определении местоположения устройства пользователя, которое может быть использовано для отображения информации на карте, при внедрении GPS координат в объекты, связанные с какой-то активностью и во многих других задачах. Windows Phone 8 позволяет использовать все доступные механизмы по определению позиции устройства, это GPS датчик, через Wi-Fi сеть или используя сеть мобильного оператора. Тут все зависит от предпочтений разработчика – точность или время определения позиции.

Начнем с того, что разработчик может найти в Windows Phone 8 сразу два программных интерфейса по определению местоположения. Один интерфейс является частью Silverlight и присутствовал еще в Windows Phone 7, а второй – частью Windows Runtime. Сохранить интерфейс в Silverlight требует поддержка старых приложений, а добавление нового интерфейса в Windows Runtime объясняется необходимостью использования его и в С++ приложениях. Ведь если Вы создаете симпатичный 3D навигатор, то тут без DirectX никак не обойтись, а это означает, что DirectX приложения должны иметь возможность использовать интерфейс по определению местоположения. Если внимательно читать документацию, то можно заметить, что Microsoft не рекомендует использовать старый Silverlight интерфейс по определению местоположения даже в том случае, если Ваше приложение разрабатывается на C#. Старый интерфейс хоть и остался, но никак не развивался и предлагает значительно меньше возможностей. Поэтому далее мы будем использовать только интерфейс из Windows Runtime.

Получение позиции и отслеживание изменений

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

 

<Capabilities>
  <Capability Name="ID_CAP_NETWORKING" />
  <Capability Name="ID_CAP_LOCATION" />
</Capabilities>

 

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

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

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

Перейдем к классам, позволяющим определить местоположение. Тут всего один класс Geolocator с двумя методами (формально один, но перегруженный), двумя событиями и пятью свойствами. Класс находится в пространстве имен Windows.Devices.Geolocation и представляет собой часть Windows Runtime. Поэтому подключать какие-то дополнительные сборки нет необходимости.

Обратимся к свойствам этого класса. Вот их список и назначение:

· DesiredAccurancy – свойство позволяет задать один из двух режимов определения позиции: Default и High. В первом случае местоположение будет определятся максимально эффективным способом с точки зрения ресурсов и времени. Во втором случае полученное местоположение будет подобрано исходя из максимальной точности. Подобное поведение можно было задать и в предыдущих версиях платформы, но это не устраивало разработчиков, так как механизм не предоставлял тонкой настройки. Поэтому следующее свойство более интересно;

· DesiredAccurancyInMeters – позволяет задать точность определения местоположения в метрах. Если установлено это свойство в значение отличное от null, то DesiredAccurancy игнорируется, а поиск местоположения происходит с той точностью, которую определяет DesiredAccurancyInMeters. Несомненно, это более гибкий механизм, который может быть использован в задачах любой сложности;

· LocationStatus – это свойство позволяет узнать готовность объекта Geolocator к получению данных, принимая значение перечислимого типа PositionStatus. На мой взгляд тут одно полезное значение, которое нужно проверять всякий раз, когда Вы решите получить позицию, это PositionStatus.Disabled. Ведь если пользователь разрешил определение местоположения внутри приложения, это вовсе не означает, что он не запретил определение местоположения в глобальный настройках телефона. Это также нужно проверить и значение Disabled это показывает;

· MovementThreshold – это и следующее свойства используются только в том случае, если приложение не только единожды определяет позицию, но и пытается отслеживать изменение положения. Данное свойство определяет изменение положения устройства в метрах по отношению к текущей позиции для отправки события приложению. Иными словами, если мне не интересно обновлять позицию и проводить какие-то вычисления и изменения интерфейса при перемещениях пользователя до 100 метров, то я установлю это свойство в 100. Тогда я гарантирую, что мое приложение не будет делать лишнюю работу, пока пользователь находится в одном месте;

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

Итак, со свойствами мы познакомились и можно приступать к определению местоположения. Для этого используется метод GetGeopositionAsync, который имеет две сигнатуры вызова. В первом случае метод не принимает параметров и ориентируется на свойства объекта. А вот во втором случае разработчик уже может задать два параметра типа TimeSpan. Второй параметр будет определять время, которое отводится на поиск позиции (после чего будет сгенерирован Time Out, если позиция не найдена). Первый параметр более интересный и позволяет задать «возраст» позиции. Дело в том, что Windows Phone умет кэшировать местоположение и в ситуации, когда текущую позицию найти не удается, имеет привычку возвращать данные из кэша. Это доставляло массу проблем разработчикам, так как часто нельзя было гарантировать достоверность данных. Теперь проблема решена и контроль кэша обеспечивается полностью. В дополнении хотелось бы отметить, что оба метода используют новый подход async/await для вызова асинхронных методов. Подобный подход отсутствует в Silverlight, но все новые API вызываются именно так.

Таким образом код, который определяет текущее местоположение может выглядит так:

 

private async void OneShotLocation_Click()
{
   //переменную следует выбрать откуда-то из хранилища настроек пользователя
   //и установить в реальное значение
   bool isAllow=true;

   Geolocator geolocator = new Geolocator();

   if (geolocator.LocationStatus == PositionStatus.Disabled)
   {
       if (MessageBox.Show(
           "Определение позиции заблокировано. Перейти к настройкам телефона?",
           "Ошибка настроек", MessageBoxButton.OKCancel)==MessageBoxResult.OK)
       {
           await Launcher.LaunchUriAsync(new Uri("ms-settings-location:"));
       }
       return;
   }

   geolocator.DesiredAccuracyInMeters = 50;

   if (!isAllow)
   {
       if (MessageBox.Show(
           "Разрешить определение позиции устройства для приложения?",
           "Настройки", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
       {
           //сохранить выбранное значение для дальнейшего использования
           //чтобы в следующий раз им заполнять isAllow
       }
       else
       {
           return;
       }
   }

   try
   {
       Geoposition geoposition = await geolocator.GetGeopositionAsync(
           TimeSpan.FromMinutes(5),
           TimeSpan.FromSeconds(10)
           );

       MessageBox.Show(String.Format(
           "Местоположение получено! Позиция: {0}, {1}", 
           geoposition.Coordinate.Latitude, geoposition.Coordinate.Longitude));

   }
   catch (Exception ex)
   {
       MessageBox.Show("Что-то случилось странное!");
   }
}

 

Если приложению необходимо не просто получить позицию устройства, а отслеживать ее изменение, то тут в дело вступают два события, описанные в классе Geolocator, это PositionChanged и StatusChanged. Первое событие генерируется, когда происходит отправка приложению новой позиции. В основном тут и происходит вся логика работы. Второе событие генерируется всякий раз, когда происходит изменение состояния Geolocator. Например, при работе приложения пользователь может пойти в настройки и выключить определение положения для всего устройства. Обратите внимание, что для того, чтобы отслеживание положения заработало, достаточно привязать к этим событиям свои обработчики, а для выключения – удалить обработчики.

Отслеживание местоположения в фоне

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

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

 

<Tasks>
  <DefaultTask Name="_default" NavigationPage="MainPage.xaml">
    <BackgroundExecution>
      <ExecutionType Name="LocationTracking"/>
    </BackgroundExecution>
  </DefaultTask>
</Tasks>

 

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

· Приложение прекратило отслеживать местоположение;

· Пользователь завершил Background процесс, используя глобальные настройки телефона для приложений;

· Пользователь запретил использование Location служб в ходе работы приложения;

· Недостаточно памяти;

· Прошло более 4-х часов после начала работы приложения в фоне;

· Пользователь запустил другое приложение по отслеживанию позиции и оно также ушло в фон;

· В телефоне включена экономия заряда батареи.

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

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

Поскольку приложение работает в фоне, то следующие ограничения касаются доступа к обновлению интерфейса и таким ресурсам как камера и микрофон. Но если с камерой и микрофоном понятно, то с интерфейсом нужно бороться дополнительно. Фактически разработчику нужен некоторый механизм, который позволит определять, когда приложение запущено в фоне и вызывать части кода по обновлению интерфейса только в том случае, если приложение работает в обычном режиме. Для этих целей можно объявить обработчик события RunningInBackground, которое ассоциировано с приложение и может быть задекларировано в файле App.xaml:

 

<Application.ApplicationLifetimeObjects
    <shell:PhoneApplicationService
       Launching="Application_Launching" 
       Closing="Application_Closing"
       Activated="Application_Activated" 
       Deactivated="Application_Deactivated"
       RunningInBackground="PhoneApplicationService_RunningInBackground"/>
</Application.ApplicationLifetimeObjects>

 

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

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

Зная, как определить местоположение можно переходить к работе с картами.

Written by Sergiy Baydachnyy

11.12.2012 at 13:07

Опубликовано в Windows Phone

Tagged with

Выбираем язык программирования: Windows 8 vs Windows Phone 8

6 комментариев

 

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

Итак, все Вы знаете, что Windows 8 представляет собой абсолютно новую операционную систему, ориентированную на пользователей, которые работают как с обычными компьютерами, так и с планшетами или лэптопами с Touch экраном. Это достигается за счет нового интерфейса, возможности работы на ARM процессорах и реализации абсолютно нового программного интерфейса, который получил название Windows Runtime. Именно Windows Runtime является набором тех строительных блоков, которые предоставляют множество элементов управления нового типа, компонентов по работе с данными, сетью и др. То есть, в Windows Runtime есть все то, что необходимо для построения типичного бизнес-приложения. При этом в Windows Runtime практически не используется старый программный интерфейс Win 32 API. Вместо этого Windows Runtime базируется непосредственно на ядре операционной системы (Kernel), а для прорисовки элементов управления использует DirectX.

Обычно Windows Runtime преподносится как новый, объектно-ориентированный, нативный программный интерфейс. По факту, это набор COM объектов. Технология COM отнюдь не нова для платформы Windows и лежит в основе работы этой операционной системы. Естественно, предоставляемый набор COM объектов является абсолютно новым и несет в себе некоторые расширения, хотя и сделанные не очень нативно. Ключевых изменений несколько:

1). Работа с COM объектами в предыдущих версиях Windows выглядела не очень привлекательно со стороны объектно-ориентированного разработчика. Вытянуть информацию о структуре объекта было затруднительно и основные ошибки можно было отловить только на этапе выполнения, а программирование требовало механизмов динамического создания объектов и большого количества проверок. По этой причине, весь набор COM, входящих в состав Windows Runtime, включают дополнительные файлы, содержащие метаданные. Формат метаданных был заимствован из .NET Framework, но, в .NET Framework они находились внутри сборки, а при работе с COM речь идет и стандартных динамических библиотеках. Поэтому ничего не остается, как хранить метаданные в отдельных файлах. Их можно найти в папке C:\Windows\System32\WinMetadata. Причем, если Вы используете утилиту ildasm из .NET Framework 4.5, то эти метаданные можно легко посмотреть и исследовать всю структуру Windows Runtime.

2). Поскольку работа с COM из языков С# или C++ не выглядит «натуральной», то компиляторы и средства разработки были модифицированы таким образом, что весь набор COM из Windows Runtime разработчику представляется как набор классов. Тут разработчик не думает об интерфейсе IUnknown, не обрабатывает HRESULT, а работает с исключениями и др. Все это стало возможно благодаря метаданным и специальным расширениям, преобразующим конструкции, понятные ООП программисту в вызовы COM. Причем в зависимости от языка эти расширения разные и работают по разному. Так, приложения на С++ компилируются в нативный код. То есть все расширения представляют собой синтаксических сахар, а вот приложения на C# продолжают использовать .NET Framework (.NET Core, включающей основные службы и множество утилитных класов) для своей работы. Естественно, создавая свои собственные компоненты для Windows Runtime Вы будете на выходе получать тот же самый COM и файл с метаданными.

3). Поскольку COM является нативной для Windows, а Win 32 API еще активно используется как старыми приложениями, так и некоторыми системными утилитами, то для того, чтобы обязать приложения (разработчика) использовать «правильный» программный интерфейс, в операционной системе появляется отдельный компонент Broker, который контролирует обращение к различным API из приложения, загруженного из Windows Store. Ведь на том же С++ можно попытаться вызвать как Win 32 API, так и Windows Runtime. Тут есть два варианта: если приложение обращается к небезопасному API, например, требующему дополнительного подтверждения пользователя, то Broker перехватывает такую ситуацию и инициирует вызов только в том случае, если пользователь дал подтверждение. Если приложение пытается вызвать API, который не разрешен при публикации приложений в Store, то тут все гораздо проще — Ваше приложение просто не пройдет сертификациюJ Хотя, на своей девелоперской машине Вы можете обращаться к любым методам того же Win 32 API. Следует отдельно отметить, что существует небольшое количество методов из Win 32 API, к которым все еще можно обращаться из современных Windows 8 приложений. Но их очень мало и все они описаны в документации.

Теперь, когда все стало ясно о Windows Runtime, прейдем к вопросу написания игр. И вот тут нас ждет сюрприз. Так, в Windows 8 в этом плане практически не изменилась. Для написания игр используется старый добрый DirectX (версия 11.1). Тут разработчик может использовать либо какие-то фреймворки, либо использовать DirectX напрямую. О сторонних фреймворках мы говорить не будем, их сейчас появляется большое количество. А вот если говорить о фреймворках, предоставляемых Microsoft, то их просто нет. Старый добрый XNA больше не поддерживается, как и управляемый DirectX. Поэтому единственный язык, который тут можно использовать, это С++.

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

 

image

 

К картинки можно придираться, но она отражает то, о чем я писал выше. Тут С++ можно использовать для разработки современных приложений с использование Windows Runtime, утилизировать часть разрешенных методов из Win 32 API и создавать игры с использованием DirectX. Обратите внимание, что небольшую часть DirectX использовать нельзя даже в C++. Это касается динамической компиляции шейдеров и еще пары механизмов (поэтому прямоугольник я не дотянул).

Если говорить о С#, то тут картина несколько другая:

 

image

 

Тут C# работает на основе .NET Framework, последние предоставляет не только свои возможности по работе с коллекциями, сериализацией и др., но и обвертки для Windows Runtime (хотя их можно отнести скорее к возможностям компилятора). Ни о каким DirectX речи и не идет. Нет, Вы можете написать свои обертки для DirectX и нечто подобное уже есть (SharpDX), но для этого Вам потребуется С++J Почему? Ответ тут очень простой и состоит в том, чтобы заставить разработчика создавать приложения с максимальной производительностью. Именно большое количество качественных приложений позволит сдвинуть ARM устройства в сторону потребителя. Напоминаю, что на ARM, в отличии от Intel архитектуры пользователь не сможет поставить старые приложения в режиме десктопа. Ведь на ARM всех старых приложений просто не существовало. Видимо это подход правильный и он сработает.

Если говорить об HTML 5, то тут идея похожа на C#, но вместо .NET Framework идет двигатель, заложенный в основе IE 10, а также библиотека Win JS, которая предоставляет обертки для Windows Runtime в JavaSсript.

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

Еще раз отмечу, что мое мнение не отражает официальную позицию, а скорее мое внутреннее ощущение.

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

1). Перебросил бы всю утилитную составляющую .NET Core в Windows Runtime и превратил бы язык C# в нативный, избавившись от дополнительной прослойки;

2). Заменил бы DirectX новым API для создания высокопроизводительных графических приложений, сделав бы его в стиле Windows Runtime (частью), что автоматически бы сравняло возможности C# и С++.

Но это все мои фантазии. Реальные же действия по улучшению платформы будут базироваться на отзывах разработчиков. Поэтому все в наших руках.

Перейдем к вопросу выбора языка. Как видите, тут все просто. Если такие технологии как Silverlight и WPF для Вас являются новыми, то однозначно выбирайте С++. Если уж учить новые подходы, то лучше и язык выбирать универсальный. Аналогично стоит поступить, если Вы только начинаете программировать. Но, если Вам нужно написать приложение, а Вы уже имеете знания Silverlight, WPF или JavaScript, то используйте эти языки. Это позволит Вам сразу включится в работу. Правда к большинству игр это не относится, хотя существующие внешние фреймворки могут решить и эту задачу.

В моей практике было несколько случаев, когда компании, пытавшиеся программировать на JavaScript (до этого программируя на C#), не создавали конечный продукт, а также компании, которые вопреки моим советам садились за JavaScript и очень оперативно создавали продукт. Все зависит от уровня и Ваших знаний и тех разработчиков, которые с Вами работают.

И еще одна сноска о JavaScript. Помните, что JavaScript является объектно-ориентированным языком программирования, не уступающим по сложности С++. Поэтому, если Вы садитесь за создание Windows 8 приложения на этом языке, то обязательно проверьте свои знания. К сожалению, большинство современных JavaScript разработчиков с этим языком «дружат» не всегда (как ни странно), а все их программирование сводится к созданию небольших методов и утилизации существующих фреймворков.

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

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

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

Итак, что представляет собой программный интерфейс Windows Phone 8. Первый и самый важный компонент, это SilverLight. Да, тот самый Silverlight, который присутствовал и в Windows Phone 7.x. И сразу же хочу обратить внимание, что в новой версии Windows Phone мы имеет дело не с Silverlight Core или чем-то подобным, а с полноценным Silverlight, который несет в себе не только полезные классы .NET Framework, но и все элементы управления по построению интерфейса. А что же Windows Runtime. Несомненно, Windows Runtime присутствует, но только на самом начальном уровне. Ведь действительно, ядро в Windows Phone 8 и Windows 8 одно и то же. Отсюда появляются дополнительные возможности, например использовать язык программирования С++, который в отличии от Silverlight позволяет создавать нативные приложения. Но, по каким-то загадочным причинам, Windows Runtime значительно урезан по сравнению с большим братом. Можно догадываться об этих причинах – необходимость работы старых приложений и совместимости. Но догадки не отвечают на вопрос о том, что будет дальше и как это будет развиваться. Поэтому я не буду ничего предполагать, а скажу лишь то, что Windows Runtime не содержит ни одного элемента управления! Это означает, что создавать приложения на С++ можно, но только в том случае, если они не имеют интерфейса или для его построения используют DirectX. Попробую зарисовать программную архитектуру:

 

image

 

На картинке C++ и Silverlight никак не пересекаются, просто я решил не рисовать две отдельные картинки. Тут на С++ можно создавать все то, что и в Windows 8, но его возможности ограничены возможностями Windows Runtime и DirectX. А вот Silverlight не только предоставляет окружение для управляемого кода и несет утилитные классы из .NET Core, но и предоставляет весь спектр элементов управления.

Таким образом, выбор языка программирования на Windows Phone 8 не совсем очевиден. Универсального средства в виде С++ тут не, так как интерфейсная часть все еще за пределами Windows Runtime. Таким образом, C# придется использовать и дальше, даже при очень большом желании полностью перейти на С++. Также хочу обратить ваше внимание на то, что Windows Phone продолжает поддерживать и XNA, что диктуется тем же вопросом совместимости. Кстати, из этой картинки становится ясно, почему в Windows Phone 8 присутствует два Location API. Опять же вопрос совместимости. Так, старое API было частью Silverlight, а новое — часть Windows Runtime.

Итак, чтобы выбрать язык(и) программирования для Вашего проекта, обязательно проанализируйте для какой из двух платформ Вы будете создавать приложение. Если Вы планируете покрыть обе платформы, то дальше выбирайте язык исходя из типа приложения и знаний Ваших разработчиков. Для игр выбор не особо велик, а вот с бизнес-приложениями можно экспериментировать достаточно долго. Например, можно писать все на C# или бизнес-логику выносить в отдельную библиотеку на С++ или … В общем, все зависит от ситуации. Надеюсь, что информация выше поможет сделать правильный выбор.

Written by Sergiy Baydachnyy

08.12.2012 at 15:10

Опубликовано в Windows 8, Windows Phone

Tagged with ,

Ассоциация с файлами и «глубокие» ссылки

2 комментария

 

Немного о классе Launcher

Разрабатывая приложения для Windows Phone и Windows 8, все время сталкиваюсь с необходимостью использовать класс Launcher. Ведь с помощью этого класса можно вызвать браузер, передав ему ссылку на страницу для загрузки. Таким образом, будь то «Политика конфиденциальности» или ссылка на детали о событии, класс Launcher всегда поможет. Вот простой код, который позволяет запустить браузер из кода:

 

private async void LauchSomething()
{
    bool b = await Launcher.LaunchUriAsync(new Uri("http://kp.ua"));
}

 

Обратите внимание на то, что тут используется асинхронный метод, поддерживающий новый, более простой сценарий вызова через async/await. Метод LaunchUriAsync класса Launcher возвращает значение типа bool, которое сигнализирует об успешности вызова браузера.

Но, если копнуть глубже, то можно обнаружить, что метод LaunchUriAsync никак не связан с браузером. Его задача отыскать приложение, которое поддерживает протокол, описываемый в Uri. В данном случае протоколом является http и приложение, которое с ним ассоциировано, это Internet Explorer. Следовательно, для другого протокола может быть и другое приложение.

В Windows Phone 8 описано несколько протоколов, которые позволяют вызывать разработчику какие-то встроенные приложения. Например, метод ниже вызовет приложение по отправке почты, и в поле TO установит указанный адрес:

 

private async void LauchSomething()
{
    bool b = await Launcher.LaunchUriAsync(
        new Uri("mailto:sbaydach@microsoft.com"));
}

 

Полный список доступных протоколов можно посмотреть тут: http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj662937(v=vs.105).aspx.

Попробуйте указать в качестве адреса что-то типа такого:

 

bool b = await Launcher.LaunchUriAsync(new Uri("myprotocol:Hello"));

 

В результате запуска на экране появится вот такое сообщение:

image

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

При попытке найти приложение в магазине, пользователь получает не весь список, а только те приложения, которые задекларировали требуемый протокол. Если же на телефоне у пользователя уже стоит несколько приложений с требуемым протоколом, то у него появляется список доступных приложений и пользователь должен выбрать одно из них. Возможности задать приложение по умолчанию для того или иного протокола в Windows Phone 8 нет.

Из вышесказанного можно сделать вывод о том, что разработчик может ассоциировать свое приложение с придуманным им протоколом, чтобы позволить запускать свое приложение извне, используя своеобразный механизм «глубоких» ссылок (deep links). Такая возможность есть, но при одном важном ограничении: нельзя ассоциировать приложение с одним из зарезервированных протоколов. Например, http входит в число зарезервированных протоколов. Список зарезервированных слов можно посмотреть тут: http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207065(v=vs.105).aspx.

Обратите внимание на то, что у класса Launcher есть и второй метод LaunchFileAsync. Если при запуске приложения через «глубокую» ссылку можно передать лишь текст в качестве параметра, то в случае LaunchFileAsync передается файл. При этом основным критерием выбора приложения является расширение файла. Иными словами, в качестве параметра, методу достаточно передать ссылку на объект типа StorageFile:

 

private async void LauchSomething()
{
    StorageFolder local = ApplicationData.Current.LocalFolder;

    StorageFile bqfile = await local.GetFileAsync("myfile.myex");

    bool b=await Launcher.LaunchFileAsync(bqfile);
}

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

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

Наконец, чтобы посмотреть примеры уже работающих ассоциаций, можно воспользоваться почтовым клиентом или браузером. Например, если использовать телефон для открытия вложений с неподдерживаемыми по умолчанию форматами (например, PDF), или при попытке открыть ссылку при чтении страницы в Internet Explorer, указывающую на какой-то документ, тут и срабатывают ассоциации. Иными словами, существует множество приложений, которые поддерживают класс Launcher, среди которых есть и стандартные.

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

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

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

Создание «глубоких» ссылок

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

 

<Extensions>
  <Protocol Name="myprotocol" 
      NavUriFragment="encodedLaunchUri=%s" TaskID="_default"/>
</Extensions> 

 

При этом элемент Extensions должен следовать сразу за элементом Tokens. Тут, с помощью вложенных элементов Protocol, прописываются все протоколы, на которые реагирует приложение. Общее число протоколов не должно превышать десяти, но обычно хватает одного. В качестве атрибутов элементу Protocol указывают имя протокола, идентификатор задачи, где прописывается страница запуска приложения, а также фиксированную строку (ее нужно просто скопировать), которая задает формат запроса.

Описав протокол в манифесте, Вы тем самым декларируете доступ к Вашему приложению по ссылке, через указанный протокол. Остается лишь определить тот момент, когда приложение запускается именно через ссылку и выбрать все возможные параметры. Вот тут разработчика может подстерегать сложность. Дело в том, что когда приложение запускается из меню или через плитку, то в качестве имени начальной страницы передается та, что прописана в манифесте внутри элемента Task. Скорее всего, это MainPage.xaml. Но, если приложение запускается с помощью класса Launcher, то приложение получает в качестве точки входа специально подготовленный адрес. Например, для следующей команды Launcher:

 

await Launcher.LaunchUriAsync(new Uri("myprotocol:Message?Say=Hello"));

 

точка входа будет выглядит следующим образом:

 

/Protocol?encodedLaunchUri=myprotocol%3AMessage%3FSay%3DHello

 

Естественно, если приложение оставить без изменений, то оно будет вылетать при запуске через Launcher с сообщением о том, что xaml страница не найдена. Действительно, в адресе выше нет и намека на XAML файл. Поэтому, чтобы переадресовать приложение на нужную страницу, необходимо написать собственный класс, который будет разбирать адрес выше и формировать правильную точку входа. Для этого необходимо создать класс, который будет наследоваться от класса UriMapperBase и реализовывать метод MapUri:

 

class AssociationUriMapper : UriMapperBase
{
    private string tempUri;

    public override Uri MapUri(Uri uri)
    {
        tempUri = System.Net.HttpUtility.UrlDecode(uri.ToString());

        if (tempUri.Contains("myprotocol:Message?Say="))
        {
            int categoryIdIndex = tempUri.IndexOf("Say=") + 4;
            string message = tempUri.Substring(categoryIdIndex);

            return new Uri("/MainPage.xaml?Message=" + 
                message, UriKind.Relative);
        }

        return uri;
    }
}

 

Тут метод MapUri принимает адрес точки входа. Если это какой-то «нормальный» адрес, например, при навигации в приложение из меню или навигации между страницами, то мы ничего не делаем и возвращаем исходный адрес. А вот если в строке содержится наше сообщение, то мы выбираем значение параметра и формируем новый адрес для точки входа в приложение. В нашем случае навигацию перенаправляем на страницу MainPage.xaml, передавая ей параметр.

Осталось создать объект типа AssociationUriMapper и заменить им стандартный механизм. Это можно сделать в файле App.xaml.cs сразу после создания основного фрейма:

 

RootFrame = new PhoneApplicationFrame();
RootFrame.Navigated += CompleteInitializePhoneApplication;

RootFrame.UriMapper = new AssociationUriMapper();

 

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

Ассоциация приложения с файлом

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

· Из интерфейса другого приложения через класс Launcher;

· Открыть файл как вложение письма в почтовом клиенте;

· Загрузить файл через браузер;

· При работе с хабом Office, где могут присутствовать файлы Вашего типа;

Если первый вариант предполагает, что разработчик сам определит механизм запуска приложения, ассоциированного с файлом в своем интерфейсе, то почтовый клиент, браузер и Office Hub имеют устоявшиеся интерфейсы и поведение. Так, при просмотре вложений в почтовом клиенте, рядом с именем файла отображается иконка. Аналогично, иконка отображается и в Office Hub и в браузере. Поэтому, при определении ассоциации в манифесте, следует указать не только разрешение, но и все возможные иконки. Вот пример описания манифеста:

 

<Extensions>
   <FileTypeAssociation Name="myas" TaskID="_default" 
       NavUriFragment="fileToken=%s">
       <Logos>
           <Logo Size="small" IsRelative="true">33x33.png</Logo>
           <Logo Size="medium" IsRelative="true">69x69.png</Logo>
           <Logo Size="large" IsRelative="true">176x176.png</Logo>
       </Logos>
       <SupportedFileTypes>
         <FileType ContentType="application/text">.myex1</FileType>
       </SupportedFileTypes>
   </FileTypeAssociation>
</Extensions>

 

Тут, как и в случае со ссылками, тут указывается имя ассоциации (но тут оно не особо на что-то влияет), идентификатор задачи, связанной с запуском приложения и NavUriFragment, который просто нужно скопировать. Внутри этого элемента указываются логотипы, которые будут использоваться в ситуациях, описанных выше. Если логотипы не указаны, то будет подставлена иконка по умолчанию. Стандартные приложения отображают иконку по умолчанию и тогда, когда с одним расширением файла связано более одного приложения (или нет приложения вовсе). После логотипов идет самый важный элемент всей этой конструкции, а именно, сами ассоциации с расширениями, которые задаются с помощью элементов FileType. Тут задается тип контента и само расширение. Якобы подобных расширений может быть до 20 штук для одного приложения, хотя это актуально только для «читалок» различных форматов документов.

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

 

/FileTypeAssociation?fileToken=89819279-4fe0-4531-9f12-d612f0323a20

 

Тут приложению передается уникальный токен файла, по которому можно получить и сам файл. Для этого в Windows Phone 8 есть класс SharedStorageAccessManager, который содержит всего два метода: GetSharedFileName и CopySharedFileAsync.

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

Итак, первым делом нужно определить расширение и выполнить правильную переадресацию. Для этого создаем класс, наследник от класса UriMapperBase, как это было со ссылками:

 

class AssociationFileMapper : UriMapperBase
{
 private string tempUri;

 public override Uri MapUri(Uri uri)
 {
     tempUri = uri.ToString();

     if (tempUri.Contains("/FileTypeAssociation"))
     {
         int fileIDIndex = tempUri.IndexOf("fileToken=") + 10;

         string fileID = tempUri.Substring(fileIDIndex);

         string incomingFileName =
             SharedStorageAccessManager.GetSharedFileName(fileID);

         string incomingFileType = Path.GetExtension(incomingFileName);

         if (incomingFileType.Equals(".myex1"))
         {
             return new Uri(
                 "/MainPage.xaml?fileToken=" + fileID, UriKind.Relative);
         }
     }

     return uri;
 }
}

 

Как и в случае со ссылками, устанавливаем свойство UriMapper фрейма в объект созданного класса. Далее, в коде страницы MainPage.xaml (в нашем случае) можно скопировать файл в локальное хранилище и приступить к работе с ним.

Written by Sergiy Baydachnyy

07.12.2012 at 13:54

Опубликовано в Windows Phone

Tagged with