动手实验

实验 8: Windows应用商店API

2012年9月

简介

编写Windows应用商店应用最令人瞩目的理由之一是您可以方便地将它们发布到Windows应用商店。考虑到世界范围内目前有超过7亿台PC运行Windows 7,并且每台PC代表一个潜在的Windows 8升级,市场和收入潜力是巨大和多样的。鉴于收入分享计划将高达80%的销售收益分配给作者,开发者具有编写优秀应用并将它们提供给用户的充分动机。

应用商店具有灵活的盈利选项:您可以提供试用,一次性购买,应用内购买,第三方电子商务和广告。

对于试用,您可以使用位于Windows.ApplicationModel.Store命名空间的Windows应用商店API来检测应用程序是否运行于试用许可证。Windows运行时同时提供其他API以轻松地从试用版升级到付费版本,检索许可证信息并提供更多功能。Windows运行时中的CurrentAppSimulator类提供了方便的模拟购买和测试代码的方法,它们依赖于Windows应用商店API并且全部位于一个受控的环境中。

在本实验中您将使用Windows应用商店API来实现Contoso Cookbook的盈利。

首先,您将修改关于框以检测试用版,如果应用程序尚未付费则包含一个购买按钮。接着,当购买按钮被单击后您将使用CurrentAppSimulator模拟购买。最后,您将提供付费而不是免费的意大利食谱来模拟应用内购买。

目标

本实验将向您展示如何:

  • 检测您的应用程序是否以试用版运行。
  • 模拟在应用内部购买应用。
  • 模拟应用内购买额外的产品。
  • 检索有关应用程序和产品的许可证信息。

系统要求

您需要下列软件完成本实验:

  • Microsoft Windows 8
  • Microsoft Visual Studio 2012

设置

您必须执行以下步骤来准备本实验的计算机:

  1. 安装 Microsoft Windows 8。
  2. 安装 Microsoft Visual Studio 2012。

练习

本动手实验包含以下练习:

  1. 检测试用版
  2. 模拟应用购买
  3. 模拟产品购买

完成本实验的预计时间:30至40分钟。

练习 1:检测试用版

在本练习中您将使用Windows运行时中的Windows应用商店API来自定义Contoso Cookbook的开始页面内容。如果应用已经被购买,您将显示许可证信息。如果还未被购买(即以试用版运行),您将显示一个购买按钮。此外,在购买按钮上显示的价格并未被写死,而是来自从Windows应用商店检索的列表信息。

任务 1 – 添加许可证文件

我们将使用CurrentAppSimulator类来完成模拟购买,检索许可证信息以及其他工作。为了使模拟尽可能真实,我们将使用一个名称为license.xml的文件来向CurrentAppSimulator提供价格、过期日期等信息。

1、在Visual Studio中打开您在实验7中完成的ContosoCookbook项目。如果您尚未完成实验7或希望从一个参考副本开始,您可以在开始材料中找到实验已完成的版本。

2、如果项目中没有Data文件夹,则在解决方案资源管理器中创建该文件夹。

3、右键单击Data文件夹并使用Add > Existing Item命令从开始材料的data文件夹导入license.xml。

4、打开App.xaml.cs并向OnLaunched方法添加以下语句。将语句放在检查连接和订阅推送通知的if子句之后。

C#

// 初始化CurrentAppSimulator
var file = await Package.Current.InstalledLocation.GetFileAsync("Data\\license.xml");
await Windows.ApplicationModel.Store.CurrentAppSimulator.ReloadSimulatorAsync(file);

5、打开license.xml并花一些时间检查其内容。<ListingInformation>元素包含有关应用程序自身和我们将在练习3中提供购买的意大利食谱产品的信息。<LicenseInformation>包含有关应用程序和产品的许可证信息。现实生活中所有这些信息将来自Windows应用商店。但是在模拟环境下,信息来自WindowsStoreProxy.xml。

任务 2 – 修改关于页面

