【问题标题】:How to Implement In-App Purchases in Windows 10 Apps?如何在 Windows 10 应用中实现应用内购买?
【发布时间】:2015-08-31 09:30:35
【问题描述】:

我想在我的 Windows 通用应用中集成应用内购买。我在编码之前做了以下事情。

  • Windows Dev Center上制作应用

  • 在 IAP 部分添加带有详细信息的产品并提交到商店,如您在 Image 中看到的那样

  • 之后,我在我的应用中使用以下代码来获取应用内购买的产品列表和购买产品的按钮。我还在代码中使用了CurrentApp 而不是CurrentAppSimulator,但它出现了异常。
private async void RenderStoreItems()
    {
        picItems.Clear();

        try
        {
            //StoreManager mySM = new StoreManager();
            ListingInformation li = await CurrentAppSimulator.LoadListingInformationAsync();

            System.Diagnostics.Debug.WriteLine(li);

            foreach (string key in li.ProductListings.Keys)
            {
                ProductListing pListing = li.ProductListings[key];
                System.Diagnostics.Debug.WriteLine(key);

                string status = CurrentAppSimulator.LicenseInformation.ProductLicenses[key].IsActive ? "Purchased" : pListing.FormattedPrice;

                string imageLink = string.Empty;

                picItems.Add(
                    new ProductItem
                    {
                        imgLink = key.Equals("BaazarMagzine101") ? "block-ads.png" : "block-ads.png",
                        Name = pListing.Name,
                        Status = status,
                        key = key,
                        BuyNowButtonVisible = CurrentAppSimulator.LicenseInformation.ProductLicenses[key].IsActive ? false : true
                    }
                );
            }

            pics.ItemsSource = picItems;
        }
        catch (Exception e)
        {
            System.Diagnostics.Debug.WriteLine(e.ToString());
        }
    }

    private async void ButtonBuyNow_Clicked(object sender, RoutedEventArgs e)
    {
        Button btn = sender as Button;

        string key = btn.Tag.ToString();

        if (!CurrentAppSimulator.LicenseInformation.ProductLicenses[key].IsActive)
        {
            ListingInformation li = await CurrentAppSimulator.LoadListingInformationAsync();
            string pID = li.ProductListings[key].ProductId;

            string receipt = await CurrentAppSimulator.RequestProductPurchaseAsync(pID, true);

            System.Diagnostics.Debug.WriteLine(receipt);

            // RenderStoreItems();
        }
    }

我还将我的应用与 Store 关联,并且我的应用包与 MS Dev Center 应用中的相同,如您在 Image 中看到的那样

当我运行我的应用并点击购买按钮时,我得到了这个对话框,正如你在Image 中看到的那样,之后我没有从商店获得收据数据。

如果我做错了,请给我适当的指导来实施应用内购买并在我的笔记本电脑设备上测试应用内购买。

