Автоматизация эмулятора Windows Phone 7

http://justinangel.net/WindowsPhone7EmulatorAutomation
  • Перевод
Всем привет,
В этой статье мы рассмотрим, как автоматизировать эмулятор Windows Phone 7 и какую пользу нам это принесёт в реальной жизни.



Эта статья является второй в серии не связанных друг с другом статей о продвинутых возможностях Windows Phone 7.
Предыдущая статья в этой серии называлась "Windows Phone 7 – Unlocked ROMs".

Зачем нужна автоматизация эмулятора Windows Phone 7?


В настоящее время эмулятор Windows Phone 7 может запускать developer packages (XAP’ы) только из Visual Studio 2010.
То есть, если у нас есть XAP мы не можем заставить эмулятор загрузить его без Visual Studio.
Как мы видели в предыдущей статье эмулятор может быть запущен и даже установлен на машинах, на которых нет Visual Studio. Подробнее об этом здесь.
Представим, что на данный момент для того, чтобы загрузить XAP’ы в эмулятор мы должны использовать Visual Studio.

Проблема вот в чём: как мы загрузим XAP’ы в эмулятор или устройства с WP7, не используя Visual Studio?
И ещё, как наш Build-сервер запустит ночные тесты? Или как наши клиенты увидят наши приложения?

У клиентов и Build-серверов нет установленной Visual Studio 2010.
Так как же мы можем развернуть XAP’ы в эмуляторе, работающем на этих машинах?

Прекращаем болтовню, переходим к автоматизации эмулятора WP7!


Давайте создадим новый solution, состоящий из консольного приложения и приложения для Windows Phone 7.



Мы будем использовать консольное приложение как инструмент автоматизации, который сможет работать на любом компьютере с. NET Framework.
Приложение для WindowsPhone – это то приложение, развертывание которого мы и будем автоматизировать.

CoreCon 10 WP7 API


Секретный соус для автоматизации WP7 – это CoreCon API.
Библиотеки CoreCon были в глубокой спячке с 2007 года, когда они в последний получили крупное обновление.
Но для WP7 CoreCon API был обновлен и теперь используется в Visual Studio 2010 при развертывании приложений на устройствах и эмуляторах WP7.
Давайте добавим ссылку на Microsoft.SmartDevice.Connectivity.dll из CoreCon API.
На 64-битной системе DLL можно найти по адресу: C:\Program Files (x86)\Common Files\Microsoft Shared\Phone Tools\CoreCon\10.0\Bin\Microsoft.Smartdevice.Connectivity.dll



Теперь, когда у нас есть ссылка на CoreCon DLL, мы можем приступить к автоматизации WP7.
Вот что у нас должно получиться в итоге:



Мы должны выполнить следующую последовательность действий:
  1. Получить экземпляр WP7 CoreCon SDK
  2. Получить ссылку на эмулятор/устройство
  3. Подключиться к эмулятору/устройству
  4. Удалить предыдущей версии
  5. Установить XAP
  6. Запустить приложение
Получение экземпляра WP7 CoreCon SDK

Мы начнем с получения экземпляра WP7 CoreCon SDK для работы с ним:
  1. // Get CoreCon WP7 SDK
  2. DatastoreManager dsmgrObj = new DatastoreManager(1033);
  3.  
  4. Platform WP7SDK = dsmgrObj.GetPlatforms().Single(p => p.Name == "New Windows Mobile 7 SDK");
* This source code was highlighted with Source Code Highlighter.

Получение ссылки на эмулятор/устройство

Затем нам нужно получить ссылку либо на физическое устройство с WP7, либо на эмулятор с WP7.
Этот пример будет использовать эмулятор, но если установить фраг "useEmulator = false", то этот же пример будет пытаться подключиться к физическому устройству с WP7.
  1. // Get Emulator / Device
  2. bool useEmulator = true;
  3. Device WP7Device = null;
  4. if (useEmulator)
  5.     WP7Device = WP7SDK.GetDevices().Single(d => d.Name == "Windows Phone 7 Emulator");
  6. else
  7.     WP7Device = WP7SDK.GetDevices().Single(d => d.Name == "Windows Phone 7 Device");