现在让我们修改您在实验6中创建的关于页面。目前单词”试用版”出现在关于页面的应用程序标题下面。我们将使用Windows应用商店API来确定它是否的确是试用版并根据结果对页面进行自定义。

1、右键单击项目的DataModel文件夹并使用Add > New Item命令向项目添加一个新的类。将文件命名为AppLicenseDataSource.cs。

2、将文件内容替换如下。

C#

using Windows.ApplicationModel.Store;
using Windows.Foundation; namespace ContosoCookbook
{
class AppLicenseDataSource : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged; private bool _licensed = false;
private string _price; public AppLicenseDataSource()
{
if (CurrentAppSimulator.LicenseInformation.IsTrial)
{
CurrentAppSimulator.LicenseInformation.LicenseChanged += OnLicenseChanged;
GetListingInformationAsync();
}
else
_licensed = true;
} private async void GetListingInformationAsync()
{
var listing = await CurrentAppSimulator.LoadListingInformationAsync();
_price = listing.FormattedPrice;
} private void OnLicenseChanged()
{
if (!CurrentAppSimulator.LicenseInformation.IsTrial)
{
_licensed = true;
CurrentAppSimulator.LicenseInformation.LicenseChanged -= OnLicenseChanged; ((ContosoCookbook.App)App.Current).Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("IsLicensed"));
PropertyChanged(this, new PropertyChangedEventArgs("IsTrial"));
PropertyChanged(this, new PropertyChangedEventArgs("LicenseInfo"));
}
});
}
} public bool IsLicensed
{
get { return _licensed; }
} public bool IsTrial
{
get { return !_licensed; }
} public string LicenseInfo
{
get
{
if (!_licensed)
return "Trial Version";
else
return ("Valid until " + CurrentAppSimulator.LicenseInformation.ExpirationDate.LocalDateTime.ToString("dddd, MMMM d, yyyy"));
}
} public string FormattedPrice
{
get
{
if (!String.IsNullOrEmpty(_price))
return "Upgrade to the Full Version for " + _price;
else
return "Upgrade to the Full Version";
}
}
}
}
}

注意:您刚添加的AppLicenseDataSource类实现了INotifyPropertyChanged接口并公开了名称为IsLicensed, IsTrial, LicenseInfo和 FormattedPrice的属性。前面两个使用CurrentAppSimulator.LicenseInformation.IsTrial来确定现在运行的应用程序是否已经购买或以试用版运行。如果应用程序是试用版,LicenseInfo返回“Trial Version”字符串,或者如果不是试用版,返回包含许可证的过期日期的字符串。FormattedPrice返回一个包含应用程序价格的按钮标签,该价格从Windows应用商店获得(或者在这里来自WindowsStoreProxy.xml)。价格信息来自通过CurrentAppSimulator.LoadListingInformationAsync 检索获得的ListingInformation对象。

3、打开AboutUserControl.xaml并向页面顶部的UserControl元素添加xmlns:common="using:ContosoCookbook.Common"属性。

XAML

<UserControl
x:Class="ContosoCookbook.AboutUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ContosoCookbook"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:common="using:ContosoCookbook.Common"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">

4、现在在Grid元素上方添加以下语句。

XAML

<UserControl.Resources>
<local:AppLicenseDataSource x:Key="License" />
<common:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</UserControl.Resources>

注意:BooleanToVisibilityConverter是一个简单的值转换器,它将布尔值true转换为Visibility.Visible,将false转换为Visibility.Collapsed。它在Visual Studio创建项目时已经被包含在其中。

5、将text属性为“Trial Version”的TextBlock替换为以下语句。

XAML

<TextBlock Text="{Binding LicenseInfo, Source={StaticResource License}}" FontFamily="Segoe UI" FontWeight="SemiLight" FontSize="18" TextWrapping="Wrap" />
<Button x:Name="PurchaseButton" Width="225" Height="120" Margin="0,24,0,0" Visibility="{Binding IsTrial, Source={StaticResource License}, Converter={StaticResource BooleanToVisibilityConverter }}">
<Button.Content>
<TextBlock Text="{Binding FormattedPrice, Source={StaticResource License}}" TextWrapping="Wrap" TextAlignment="Center" />
</Button.Content>
</Button>

