应用内购买和试用

Windows SDK 提供了可用于实现以下功能的 API,以便从通用 Windows 平台 (UWP) 应用获得更多资金:

  • 应用内购买 无论你的应用是否免费,你都可以直接在应用内销售内容或新的应用功能(如解锁游戏的下一个级别)。

  • 试用功能 如果在 合作伙伴中心将应用配置为免费试用版,则可以通过排除或限制试用期内的某些功能,吸引客户购买应用的完整版本。 还可以在客户购买应用之前启用仅在试用期间显示的功能(如横幅或水印)。

本文概述了 UWP 应用中的应用内购买和试用版的工作原理。

选择要使用的命名空间

可以使用两个不同的命名空间将应用内购买和试用功能添加到 UWP 应用,具体取决于你的应用目标 Windows 10 或 Windows 11 版本。 尽管这些命名空间中的 API 具有相同的目标,但它们的设计方式大相径庭,并且代码在两个 API 之间不兼容。

  • Windows.Services.Store 从 Windows 10 版本 1607 开始,应用可以使用此命名空间中的 API 来实现应用内购买和试用版。 如果你的应用项目面向 Windows 10 周年版(10.0 版),建议使用此命名空间中的成员内部版本 14393) 或更高版本在 Visual Studio 中。 此命名空间支持最新的加载项类型,如应用商店管理的易耗型加载项,旨在与合作伙伴中心和应用商店支持的未来产品和功能类型兼容。 有关此命名空间的详细信息,请参阅本文中 Windows.Services.Store 命名空间的应用内购买和试用版 部分。

  • Windows.ApplicationModel.Store 所有版本的 Windows 10 和 Windows 11 也支持用于此命名空间中的应用内购买和试用版的旧 API。 有关 Windows.ApplicationModel.Store 命名空间的信息,请参阅使用 Windows.ApplicationModel.Store 命名空间应用内购买和试用。

重要

Windows.ApplicationModel.Store 命名空间将不再更新新功能,建议您尽可能使用 Windows.Services.Store 命名空间。 Windows.ApplicationModel.Store 命名空间不支持使用 桌面桥 的 Windows 桌面应用程序,或在合作伙伴中心使用开发者沙盒的应用或游戏(例如,任何与 Xbox Live 集成的游戏都是如此)。

基本概念

商店中提供的每个商品通常称为 产品。 大多数开发人员仅处理以下类型的产品: 应用加载项

加载项是在应用上下文中提供给客户的产品或功能:例如,在应用或游戏中使用的货币、游戏的新地图或武器、在没有广告的情况下使用你的应用的功能,或者提供此类内容类型的应用的数字内容(如音乐或视频)。 每个应用和加载项都有一个关联的许可证,该许可证指示用户是否有权使用该应用或加载项。 如果用户有权将应用或加载项用作试用版,则许可证还提供有关试用版的其他信息。

若要为应用中的客户提供加载项,你必须 在合作伙伴中心为应用定义加载项,以便应用商店知道它。 然后,你的应用可以使用 Windows.Services.StoreWindows.ApplicationModel.Store 命名空间中的 API 向用户提供作为应用内购买的加载项。

UWP 应用可以提供以下类型的加载项。

加载项类型 DESCRIPTION
耐用 在合作伙伴中心指定的生存期内保留的加载项。

默认情况下,持久加载项永远不会过期,在这种情况下,只能购买一次。 如果为加载项指定特定持续时间,用户可以在加载项过期后重新购买该加载项。
开发者管理的消耗物品 一个附加组件,可以购买并使用,然后在消耗后再次购买。 你负责跟踪加载项所表示项目的用户余额。

当用户使用与加载项关联的任何项目时,你负责维护用户的余额,并在用户使用完所有商品后将加载项的购买报告给应用商店。 在应用将以前的加载项购买报告为已完成之前,用户无法再次购买加载项。

例如,如果你的加载项在游戏中表示 100 个硬币,并且用户消耗了 10 个硬币,你的应用或服务必须为用户维护 90 个硬币的新剩余余额。 用户消耗所有 100 个硬币后,你的应用必须将加载项报告为已完成,然后用户可以再次购买 100 个硬币加载项。
商店管理的易耗品 可以随时购买、使用,并且可以重复购买的加载项。 商店会跟踪用户加载项所代表项目的余额。