* This source code was highlighted with Source Code Highlighter.

Подключение к эмулятору/устройству

Теперь мы запускаем эмулятор/устройство с WP7.
Обратите внимание, что мы будем запускать стандартный WP7 Emulator Image, в предыдущей статье я объяснял, как использовать Unlocked ROM в качестве ROM по умолчанию.
  1. // Connect to WP7 Emulator / Device
  2. Console.WriteLine("Connecting to Windows Phone 7 Emulator/Device...");
  3. WP7Device.Connect();
  4. Console.WriteLine("Windows Phone 7 Emulator/Device Connected...");
* This source code was highlighted with Source Code Highlighter.

Удаление предыдущей версии

Далее, мы должны проверить, что наше приложение уже установлено, и если это так, мы удалим его.
Поскольку метод UpdateApplication в текущем CoreCon API не работает, это самый простой способ обновления установленных приложений.

Для того, чтобы установить или удалить наше приложение, нам нужен его Application Product Identifier (GUID).
Мы можем получить GUID приложения из файла Properties/WMAppManifest.xml.



Следующий код проверяет, установлено ли приложение, и если это так, удаляет его.
  1. Guid appID = new Guid("{5e75bba1-fbf6-463c-94ac-fa4a78f8fd12}");
  2. RemoteApplication app;
  3. if (WP7Device.IsApplicationInstalled(appID))
  4. {
  5.     Console.WriteLine("Uninstalling sample XAP to Windows Phone 7 Emulator/Device...");
  6.  
  7.     app = WP7Device.GetApplication(appID);
  8.     app.Uninstall();
  9.  
  10.     Console.WriteLine("Sample XAP Uninstalled from Windows Phone 7 Emulator/Device...");
  11. }
* This source code was highlighted with Source Code Highlighter.

Установка XAP

Теперь мы установим наш XAP.
Для того, чтобы сделать это, нам понадобится информация о следующем:
  1. Расположение нашего XAP.
  2. GUID приложения.
  3. Расположение иконки приложения.
  1. // Install XAP
  2. Console.WriteLine("Installing sample XAP to Windows Phone 7 Emulator/Device...");
  3.  
  4. app = WP7Device.InstallApplication(
  5.     appID,
  6.     appID,
  7.     "NormalApp",
  8.     @"D:\visual studio 2010\Projects\ConsoleApplication1\WindowsPhoneApplication1\ApplicationIcon.png",
  9.     @"D:\visual studio 2010\Projects\ConsoleApplication1\WindowsPhoneApplication1\Bin\Debug\WindowsPhoneApplication1.xap");
  10.  
  11. Console.WriteLine("Sample XAP installed to Windows Phone 7 Emulator...");
* This source code was highlighted with Source Code Highlighter.

Запуск приложения

И последний шаг: запуск нашего приложения.
  1. // Launch Application
  2. Console.WriteLine("Launching sample app on Windows Phone 7 Emulator...");
  3. app.Launch();
  4. Console.WriteLine("Launched sample app on Windows Phone 7 Emulator...");
* This source code was highlighted with Source Code Highlighter.

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



Итак, для чего может пригодится автоматизация эмулятора WP7?


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

Например, в Vertigo, мы используем автоматизацию для запуска эмулятора WP7 на multi-touch, ноутбуках, которые есть у наших клиентов.
Таким образом, клиенты получают доступ к нашим текущим build’ам без необходимости устанавливать Visual Studio 2010.

Доступ к изолированному хранилищу


Один способ использования особенно интересен мне: автоматический запуск всех unit-тестов в проекте для ночных сборок.