</Button>

6、花一些时间检查您刚添加的XAML。TextBlock的文本现在来自AppLicenseDataSource对象的LicenseInfo属性。按钮的文本来自相同对象的FormattedPrice属性,并且按钮是否可见被链接到IsTrial属性。结果是按钮甚至不会在页面中显示,除非应用程序以试用版运行。

任务 3 – 测试结果

现在让我们测试这些修改以查看CurrentAppSimulator和WindowsStoreProxy.xml的运行。

1、按F5启动应用程序。

2、显示超级按钮并点击设置超级按钮。

3、在设置菜单点击About以显示关于页面。

4、确认购买按钮显示在关于页面上,并且价格是$12.99,如图1所示。

图 1 应用程序试用版的关于页面

5、返回Visual Studio并停止调试。

6、打开license.xml并在<App>部分的<Price>元素中将购买价格由$12.99修改为$8.99。

7、再次启动应用程序并转到关于页面。现在购买按钮上显示的价格是多少?

8、再次返回Visual Studio并停止调试。

9、再次打开license.xml并将价格修改回$12.99。同样将<IsTrial>从“true”修改为“false”。

10、启动应用程序并转到关于页面。验证购买按钮已经消失并且您现在将看到消息“Valid until Saturday, December 31, 2022”(在2022年12月31日周六前一直有效),如图2所示。

图 2 应用程序已购买版本的关于页面

11、返回Visual Studio并停止调试。

12、为准备下一个练习,在license.xml中将<IsTrial>从“false”改回到“true”。

练习 2: 模拟应用购买

您可以使用license.xml来测试基于应用程序是否为试用版的用户界面的改变,但是它并不能代替对实际购买的模拟。在本练习中您将为购买按钮编写处理程序,这样您就可以从Windows应用商店“购买”应用程序了。

任务 1 – 为购买按钮编写处理程序

为模拟应用程序购买,我们将在用户单击关于页面的购买按钮时调用CurrentAppSimulator.RequestAppPurchaseAsync。并且为了对购买成功完成进行检测,我们将使用已经存在于AppLicenseDataSource中的LicenseChanged事件处理程序。

1、打开AboutUserControl.xaml。

2、向购买按钮添加以下Click属性。

XAML

Click="OnPurchaseButtonClicked"

3、打开AboutUserControl.xaml.cs并添加以下using语句。

C#

using Windows.ApplicationModel.Store;

4、然后添加以下事件处理程序。

C#

private void OnPurchaseButtonClicked(object sender, RoutedEventArgs e)
{
// 购买应用程序
CurrentAppSimulator.RequestAppPurchaseAsync(false);
}

注意:RequestAppPurchaseAsync是一个异步方法。为了确定购买是否执行,您将处理LicenseChanged事件。您没有在这里处理该事件是因为您已经在AppLicenseDataSource.cs中进行了处理。当LicenseChanged事件被触发时,处理程序验证应用程序已经不再是试用版并触发PropertyChanged事件来更新绑定到IsTrial和其他AppLicenseDataSource属性的控件。

5、在测试许可证之前,我们需要缓存App对象的调度程序(dispatcher),因为LicenseChanged事件可以在后台线程中触发,并且我们在事件中使用数据绑定来更新用户界面。打开App.xaml.cs并向App类添加以下成员和属性。

C#

        Windows.UI.Core.CoreDispatcher _dispatcher = null;
public Windows.UI.Core.CoreDispatcher Dispatcher
{
get
{
return _dispatcher;
}
}

6、在App类重写OnWindowCreated方法,这样我们就可以捕获到窗口的dispatcher。

C#