当用户使用与加载项关联的任何项目时,你负责将这些项目报告为“应用商店”完成,应用商店会更新用户的余额。 用户可以多次购买附加组件(无需先消耗物品)。 你的应用可以随时查询用户的当前余额。

例如,如果你的加载项表示游戏中的初始数量为 100 个硬币,并且用户消耗了 50 个硬币,你的应用会向应用商店报告加载项的 50 个单位已完成,并且应用商店会更新剩余余额。 如果用户随后重新购买您的附加组件以获取 100 个硬币,那么他们现在总共有 150 个硬币。

注意 若要使用应用商店管理的消耗品,您的应用程序必须在 Visual Studio 中面向 Windows 10 周年版(10.0; 内部版本 14393) 或更高版本,并且必须使用 Windows.Services.Store 名称空间,而不是 Windows.ApplicationModel.Store 名称空间。
订阅 持久加载项,客户将继续按定期间隔收费,以便继续使用加载项。 客户可以随时取消订阅,以避免产生进一步的费用。

注意 要使用订阅加载项,你的应用必须面向 Windows 10 周年版(10.0;内部版本 14393) 或更高版本在 Visual Studio 中,它必须使用 Windows.Services.Store 命名空间而不是 Windows.ApplicationModel.Store 命名空间。

注释

其他类型的加载项,例如包含包(也称为可下载内容或 DLC)的持久加载项,仅限某些受限开发人员使用,本文档未做介绍。

使用 Windows.Services.Store 命名空间进行应用内购买和试用

本部分概述了 Windows.Services.Store 命名空间的重要任务和概念。 此命名空间仅适用于以 Windows 10 周年版(10.0,内部版本 14393) 或更高版本为目标的应用程序(这对应于 Windows 10 版本 1607),在 Visual Studio 中使用。 我们建议应用尽可能使用 Windows.Services.Store 命名空间而不是 Windows.ApplicationModel.Store 命名空间。 有关 Windows.ApplicationModel.Store 命名空间的信息,请参阅 本文

本部分

StoreContext 类入门

Windows.Services.Store 命名空间的主要入口点是 StoreContext 类。 此类提供了可用于获取当前应用及其可用加载项的信息、获取当前应用或其加载项的许可证信息、为当前用户购买应用或加载项以及执行其他任务的方法。 若要获取 StoreContext 对象,请执行以下作之一:

  • 在单用户应用中(即仅在启动应用程序的用户上下文中运行的应用程序),使用静态 GetDefault 方法获取 StoreContext 对象,该对象可用于访问该用户的 Microsoft Store 相关数据。 大多数通用 Windows 平台 (UWP) 应用都是单用户应用。

    Windows.Services.Store.StoreContext context = StoreContext.GetDefault();
    
  • 多用户应用中,使用静态 GetForUser 方法来获取 StoreContext 对象。通过该对象,可以访问特定用户在使用应用时通过其 Microsoft 帐户登录的微软应用商店相关数据。 以下示例获取第一个可用用户的 StoreContext 对象。

    var users = await Windows.System.User.FindAllAsync();
    Windows.Services.Store.StoreContext context = StoreContext.GetForUser(users[0]);
    

注释

使用 桌面桥 的 Windows 桌面应用程序必须执行其他步骤来配置 StoreContext 对象,然后才能使用此对象。 有关详细信息,请参阅本节

拥有 StoreContext 对象后,可以开始调用此对象的方法来获取当前应用及其加载项的 Store 产品信息、检索当前应用及其加载项的许可证信息、为当前用户购买应用或加载项,以及执行其他任务。 有关可以使用此对象执行的常见任务的详细信息,请参阅以下文章:

有关演示如何在 Windows.Services.Store 命名空间中使用 StoreContext 和其他类型的示例应用,请参阅应用商店示例

实现应用内购买

以便使用 Windows.Services.Store 命名空间为您的应用客户提供应用内购买功能:

  1. 如果你的应用提供客户可以购买的加载项,在合作伙伴中心为应用创建加载项提交

  2. 在应用中编写代码,以 检索应用或其提供的加载项的产品信息,然后 确定许可证是否为有效状态(即用户是否持有使用该应用或加载项的许可证)。 如果许可证未处于活动状态,请显示一个界面,以应用内购买的形式向用户提供应用或插件。

  3. 如果用户选择购买应用或加载项,请使用适当的方法来购买产品:

  4. 根据本文 测试指南 对实现进行测试。

实现试用功能