Для автоматизации эмулятора WP7 мы можем ограничиться теми действиями, которые мы выполнили до этого, но как мы получим результаты? Или получим инструкции?

Самый простой метод, который я смог придумать – это связываться через cold storage — читать и записывать файлы в изолированном хранилище.



Мы начнем с записи файла в наш WP7 Application IsoStore.
Помните, что этот код выполняется на эмуляторе/устройстве WP7.
  1. public MainPage()
  2. {
  3.     InitializeComponent();
  4.  
  5.     SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape;
  6.  
  7.     using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
  8.     using (var sw = new StreamWriter(isoStore.OpenFile("Foo.txt", FileMode.OpenOrCreate, FileAccess.Write)))
  9.     {
  10.         sw.Write("Hello WP7! (Written from WP7 IsoStore, read by Console Harness!)");
  11.     }
  12. }
* This source code was highlighted with Source Code Highlighter.

В принципе, мы уже добавили foo.txt файл в наш IsoStore и добавили некоторый текст в него.

Далее, мы бы использовали класс RemoteIsolatedStorage и получили бы доступ к IsoStore эмулятора, но он ещё не включен в CoreCon10.



Мы бы использовали RemoteApplication.GetIsolatedStorage (), но он тоже ещё не реализован.

Вместо этого, мы будем использовать класс FileDeployer.
Здесь есть кое-какая рефлексивная магии, связанная с получением копии класса FileDeployer которая может быть использована в нашем приложении.
  1. Thread.Sleep(10000);
  2. //app.GetIsolatedStore(); <-- Throws NotImplementedException
  3. object ConManServer = WP7Device.GetType().GetField("mConmanServer", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(WP7Device);
  4. FileDeployer f = (FileDeployer)typeof(FileDeployer).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0].Invoke(new object[] { ConManServer });
* This source code was highlighted with Source Code Highlighter.