protected override void OnWindowCreated(WindowCreatedEventArgs args)
{
_dispatcher = args.Window.Dispatcher; base.OnWindowCreated(args);
}

任务 2 – 购买应用

现在让我们模拟应用程序购买。请注意CurrentAppSimulator将购买和许可证状态的更改信息存储在内存中,它并未将它们记录在WindowsStoreProxy.xml中。当您购买应用程序后,只要应用程序在运行,它将保持“已购买”状态;但是当您重新启动应用程序时,您将再次运行试用版。

1、按F5以启动应用程序。

2、转到关于页面并点击购买按钮以模拟应用程序购买。

3、在Windows应用商店对话框中点击Continue(继续)按钮完成模拟购买。

4、再次显示关于页面并确认购买按钮已经消失。

注意:在被购买后Contoso Cookbook并未向用户公开额外的功能,它仅用许可证信息替换购买按钮。在现实生活中,您可以选择限制试用版用户的功能并在购买后公开所有的功能。

5、返回Visual Studio并停止调试。

练习 3: 模拟产品购买

除了允许应用程序购买以外,Windows应用商店还支持应用内的产品购买。例如某个游戏在用户完成上一个级别后可以允许用户购买游戏的其他级别。在Windows应用商店术语中,以这种方式购买的功能称为产品,并且Windows运行时为产品购买、确定哪些产品已经被购买、这些产品的许可证状态等内容提供了您所需要的API。

在本练习中您将修改Contoso Cookbook以使意大利食谱不再免费,即查看前必须购买。您将添加一个简单的购买它们的用户界面,这个用户界面基于CurrentAppSimulator,同时您还将添加在产品购买之后才能显示所有意大利食谱的逻辑。

任务 1 – 修改项-明细页面

第一步是添加一个数据源类以提供产品许可证信息。然后我们将添加一个购买按钮并使用数据绑定来确保对于意大利食谱,购买按钮或食谱指南只有其中之一被显示,而不是两者都被显示。

1、右键单击项目的DataModel文件夹并使用Add > New Item命令向项目添加一个新的类。将文件命名为ProductLicenseDataSource.cs。

2、将文件内容替换如下。

C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Store; namespace ContosoCookbook
{
class ProductLicenseDataSource : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged; private const string _name = "ItalianRecipes";
private bool _licensed = false;
private string _price; public string GroupTitle
{
set
{
if (value != "Italian")
_licensed = true;
else if (CurrentAppSimulator.LicenseInformation.ProductLicenses[_name].IsActive)
_licensed = true;
else
{
CurrentAppSimulator.LicenseInformation.LicenseChanged += OnLicenseChanged;
GetListingInformationAsync();
}
}
} private async void GetListingInformationAsync()
{
var listing = await CurrentAppSimulator.LoadListingInformationAsync();
_price = listing.ProductListings[_name].FormattedPrice;
} private void OnLicenseChanged()
{
if (CurrentAppSimulator.LicenseInformation.ProductLicenses[_name].IsActive)
{
_licensed = true;
CurrentAppSimulator.LicenseInformation.LicenseChanged -= OnLicenseChanged; ((ContosoCookbook.App)App.Current).Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("IsLicensed"));
PropertyChanged(this, new PropertyChangedEventArgs("IsTrial"));
}
}); }
} public bool IsLicensed
{
get { return _licensed; }
} public bool IsTrial
{
get { return !_licensed; }
} public string FormattedPrice
{
get
{
if (!String.IsNullOrEmpty(_price))
return "Purchase Italian Recipes for " + _price;
else
return "Purchase Italian Recipes";
}
}
}
}

注意:ProductLicenseDataSource类似于您之前添加的AppLicenseDataSource类。ProductLicenseDataSource对名称为“ItalianRecipes”的产品状态信息进行封装,而AppLicenseDataSource对应用程序的许可证状态数据进行封装。该产品在license.xml中定义。

3、打开ItemDetailPage.xaml并向<Page.Resources>部分添加以下语句。

XAML

