Приложения для всех: готовность к мировому рынку и Магазин Windows
API Магазина Windows
Теперь, когда вы, очевидно, определились с направленностью вашего приложения, давайте посмотрим, как использовать API Магазина Windows для достижений избранных вами целей. Эти API можно найти в пространстве имен Windows.ApplicationModel.Store (http://msdn.microsoft.com/library/windows/apps/windows.applicationmodel.store.aspx). Все объекты, упомянутые в данном разделе, содержатся в этом пространстве имен, если не упомянуто иное .
Во-первых, знайте, что базовые действия по работе с лицензированием и с пробной версией имеются по умолчанию: приложению вообще не нужно что-либо делать. Пользователь не может получить ваше приложение без Магазина Windows, и даже если он это сделал, ему нужна лицензия разработчика для того, чтобы установить и запустить его. Более того, так как Магазин Windows автоматически отслеживает пробный период приложений, Windows просто не запустит приложение после того, как пробный период истечет. Вместо этого Windows перенаправит пользователя на страницу приложения в Магазине Windows, где пользователь может купить полную лицензию.
Кроме того, приложение может установить время истечение срока лицензии – не только для пробной версии, но и для полной версии приложения. Это может быть полезным для приложений, которые недействительны или бесполезны после определенной даты, например, приложения для регистрации на какие-либо события (конференции, встречи и так далее), или демо-версии, ограниченные по времени. Подумайте об этом, однако: если пользователь решился на покупку приложения, хотите ли вы просто взять и отключить его? Гораздо лучше, я думаю, поддерживать каким-то образом полезность приложения. В случае с приложением для регистрации на какое-то событие, например, можно предоставить пользователю сведения о других событиях, которые произойдут в будущем, возможно, о времени начала регистрации на них. Опять же, у пользователя уже есть приложение и должны быть какие-то намерения для запуска его даже тогда, когда срок его действия истёк. Как вы можете вызвать подобное намерение? Это хороший вопрос.
Как упомянуто выше, приложения могут применять вторичную схему лицензирования, если нужно. При её применении они могут запросить у пользователя отдельную регистрацию или отдельно получаемый лицензионный ключ какого-либо рода. Опять же, Windows не предлагает API для подобных действий, но не запрещает использования ваших собственных схем.
WinRT обеспечивает следующие возможности:
- Получение из Магазина Windows информации о приложении и продуктах (покупках из приложения), включая значения цены, отформатированные в соответствии с региональными настройками пользователя.
- Получение лицензионной информации о приложении, содержащей сведения о пробном периоде, дате истечения срока действия лицензии и так далее. Приложение может принимать любые необходимые решения на основе этих сведений.
- Предложение пользователю приобрести полную версию лицензии в течение или по окончанию пробного периода. Это особенно полезно, когда приложение исполняется, а пробный период истёк.
- Поддержка покупок из приложения (продуктов).
- Создание чеков.
- Тестирование различных видов взаимодействия с Магазином Windows до отправки туда приложения.
Когда приложение приступает к реальной работе, то есть, после того, как оно будет отправлено в Магазин Windows и попадёт на компьютер пользователя – взаимодействие с API происходит через статический объект CurrentApp (http://msdn.microsoft.com/library/windows/apps/windows.applicationmodel.store.currentapp.aspx):
var currentApp = Windows.ApplicationModel.Store.CurrentApp;
Он имеет следующие методы и свойства:
- appId GUID, который уникально идентифицирует приложение в Магазине Windows.
- linkUri URI (Windows.Foundation.Uri) к странице приложения в Магазине Windows. (Если вы вспомните, в Главе 1 именно это значение нужно сохранить в свойстве application-ListingUri DataPackage , который используется при реализации контракта Общий доступ. Это позволяет пользователю, который получил данные, предоставленные в общий доступ, легко найти ваше приложение.)
- licenseInformation Объект LicenseInformation (http://msdn.microsoft.com/library/windows/apps/windows.applicationmodel.store.licenseinformation.aspx).
- loadListingInformationAsync Возвращает объект ListingInformation (http://msdn.microsoft.com/library/windows/apps/windows.applicationmodel.store.listinginformation.aspx) для приложения; с его помощью можно получить инаформацию о продуктах, доступных для покупки из приложения.
- requestAppPurchaseAsync Вызывает пользовательский интерфейс Магазина Windows для того, чтобы предложить пользователю купить приложение. Этот вызов используется, когда приложение исполняется и обнаружено, что лицензия истекла.
- requestProductPurchaseAsync Вызывает пользовательский интерфейс Магазина Windows для того, чтобы предложить пользователю совершить покупку продукта из приложения.
- getAppReceiptAsync Запрашивет XML-строку, которая содержит чеки покупки приложения и покупок из приложения .
Объект ListingInformation содержит набор свойств, которые соответствующим образом локализованы: ageRating (число, в настоящее время одно из значений: 3, 7, 12, and 16), currentMarket (BCP-47-строка, указывает на рынок пользователя, используется для транзакций), description (строка, содержащая описание приложения из Магазина Windows и локализованное для текущего рынка пользователя), formattedPrice (строка, содержащая информацию о стоимости приложения, отформатированную в соответствии с текущим рынком пользователя и валютой), name (строка с именем приложения для текущего рынка), и productListings. Последнее – это массив объектов ProductListing (http://msdn.microsoft.com/library/windows/apps/windows.applicationmodel.store.productlisting.aspx), каждый из которых содержит три свойства: productId (строка, содержащая идентификатор продукта, определенный в приложении) , formattedPrice (локализованная строка, содержащая информацию о цене), и name (имя продукта, локализованная строка). Вы можете видеть, что эта коллекций – это в точности то, что вы будете использовать для представлению пользователю локализованного списка опций, которые он может приобрести, где productId можно использовать для получения дополнительного содержимого, наподобие изображений из пакета приложения или с веб-сервиса.
Объект LicenseInformation, в свою очередь, содержит следующие свойства: expirationDate (типа Date), isActive (логического типа), и isTrial (логического типа). У него есть одно событие, licenseChanged, которое можно использовать для обнаружения изменений в лицензии, таких, как истечение лицензии во время исполнения приложения, когда пользователю можно показать предложение покупки приложения. Еще одно свойство, productLicenses, это коллекция объектов ProductLicense. Каждый из них содержит соответствующие свойства productId, expirationDate, и isActive.
Совет. Для целей глобализации никогда не сравнивайте два значения, содержащие дату с помощью простых арифметических операторов, наподобие <, >, и =. Вместо этого используйте метод Windows.Globalization.Calendar.compareDateTime (http://msdn.microsoft.com/library/windows/apps/windows.globalization.calendar.comparedatetime.aspx), который учитывает специфические особенности различных календарных систем, которые могут повлиять на результат сравнения.
Это, в двух словах, и есть API Магазина Windows. Вы можете заметить, кстати, что это API не занимается вопросами рекламы, размещенной в приложениях, так как Магазин Windows не участвует в показе рекламы. Но вы можете задаться важным вопросом: как эти API возвращают любую имеющую значение информацию, пока приложение еще в разработке и еще не отправлено в Магазин Windows? Как получить информацию о продукте и протестировать все функции, связанные с покупкой, когда еще ничего не доступно для покупки?
Это хорошие вопросы, и ответы на них находятся в еще одном объекте, в пространстве имен Windows.ApplicationModel.Store, что и станет нашей следующей темой: имитатор приложений Магазина Windows.
Объект CurrentAppSimulator
Для того, чтобы сделать возможным тестирование взаимодействия приложения с Магазином Windows до того, как приложение будет размещено в нём, WinRT предоставляет статический объект CurrentAppSimulator (http://msdn.microsoft.com/library/windows/apps/windows.applicationmodel.store.currentappsimulator.aspx), который идентичен объекту CurrentApp с двумя исключениями: объект имитатора работает с данными из локального XML-файла, а не с настоящими данными из Магазина Windows, и данный объект имеет дополнительный метод, reloadSimulatorAsync, для повторной инициализации имитатора с помощью подобных XML-данных. В течение разработки вы сможете использовать строчку кода для того, чтобы начать работать с этим API:
var currentApp = Windows.ApplicationModel.Store.CurrentAppSimulator;
После, когда вы будете готовы к отправке приложения в Магазин Windows, удалите суффикс Simulator. (Если вы забудете это сделать, приложение не пройдёт сертификацию.)
Когда ваше приложение получает доступ к CurrentAppSimulator, WinRT осуществляет поиск файла, который называется WindowsStore-roxy.xml среди данных приложения, в частности, по адресу %userprofile%\AppData\local\packages\<package name="">
\Microsoft\Windows Store\ApiData. Если файл существует, имитатор инициализируется с помощью его данных. В противном случае создаётся файл со следующим содержимым по умолчанию (слегка отформатировано):
<?xml version="1.0" encoding="utf-16" ?> <CurrentApp> <ListingInformation> <App> <AppId>00000000-0000-0000-0000-000000000000</AppId> <LinkUri> http://apps.microsoft.com/webpdp/app/00000000-0000-0000-0000-000000000000 </LinkUri> <CurrentMarket>en-US</CurrentMarket> <AgeRating>3</AgeRating> <MarketData xml:lang="en-us"> <Name>AppName</Name> <Description>AppDescription</Description> <Price>1.00</Price> <CurrencySymbol>$</CurrencySymbol> <CurrencyCode>USD</CurrencyCode> </MarketData> </App> <Product ProductId="1" LicenseDuration="0"> <MarketData xml:lang="en-us"> <Name>Product1Name</Name> <Price>1.00</Price> <CurrencySymbol>$</CurrencySymbol> <CurrencyCode>USD</CurrencyCode> </MarketData> </Product> </ListingInformation> <LicenseInformation> <App> <IsActive>true</IsActive> <IsTrial>true</IsTrial> </App> <Product ProductId="1"> <IsActive>true</IsActive> </Product> </LicenseInformation> </CurrentApp>
Полную схему XML для этого можно найти на странице CurrentAppSimulator, но довольно легко увидеть, где конкретно нужно изменить данный файл для того, чтобы протестировать различные сценарии:
- Создание дополнительных элементов MarketData для указания сведений о приложении для других рынков. Элемент CurrentMarket отображает значения по умолчанию.
- Создание дополнительных элементов Product (включая их дочерние элементы MarketData) для каждого продукта, доступного для покупки из приложения.
- В элементе App, в LicenseInformation, изменяйте значения IsActive (то есть, срок действия лицензии не истек) и IsTrial между true и false для того, чтобы протестировать различные варианты существования приложения: активное/полная версия, активное/пробная версия, срок действия лицензии истек/полная версия, и срок действия лицензии истек/пробная версия. Так же вы можете добавить элемент ExpirationDate для того, чтобы указать срок действия лицензии (время в формате UTC), использовав форму yyyy-mm-ddThh:mm:ss.ssZ (заменив yyyy:mm:dd with датой и mm:ss.ss временем). Для автоматизированного тестирования дополнительные элементы позволяют вам задавать в коде возвращаемые результаты. Смотрите документацию по CurrentAppSimulator (http://msdn.microsoft.com/library/windows/apps/windows.applicationmodel.store.currentappsimulator.aspx).
- Для каждого продукта добавьте в LicenseInformation элемент Product с соответствующими значениями атрибута ProductId. Поддерживаемые дочерние элементы – это IsActive и ExpirationDate, которые имеют то же значение, что и у лицензии приложения.
Важно отметить, что использование методов в объекте имитатора, которые изменяют статус лицензии, например, таких, которые превращают пробную версию приложения в полную или позвляют совершить покупку из приложения, не изменяют содержимого файла WindowsStoreProxy.xml. Это означает, что вы можете просто перезапустить приложение для того, чтобы сбросить состояние объекта имитатора. Но это так же означает, что вам понадобится править XML-файл и запускать приложение снова для тестирования того, как различные изменения обрабатываются при запуске приложения. (Отметьте так же, что состояние имитатора не сохраняется, когда приложение приостанавливается и останавливается).
Для этой цели метод reloadSimulatorAsync объект имитатора принимает StorageFile, который содержит XML-данные для инициализации. Это может значительно упростить процедуру тестирования и часто подобные файлы находятся в папке проекта, то есть вы сможете сослаться на них с использованием URI ms-appx:///. Однако, не забудьте удалить их из пакета приложения перед отправкой его в Магазин Windows. В Visual Studio щёлкните правой кнопкой мыши файл в Обозревателе проектов, выберите Свойства (Properties). На странице свойств, которая показана на рис. 15.3, установите параметр Действие пакета (Package Action) в значение Нет (None).
Рис. 15.3. Убедитесь, что XML-файлы конфигурации для объекта имитатора не попадут в пакет приложения в Магазине Windows
В примере "Пробное приложение и покупки в приложении" (http://code.msdn.microsoft.com/windowsapps/Licensing-API-Sample-19712f1a), которым мы здесь воспользуемся, используется команда reloadSimulatorAsync для загрузки конкретного XML-файла для каждого из его сценариев. В Сценарии 4, например (js/api-listing-uri.js), он загружает файл data/app-listing-uri.xml следующим образом:
var currentApp = Windows.ApplicationModel.Store.CurrentAppSimulator; var page = WinJS.UI.Pages.define("/html/app-listing-uri.html", { ready: function (element, options) { // ... loadAppListingUriProxyFile(); // Инициализация файла с данными о лицензии }, unload: function () { currentApp.licenseInformation.removeEventListener("licensechanged", appListingUriRefreshScenario); } }); function loadAppListingUriProxyFile() { // Тае же мы можем использовать команду folder.getFileFromPathAsync("ms-appx:///data/app-listing-ur.xml") // вместо двухшагового процесса с применением getFileAsync как показано здесь. Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync("data").done( function (folder) { folder.getFileAsync("app-listing-uri.xml").done( function (file) { currentApp.licenseInformation.addEventListener("licensechanged", appListingUriRefreshScenario); Windows.ApplicationModel.Store.CurrentAppSimulator .reloadSimulatorAsync(file).done(); }); }); }
Обратите внимание на то, как пример прослушивает событие licensechanged и не забудьте вызвать removeEventListener когда страница будет выгружена. (Подробности смотрите в Главе 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript".)
Тот же Сценарий 4 показывает основы получения информации о приложении из Магазина Windows. Когда вы нажимаете на кнопку Show Uri (Показать URI) на его странице, выполняется обработчик, показанный ниже, который выводит свойство приложения linkUri:
function displayLink() { WinJS.log && WinJS.log(currentApp.linkUri.absoluteUri, "sample", "status"); } Получение других свойств приложения выглядит так же, предварительно нужно использовать currentApp.loadListingInformationAsync для получения необходимых данных. Это показано в Сценарии 1 (js/trial-mode.js): function trialModeRefreshScenario() { currentApp.loadListingInformationAsync().done( function (listing) { document.getElementById("purchasePrice").innerText = "You can buy the full app for: " + listing.formattedPrice + "."; }); displayCurrentLicenseMode(); }
Теперь давайте рассмотрим оставшуюся часть примера более подробно, так как она показывает нам, как использовать другие сценарии API Магазина Windows в целом.