Далее, мы скопируем файл foo.txt из изолированного хранилища приложения в наш локальный binary folder и выведем его в консоли:
  1. f.ReceiveFile(@"\Applications\Data\" + appID + @"\data\isolatedstore\Foo.txt", @"\Foo.txt"); Console.WriteLine("\t" + File.ReadAllText(@"foo.txt"));
* This source code was highlighted with Source Code Highlighter.

При запуске этого примера мы сможем увидеть в консоли текст, полученный из IsoStore.



И мы закончили. Мы установили канал с двусторонней связью между эмулятором/ устройством WP7 и управляемым кодом .net.

Код


Вот код, который мы написали в этом проекте:
  1. // Get CoreCon WP7 SDK
  2. DatastoreManager dsmgrObj = new DatastoreManager(1033);
  3.  
  4. Platform WP7SDK = dsmgrObj.GetPlatforms().Single(p => p.Name == "New Windows Mobile 7 SDK");
  5.  
  6. // Get Emulator / Device
  7. bool useEmulator = true;
  8. Device WP7Device = null;
  9. if (useEmulator)
  10.     WP7Device = WP7SDK.GetDevices().Single(d => d.Name == "Windows Phone 7 Emulator");
  11. else
  12.     WP7Device = WP7SDK.GetDevices().Single(d => d.Name == "Windows Phone 7 Device");
  13.  
  14. // Connect to WP7 Emulator / Device
  15. Console.WriteLine("Connecting to Windows Phone 7 Emulator/Device...");
  16. WP7Device.Connect();
  17. Console.WriteLine("Windows Phone 7 Emulator/Device Connected...");
  18.  
  19.  
  20. Guid appID = new Guid("{5e75bba1-fbf6-463c-94ac-fa4a78f8fd12}");
  21. RemoteApplication app;
  22. if (WP7Device.IsApplicationInstalled(appID))
  23. {
  24.     Console.WriteLine("Uninstalling sample XAP to Windows Phone 7 Emulator/Device...");
  25.  
  26.     app = WP7Device.GetApplication(appID);
  27.     app.Uninstall();
  28.  
  29.     Console.WriteLine("Sample XAP Uninstalled from Windows Phone 7 Emulator/Device...");
  30. }
  31.  
  32. // Install XAP
  33. Console.WriteLine("Installing sample XAP to Windows Phone 7 Emulator/Device...");
  34.  
  35. app = WP7Device.InstallApplication(
  36.     appID,
  37.     appID,
  38.     "NormalApp",
  39.     @"D:\visual studio 2010\Projects\ConsoleApplication1\WindowsPhoneApplication1\ApplicationIcon.png",
  40.     @"D:\visual studio 2010\Projects\ConsoleApplication1\WindowsPhoneApplication1\Bin\Debug\WindowsPhoneApplication1.xap");
  41.  
  42. Console.WriteLine("Sample XAP installed to Windows Phone 7 Emulator...");
  43.  
  44. // Launch Application
  45. Console.WriteLine("Launching sample app on Windows Phone 7 Emulator...");
  46. app.Launch();
  47. Console.WriteLine("Launched sample app on Windows Phone 7 Emulator...");
  48.  
  49. Console.WriteLine("Reading Foo.txt Isolated Storage file:");
  50.  
  51. Thread.Sleep(10000);
  52. //app.GetIsolatedStore(); <-- Throws NotImplementedException
  53. object ConManServer = WP7Device.GetType().GetField("mConmanServer", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(WP7Device);
  54. FileDeployer f = (FileDeployer)typeof(FileDeployer).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0].Invoke(new object[] { ConManServer });
  55. f.ReceiveFile(@"\Applications\Data\" + appID + @"\data\isolatedstore\Foo.txt", @"\Foo.txt"); Console.WriteLine("\t" + File.ReadAllText(@"foo.txt"));
  56.  
  57. Console.ReadLine();
* This source code was highlighted with Source Code Highlighter.

Конец


В этом посте мы говорили о том, зачем нужна автоматизация процесса развёртывания на эмуляторе/устройстве WP7 и как этого добиться.
Надеюсь, что теперь вы знаете, как автоматизировать развертывание XAP в WP7.
В следующей статье в этой серии мы поговорим о настройке непрерывной интеграции для WP7.
  • +29
  • 3,7k
  • 8
Поделиться публикацией
Похожие публикации
Никаких подозрительных скриптов, только релевантные баннеры. Не релевантные? Пиши на: adv@tmtm.ru с темой «Полундра»

Зачем оно вам?
Реклама
Комментарии 8
  • +3
    В настоящее время эмулятор Windows Phone 7 может запускать developer packages (XAP’ы) только из Visual Studio 2010.

    Извините, я до конца не дочитал. Есть же Application Deployment Tool, при помощи ее можно деплоить и на реальный телефон и в эмулятор. Почему его не хватает?
    • +1
      Ага, просто эта тема не раскрыта в топике. У тулзы c:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.0\Tools\XapDeploy.exe (у меня лежит так) нет возможности использовать аргументы для деплоя (Спасибо авторам тулзы). Но, она очень легко дизассемблируется, кода там совсем не много. И там можно взять весь код по деплою приложения.
      • 0
        Забыл сказать — используется та же библиотека Microsoft.SmartDevice.Connectivity.dll
        • 0
          Есть еще Tom XAP Installer, она может даже целые пакеты приложений ставить автоматически как в телефон, так и в эмулятор.
          • 0
            Tom XAP Installer тоже использует CoreCon API.
      • 0
        А разве эмуль с основной системой не связан через виртуальный сетевой интерфейс? Если мне память не изменяет, вплоть до WM 6.5 включительно так оно и было, т. е. можно было спокойно общаться по TCP/IP. Или я с ActiveSync путаю, давно уже не занимался этим.
        • 0
          Чем отличается пример кода в «Удаление предыдущей версии» и в «Установка XAP»?
          • 0
            Приношу извинения, исправил.

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