<local:ProductLicenseDataSource x:Key="License" />
<common:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>

4、找到两个Text属性是“{Binding Directions}”的TextBlock元素。将每个TextBlock替换为以下语句。

XAML

<TextBlock FontSize="20" FontWeight="Light" Text="{Binding Directions}" TextWrapping="Wrap" Visibility="{Binding IsLicensed, Source={StaticResource License}, Converter={StaticResource BooleanToVisibilityConverter }}" />
<Button Width="225" Height="120" Background="#30ffffff" Click="OnPurchaseProduct" Visibility="{Binding IsTrial, Source={StaticResource License}, Converter={StaticResource BooleanToVisibilityConverter }}">
<Button.Content>
<TextBlock Text="{Binding FormattedPrice, Source={StaticResource License}}" TextWrapping="Wrap" TextAlignment="Center" />
</Button.Content>
</Button>

5、打开ItemDetailPage.xaml.cs并在文件顶部添加以下using语句。

C#

using Windows.ApplicationModel.Store;

6、在LoadState方法的结束处添加以下语句。

C#

// 将组标题传递给LicenseDataSource (重要!)
ProductLicenseDataSource license = (ProductLicenseDataSource)this.Resources["License"];
license.GroupTitle = item.Group.Title;

注意:上述代码很重要,因为它使得ProductLicenseDataSource知道当前显示的食谱是否是意大利食谱或是其他食谱。

7、向ItemDetailPage.xaml.cs添加以下方法以在购买按钮被单击时请求产品购买。

C#

private void OnPurchaseProduct(object sender, RoutedEventArgs e)
{
// 首先检查是否是试用版,您不能在试用版购买产品
if (CurrentAppSimulator.LicenseInformation.IsTrial)
new Windows.UI.Popups.MessageDialog("Please go into About page in Settings and license first", "You must upgrade from trial first").ShowAsync();
else
{
// 购买意大利食谱产品
CurrentAppSimulator.RequestProductPurchaseAsync("ItalianRecipes", false);
}
}

任务 2 – 进行产品购买

现在所有剩下的工作就是测试您的修改并观察产品购买的运行。

1、按F5启动应用程序。

2、点击某个意大利食谱以转到项-明细页面。

3、确认购买按钮出现在烹饪指南处,如图3所示。

图 3 产品购买用户界面

4、点击按钮以启动产品购买。

5、在Windows应用商店对话框中点击Continue以模拟产品购买。

6、确认按钮消失并且烹饪指南出现在它的位置。

7、查看一些其他的意大利食谱并验证烹饪指南按预期方式显示。

8、返回Visual Studio并停止调试。

总结

您在本实验中进行的练习演示了一些Windows应用商店API最重要的方面:如何检测试用版,如何模拟应用程序购买,如何模拟应用内的产品购买以及如何检索有关这些产品的信息。当然在实际的应用程序中,您将以CurrentApp调用替换CurrentAppSimulator调用。这样您将具备通过应用程序盈利的所有工具。请继续前行并创造收益!

祝您在Windows 8中编程快乐!

