如何在Windows 10应用程序中实施应用程序内购买?

时间:2015-08-31 09:30:36

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

我想在我的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();
        }
    }

我还将我的应用与商店关联,我的应用包与MS开发中心应用相同,您可以在Image

中看到

当我运行我的应用程序并单击“购买”按钮时,我在Image中看到了这个对话框,之后我没有从商店获得收据数据。

如果我做错了,请给我一个正确的指南,以实现应用内购买并测试我的笔记本电脑设备中的应用内购买。

2 个答案:

答案 0 :(得分:3)

我也有这个问题,问题出现在WindowsStoreProxy.xml文件中。

简短的解决方案

默认情况下,WindowsStoreProxy.xml IsTrial设置为true,在该模式下,应用内购买似乎无效。当我把它改成假时,它开始为我工作。

解决方案稍微长一点

  • 首先,我们在讨论在开发时间内模拟应用程序内购买(使用CurrentAppSimulator类)。在这种情况下,您需要一个WindowsStoreProxy.xml文件。它描述了here

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

    Screenshot of purchase simulation window

  • 当它返回任何内容时,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属性中的收据。

答案 1 :(得分:0)

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;
    }