若要使用 Windows.Services.Store 命名空间排除或限制应用试用版中的功能:

  1. 在合作伙伴中心将应用配置为免费试用

  2. 在应用中编写代码以 检索应用或应用提供的加载项的产品信息 ,然后 确定与应用关联的许可证是否为试用许可证

  3. 如果这是试用版,请排除或限制应用中的某些功能,然后在用户购买完整许可证时启用这些功能。 有关详细信息和代码示例,请参阅 实现应用的试用版

  4. 根据本文 测试指南 对实现进行测试。

测试应用内购买或试用功能的实现

如果你的应用使用 Windows.Services.Store 命名空间中的 API 来实现应用内购买或试用功能,则必须将应用发布到应用商店,并将应用下载到开发设备以使用其许可证进行测试。 按照此过程测试代码:

  1. 如果你的应用尚未在应用商店中发布并可用,请确保你的应用满足最低 Windows 应用认证工具包 要求,在合作伙伴中心 提交你的应用 ,并确保你的应用通过认证过程。 你可以 配置你的应用,使其在测试期间在应用商店 中不可见。 请注意正确配置 包航班。 配置不正确的包航班可能无法被下载。

  2. 接下来,请确保已完成以下内容:

  3. 在 Visual Studio 中打开项目后,单击 “项目”菜单,指向 “应用商店”,然后单击“ 将应用与应用商店关联”。 完成向导中的说明,将应用项目与要用于测试的合作伙伴中心帐户中的应用相关联。

    注释

    如果不将项目与应用商店中的应用相关联, StoreContext 方法会将其返回值的 ExtendedError 属性设置为错误代码值0x803F6107。 此值指示应用商店对应用没有任何了解。

  4. 如果尚未这样做,请从上一步中指定的应用商店安装应用,运行该应用一次,然后关闭此应用。 这可确保将应用的有效许可证安装到开发设备。

  5. 在 Visual Studio 中,开始运行或调试项目。 代码应从您与本地项目关联的商店应用程序中检索应用和加载项数据。 如果系统提示重新安装应用,请按照说明作,然后运行或调试项目。

    注释

    完成这些步骤后,可以继续更新应用的代码,然后在开发计算机上调试更新的项目,而无需将新的应用包提交到应用商店。 只需将应用的应用商店版本下载到开发计算机一次即可获取将用于测试的本地许可证。 完成测试后,只需将新的应用包提交到应用商店,并且你想要在应用中购买或试用相关的功能提供给客户。

如果你的应用使用 Windows.ApplicationModel.Store 命名空间,则可以在应用中使用 CurrentAppSimulator 类在测试期间模拟许可证信息,然后再将应用提交到应用商店。 有关详细信息,请参阅如何开始使用CurrentApp和CurrentAppSimulator类

注释

Windows.Services.Store 命名空间不提供可用于在测试期间模拟许可证信息的类。 如果使用 Windows.Services.Store 命名空间实现应用内购买或试用版,则必须将应用发布到应用商店,并将应用下载到开发设备,以使用其许可证进行测试,如上所述。

应用内购收据

Windows.Services.Store 命名空间不提供可以用于获取交易收据的 API,因此无法在应用的代码中验证成功购买。 这是与使用 Windows.ApplicationModel.Store 命名空间的应用不同的体验,该命名空间 使用客户端 API 检索事务收据

如果您使用 Windows.Services.Store 命名空间实现应用内购买,并且希望验证指定客户是否已购买某个应用或附加组件,则可以使用 Microsoft Store 集合 REST API中的 产品查询方法。 此方法的返回数据确认指定的客户是否具有给定产品的权利,并为用户获取该产品的事务提供数据。 Microsoft 商店集合 API 使用 Azure AD 身份验证来检索此信息。

将 StoreContext 类与桌面桥配合使用

使用 桌面桥的桌面 应用程序可以使用 StoreContext 类来实现应用内购买和试用。 但是,如果你有 Win32 桌面应用程序或具有与呈现框架(如 WPF 或 Windows App SDK 应用程序)关联的窗口句柄(HWND)的桌面应用程序,则应用程序必须配置 StoreContext 对象,以指定哪个应用程序窗口是对象显示的模式对话框的所有者窗口。

许多 StoreContext 成员(以及通过 StoreContext 对象访问的其他相关类型的成员)向用户显示与应用商店相关的作(例如购买产品)的模式对话框。 如果桌面应用程序未将 StoreContext 对象配置为指定模式对话框的所有者窗口,则此对象将返回不准确的数据或错误。