【问题讨论】:

    标签: c# .net windows-10 win-universal-app windows-rt


    【解决方案1】:

    我也遇到了这个问题,问题出在WindowsStoreProxy.xml 文件中。

    简短的解决方案

    默认情况下,WindowsStoreProxy.xml 中的IsTrial 设置为 true,在该模式下,应用内购买似乎不起作用。当我将其更改为 false 时,它​​开始为我工作。

    解决方案有点长

    • 首先,我们在这里讨论的是在开发阶段模拟应用内购买(通过使用CurrentAppSimulator 类)。在这种情况下,您需要一个 WindowsStoreProxy.xml 文件。它被描述为here

    • 现在您显示的窗口由CurrentAppSimulator.RequestProductPurchaseAsync 行打开。它基本上控制了 Windows 运行时本机方法的返回值(这对我来说很奇怪......我认为这不是微软故意的......应该在那里做其他事情),但是如果你让它返回 S_OK 基本上就是这种情况当用户支付应用内购买时。

    • 当它什么都不返回时,WindowsStoreProxy.xml 中的某些东西很有可能是错误的。我建议你创建自己的WindowsStoreProxy.xml 并使用CurrentAppSimulator.ReloadSimulatorAsync 方法阅读它,如下所示:

      var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Testing\WindowsStoreProxy.xml");
      await CurrentAppSimulator.ReloadSimulatorAsync(file);
      
    • 对我来说,使用来自C:\Users\<username>\AppData\Local\Packages\<app package folder>\LocalState\Microsoft\Windows Store\ApiData\WindowsStoreProxy.xml 的默认值 没用,但一个更改已经解决了问题:我更改了这部分

      <LicenseInformation>
              <App>
                  <IsActive>true</IsActive>
                  <IsTrial>true</IsTrial>
              </App>
      </LicenseInformation>
      

      到这里:

      <LicenseInformation>
              <App>
                  <IsActive>true</IsActive>
                  <IsTrial>false</IsTrial>
              </App>
      </LicenseInformation>
      

      (所以 IsTrial 被设置为 false...)

    • 现在我还想提一下,这有点奇怪,因为在默认的WindowsStoreProxy.xml 中没有为我的应用内购买定义产品。所以对于我的“RemoveAds”,正确的WindowsStoreProxy.xml 应该是这样的:

      <?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="RemoveAds" LicenseDuration="1" ProductType="Durable">
                  <MarketData xml:lang="en-US">
                      <Name>RemoveAds</Name>
                      <Price>1.00</Price>
                      <CurrencySymbol>$</CurrencySymbol>
                      <CurrencyCode>USD</CurrencyCode>
                  </MarketData>
              </Product>      
          </ListingInformation>
          <LicenseInformation>
              <App>
                  <IsActive>true</IsActive>
                  <IsTrial>false</IsTrial>
              </App>
              <Product ProductId="1">
                  <IsActive>true</IsActive>
              </Product>
          </LicenseInformation>
          <ConsumableInformation>
              <Product ProductId="RemoveAds" TransactionId="10000000-0000-0000-0000-000000000000" Status="Active" />
          </ConsumableInformation>
      </CurrentApp>
      
    • 我想指出的另一件事是带有两个参数的CurrentAppSimulator.RequestProductPurchaseAsync 已过时。去掉 true 参数,你会得到PurchaseResults 实例作为结果,它包含ReceiptXML 属性中的收据。

    【讨论】:

    • 这有点奇怪。这是否意味着如果我们在商店中设置试用版,我们就不能在应用购买中使用?
    【解决方案2】:

    WindowsStoreProxy.xml 转为 c# 代码并序列化为 xml 文件

    public static CurrentApp LoadCurrentApp(string productKey = "Premium", bool isActive = false, bool isTrial = false)
        {
            CurrentApp currentApp = new CurrentApp();
            currentApp.ListingInformation = new ListingInformation()
            {
                App = new App()
                {
                    AgeRating = "3",
                    AppId = BasicAppInfo.AppId,
                    CurrentMarket = "en-us",
                    LinkUri = "",
                    MarketData = new MarketData()
                    {
                        Name = "In-app purchases",
                        Description = "AppDescription",
                        Price = "5.99",
                        CurrencySymbol = "$",
                        CurrencyCode = "USD",
                    }
                },
                Product = new Product()
                {
                    ProductId = productKey,
                    MarketData = new MarketData()
                    {
                        Lang = "en-us",
                        Name = productKey,
                        Description = "AppDescription",
                        Price = "5.99",
                        CurrencySymbol = "$",
                        CurrencyCode = "USD",
                    }
                }
            };
            currentApp.LicenseInformation = new LicenseInformation()
            {
                App = new App()
                {
                    IsActive = isActive.ToString(),
                    IsTrial = isTrial.ToString(),
                },
                Product = new Product()
                {
                    ProductId = productKey,
                    IsActive = isActive.ToString(),
                }
            };
            return currentApp;
        }
    

    基础 xml 模型

    [XmlRoot(ElementName = "MarketData")]
    public class MarketData
    {
        [XmlElement(ElementName = "Name")]
        public string Name { get; set; }
        [XmlElement(ElementName = "Description")]
        public string Description { get; set; }
        [XmlElement(ElementName = "Price")]
        public string Price { get; set; }
        [XmlElement(ElementName = "CurrencySymbol")]
        public string CurrencySymbol { get; set; }
        [XmlElement(ElementName = "CurrencyCode")]
        public string CurrencyCode { get; set; }
        [XmlAttribute(AttributeName = "lang", Namespace = "http://www.w3.org/XML/1998/namespace")]
        public string Lang { get; set; }
    }
    
    [XmlRoot(ElementName = "App")]
    public class App
    {
        [XmlElement(ElementName = "AppId")]
        public string AppId { get; set; }
        [XmlElement(ElementName = "LinkUri")]
        public string LinkUri { get; set; }
        [XmlElement(ElementName = "CurrentMarket")]
        public string CurrentMarket { get; set; }
        [XmlElement(ElementName = "AgeRating")]
        public string AgeRating { get; set; }
        [XmlElement(ElementName = "MarketData")]
        public MarketData MarketData { get; set; }
        [XmlElement(ElementName = "IsActive")]
        public string IsActive { get; set; }
        [XmlElement(ElementName = "IsTrial")]
        public string IsTrial { get; set; }
    }
    
    [XmlRoot(ElementName = "Product")]
    public class Product
    {
        [XmlElement(ElementName = "MarketData")]
        public MarketData MarketData { get; set; }
        [XmlAttribute(AttributeName = "ProductId")]
        public string ProductId { get; set; }
        [XmlElement(ElementName = "IsActive")]
        public string IsActive { get; set; }
    }
    
    [XmlRoot(ElementName = "ListingInformation")]
    public class ListingInformation
    {
        [XmlElement(ElementName = "App")]
        public App App { get; set; }
        [XmlElement(ElementName = "Product")]
        public Product Product { get; set; }
    }
    
    [XmlRoot(ElementName = "LicenseInformation")]
    public class LicenseInformation
    {
        [XmlElement(ElementName = "App")]
        public App App { get; set; }
        [XmlElement(ElementName = "Product")]
        public Product Product { get; set; }
    }
    
    [XmlRoot(ElementName = "CurrentApp")]
    public class CurrentApp
    {
        [XmlElement(ElementName = "ListingInformation")]
        public ListingInformation ListingInformation { get; set; }
        [XmlElement(ElementName = "LicenseInformation")]
        public LicenseInformation LicenseInformation { get; set; }
    }
    

    获取 XmlFile

    public async static Task<StorageFile> GetWindowsStoreProxyXmlAsync(string productKey, bool isActive = false, bool isTrial = false)
        {
            StorageFile xmlFile = null;
            var currentApp = LoadCurrentApp(productKey, isActive, isTrial);
            var xml = StorageHelper.SerializeToXML<CurrentApp>(currentApp);
            if (!string.IsNullOrEmpty(xml))
            {
                xmlFile = await StorageHelper.LocalFolder.CreateFileAsync("MarketData.xml", CreationCollisionOption.ReplaceExisting);
                await FileIO.WriteTextAsync(xmlFile, xml);
            }
            return xmlFile;
        }
    

    【讨论】:

      猜你喜欢
      • 2011-01-02
      • 2016-06-21
      • 1970-01-01
      • 2019-05-21
      • 2016-03-27
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多