Windows 8 动手实验系列教程 实验8:Windows应用商店API的更多相关文章

  1. Windows 8 动手实验系列教程 实验7:磁贴和通知

    动手实验 实验7:磁贴和通知 2012年9月 简介 磁贴是Windows应用商店应用用户体验的重要元素.当应用程序被安装后,它的磁贴将在Windows 8开始屏幕被创建.该磁贴(称为主磁贴)作为启动应 ...

  2. Windows 8 动手实验系列教程 实验6:设置和首选项

    动手实验 实验6:设置和首选项 2012年9月 简介 实验3介绍了合约并演示了应用程序如何轻松地与共享和搜索合约实现集成.合约同样包含设置超级按钮,它对活动的Windows应用商店应用的设置进行修改. ...

  3. Windows 8 动手实验系列教程 实验5:进程生命周期管理

    动手实验 实验5:进程生命周期管理 2012年9月 简介 进程生命周期管理对构建Windows应用商店应用的开发者来说是需要理解的最重要的概念之一.不同于传统的Windows应用(它们即使在后台仍然继 ...

  4. Windows phone 应用开发系列教程(更新中)

    Windows phone 应用开发[1]-Text To Speech        作为开篇章节.第一篇将在如下介绍一些Windows phone比较有意思的东西-Text To Speech[文 ...

  5. [js高手之路] html5 canvas系列教程 - 掌握画直线图形的常用API

    我们接着上文[js高手之路] html5 canvase系列教程 - 认识canvas以及基本使用方法继续. 一.直线的绘制 cxt.moveTo( x1, y1 ): 将画笔移动到x1, y1这个点 ...

  6. 微信程序开发系列教程(四)使用微信API创建公众号自定义菜单

    大家可能经常看到一些微信公众号具有功能强大的自定义菜单,点击之后可以访问很多有用的功能. 这篇教程就教大家如何动手做一做. 这个教程最后实现的效果是:创建一个一级菜单"UI5", ...

  7. 微信程序开发系列教程(三)使用微信API给微信用户发文本消息

    这个系列的第二篇教程,介绍的实际是被动方式给微信用户发文本消息,即微信用户关注您的公众号时,微信平台将这个关注事件通过一个HTTP post发送到您的微信消息服务器上.您对这个post请求做了应答(格 ...

  8. angular2系列教程(八)In-memory web api、HTTP服务、依赖注入、Observable

    大家好,今天我们要讲是angular2的http功能模块,这个功能模块的代码不在angular2里面,需要我们另外引入: index.html <script src="lib/htt ...

  9. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现——Post(新 ...

随机推荐

  1. MapReduce调度与执行原理之任务调度(续)

    前言 :本文旨在理清在Hadoop中一个MapReduce作业(Job)在提交到框架后的整个生命周期过程,权作总结和日后参考,如有问题,请不吝赐教.本文不涉及Hadoop的架构设计,如有兴趣请参考相关 ...

  2. Sql 参数的使用

    代码片段: a)声明实例 1.声明SQLCommand实例. SqlCommand cmd = new SqlCommand(); 2.声明SqlDataAdapter实例. SqlDataAdapt ...

  3. typeof 使用介绍

    JS中的变量是松散类型(即弱类型)的,可以用来保存任何类型的数据. typeof 可以用来检测给定变量的数据类型,可能的返回值:1. 'undefined' --- 这个值未定义: 2. 'boole ...

  4. ie6下常见的bug 调整页面兼容性

    ie6下常见的bug 我们布局页面,首先符合标准,如何写一个页面的标准性? 但是ie6等浏览器本身就比较特殊,bug比较多,兵法云,知己知彼百战百胜.我们需要了解ie6的一些常见bug,这样,更好的调 ...

  5. mysql事务和锁InnoDB(转)

    背景 MySQL/InnoDB的加锁分析,一直是一个比较困难的话题.我在工作过程中,经常会有同事咨询这方面的问题.同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题.本文,准备 ...

  6. java设计模式之——适配器模式

    适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 适配器模式的用途 用电器做例子,笔记本电脑的插头一般都是三相的,即除了阳极.阴极 ...

  7. 基于visual Studio2013解决C语言竞赛题之0803报数

       题目

  8. JAVA_2Lesson

    package test; public class abc { public static void main(String[] arg) { int[][] xx=new int[3][]; xx ...

  9. iOS开发中捕获Crash 发送Bug邮件

    在开发过程中,我们有时候会留下Bug,用户在使用我们的app 的时候,有时会出现闪退,这时候我们可以让用户给我们发送邮件,以让我们开发人员更加快速的地位到Bug的所在,以最快的时间解决,同时也提高用户 ...

  10. 关于运行robotium提示连接不上jar问题

    robotium运行测试helloworld报错: java.lang.NoClassDefFoundError: com.jayway.android.robotium.solo.Solo at c ...