若要在使用桌面桥的桌面应用程序中配置 StoreContext 对象,请执行以下步骤。

对于 .NET 6 或更高版本

如果应用程序是使用 .NET 6 或更高版本用 C# 编写的,请执行以下步骤。

  1. 确保 TargetFramework 项目文件中的属性 设置为特定的 Windows SDK 版本,以访问 Windows 运行时 API,该 API 提供 对 WinRT.Interop 命名空间的访问权限。 例如:

    <PropertyGroup>
      <!-- You can also target other versions of the Windows SDK and .NET, e.g. "net6.0-windows10.0.19041.0" -->
      <TargetFramework>net6.0-windows10.0.22000.0</TargetFramework>
    </PropertyGroup>
    
  2. 如本文前面所述,通过使用 GetDefault 方法(或如果你的应用程序是 多用户应用,则使用 GetForUser 方法)获取 StoreContext 对象。 若要使用指定的窗口句柄初始化对话框,请使用 WinRT.Interop.WindowNative.GetWindowHandleWinRT.Interop.InitializeWithWindow.Initialize 方法 (请参阅检索窗口句柄(HWND)显示依赖于 CoreWindow 的 WinRT UI 对象)。

    StoreContext context = StoreContext.GetDefault();
    // Obtain window handle by passing in pointer to the window object
    var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(windowObject);
    // Initialize the dialog using wrapper function for IInitializeWithWindow
    WinRT.Interop.InitializeWithWindow.Initialize(context, hwnd); 
    

对于较早版本的 .NET 或 C++

如果应用程序是使用早期版本的 .NET 或C++编写的,请执行以下步骤。

  1. 执行下列作之一,使应用能够访问 IInitializeWithWindow 接口:

    • 如果应用程序是使用 C# 或 Visual Basic(在 .NET 6 之前)编写的,则使用 ComImport 属性在应用的代码中声明 IInitializeWithWindow 接口,如以下 C# 示例所示。 此示例假定您的代码文件中有一个用于 System.Runtime.InteropServices 命名空间的 使用 语句。

      [ComImport]
      [Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")]
      [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
      public interface IInitializeWithWindow
      {
          void Initialize(IntPtr hwnd);
      }
      
    • 如果应用程序是用 C++ 编写的,请在代码中添加对 shobjidl.h 头文件的引用。 此头文件包含 IInitializeWithWindow 接口的声明。

  2. 通过以前在本文中描述的 GetDefault 方法(或如果您的应用是 多用户应用,则使用 GetForUser )获取 StoreContext 对象,并将此对象强制转换为 IInitializeWithWindow 对象。 然后,调用 IInitializeWithWindow.Initialize 方法,并传递希望成为 StoreContext 方法显示的任何模式对话框的所有者的窗口的句柄。 以下 C# 示例演示如何将应用的主窗口的句柄传递给该方法。 另请参阅 检索窗口句柄 (HWND)显示依赖 CoreWindow 的 WinRT UI 对象

    StoreContext context = StoreContext.GetDefault();
    IInitializeWithWindow initWindow = (IInitializeWithWindow)(object)context;
    initWindow.Initialize(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);
    

产品、SKU 和可用性

商店中的每个产品至少有一个 SKU,每个 SKU 至少有一个 库存情况。 在合作伙伴中心,这些概念对大多数开发人员而言是抽象的,多数开发人员永远不会为他们的应用或附加组件定义 SKU 或可用性。 但是,由于 Windows.Services.Store 命名空间中 Store 产品的对象模型包括 SKU 和可用性,因此对这些概念的基本了解对于某些方案很有用。

物体 DESCRIPTION
产品 产品 是指在商店中可用的任何类型的产品,包括应用或插件。

应用商店中的每个产品都有相应的 StoreProduct 对象。 此类提供一些属性,您可以使用这些属性访问数据,例如产品的商店 ID、应用商店列表中的图像和视频以及定价信息。 它还提供可用于购买产品的方法。
SKU SKU 是产品的特定版本,其自己的说明、价格和其他唯一的产品详细信息。 每个应用或加载项都有默认 SKU。 大多数开发人员唯一会为应用拥有多个 SKU 的情况是当他们分别发布其应用的完整版本和试用版时(在应用商店目录中,每一个版本都是同一应用的不同 SKU)。

某些发布者能够定义自己的 SKU。 例如,大型游戏发布者可能会推出一个 SKU 的游戏,在不允许红色血液的市场中显示绿色血液,并在其他所有市场中使用不同的 SKU 显示红色血液。 或者,销售数字视频内容的发布者可能会为视频发布两个 SKU,一个 SKU 用于高清版本,另一个 SKU 用于标准定义版本。

应用商店中的每个 SKU 都有相应的 StoreSku 对象。 每个 StoreProduct 都有一个 SKU 属性,可用于访问产品的 SKU。
可用性 可用性 是 SKU 的特定版本,具有其专属的定价信息。 每个 SKU 都有默认的可用状态。 某些发布者能够定义自己的可用性,以便为给定 SKU 引入不同的价格选项。

应用商店中的每个可用性都有相应的 StoreAvailability 对象。 每个 StoreSku 都有一个 可用情况 属性,可用于访问 SKU 的可用情况。 对于大多数开发人员,每个 SKU 都有一个默认可用性。

存储 ID

应用商店中的每个应用、加载项或其他产品都有关联的 应用商店 ID (有时也称为 产品应用商店 ID)。 许多 API 需要商店 ID 才能对应用或加载项执行操作。

在商店中,任何产品的商店 ID 都是一个由 12 个字符组成的字母数字字符串,例如 9NBLGGH4R315。 可通过多种不同的方式在应用商店中获取产品的应用商店 ID:

  • 对于应用,可以在合作伙伴中心 应用标识页上获取应用商店 ID。
  • 在合作伙伴中心的附加组件概述页上,您可以获取附加组件的应用商店 ID。
  • 对于任何产品,也可以使用代表产品的 StoreProduct 对象的 StoreId 属性以编程方式获取应用商店 ID。

对于具有 SKU 和可用性的产品,这些 SKU 和可用性还拥有格式不同的专属店铺 ID。

物体 商店 ID 格式
SKU SKU 的 Microsoft Store ID 具有 <product Store ID>/xxxx格式,其中 xxxx 是标识产品 SKU 的 4 个字符的字母数字字符串。 例如,9NBLGGH4R315/000N。 此 ID 由 StoreSku 对象的 StoreId 属性返回,有时称为 SKU 应用商店 ID
可用性 可用性的店铺 ID 采用格式 <product Store ID>/xxxx/yyyyyyyyyyyy,其中 xxxx 是一个 4 个字符的字母数字字符串,用于标识产品的 SKU,而 yyyyyyyyyyyy 是一个 12 个字符的字母数字字符串,用于标识该 SKU 的可用性。 例如,9NBLGGH4R315/000N/4KW6QZD2VN6X。 此 ID 由 StoreAvailability 对象的 StoreId 属性返回,有时称为可用性应用商店 ID

如何在代码中使用产品 ID 添加加载项

如果要在应用上下文中为客户提供加载项,则必须在合作伙伴中心 创建加载项提交 时,输入加载项的唯一产品 ID。 可以使用此产品 ID 在代码中引用加载项,但可以使用产品 ID 的具体情形取决于你在应用中进行应用内购买时使用的命名空间。

注释

在合作伙伴中心为加载项输入的产品 ID 与加载项的 应用商店 ID不同。 应用商店 ID 由合作伙伴中心生成。

使用 Windows.Services.Store 命名空间的应用

如果你的应用使用 Windows.Services.Store 命名空间,则可以使用产品 ID 轻松标识代表加载项的 StoreProduct 或代表加载项许可证的 StoreLicense 。 产品 ID 由 StoreProduct.InAppOfferTokenStoreLicense.InAppOfferToken 属性公开。

注释

尽管产品 ID 是识别代码中的加载项的有用方法,但 Windows.Services.Store 命名空间中的大多数作都使用加载项的 应用商店 ID ,而不是产品 ID。 例如,若要以编程方式检索应用的一个或多个已知加载项,请将加载项的应用商店 ID(而不是产品 ID)传递给 GetStoreProductsAsync 方法。 同样,若要报告易耗型加载项的完成情况,请将加载项的应用商店 ID(而不是产品 ID)传递给 ReportConsumableFulfillmentAsync 方法。

使用 Windows.ApplicationModel.Store 命名空间的应用

如果应用程序使用 Windows.ApplicationModel.Store 命名空间,那么在为大多数操作指定加载项时需要使用您在合作伙伴中心分配的产品 ID。 例如: