如何在Windows 10应用中实现应用内购买?

8

我想在我的Windows通用应用程序中集成应用内购买。在编码之前,我需要执行以下步骤:

  • Windows Dev Center上创建应用程序

  • 在IAPs部分添加产品详细信息,并提交到商店,如图像所示

  • 之后,我在我的应用程序中使用以下代码获取应用内购买产品列表和购买产品的按钮。我还在我的代码中使用了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 Dev Center应用程序中的相同,您可以在图像中看到。
当我运行我的应用并点击“购买”按钮时,就会出现对话框,就像您在图像中看到的那样,之后我没有从商店获取收据数据。
如果我做错了,请给我提供正确的指导,以实现应用内购买并在我的笔记本设备上测试该应用内购买。
2个回答

3

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

简短解决方案

默认情况下,在WindowsStoreProxy.xml中,IsTrial被设置为true,处于该模式下,应用内购买似乎无法正常工作。当我将其更改为false时,它开始为我工作。

稍微详细的解决方案

  • So first of all here we are talking about the simulation of an In-App Purchase in development time (by using the CurrentAppSimulator class). In that case you need a WindowsStoreProxy.xml file. It’s described here

  • Now the window you showed is opened by the CurrentAppSimulator.RequestProductPurchaseAsync line. It basically controls the return value of a Windows Runtime native method (which is very strange for me… I think it’s not intentional by Microsoft… something else should be done there), but if you let it return S_OK that basically is the case when the user paid for the in-App Purchase.

    Screenshot of purchase simulation window

  • When it returns nothing then with very high probability something in the WindowsStoreProxy.xml is wrong. I suggest you to create your own WindowsStoreProxy.xml and read it with the CurrentAppSimulator.ReloadSimulatorAsync method like this:

    var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Testing\WindowsStoreProxy.xml");
    await CurrentAppSimulator.ReloadSimulatorAsync(file);
    
  • For me using the default one from C:\Users\<username>\AppData\Local\Packages\<app package folder>\LocalState\Microsoft\Windows Store\ApiData\WindowsStoreProxy.xml did not work, but a single change already solved the problem: I changed this part

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

    To this:

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

    (So IsTrial was set to false...)

  • Now at this point I also would like to mention that this was a little bit strange, since in in the default WindowsStoreProxy.xml there was no Product defined for my In-App Purchase. So for my “RemoveAds” a proper WindowsStoreProxy.xml would be something like this:

    <?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>
    
  • Another thing I would like to point out is that the CurrentAppSimulator.RequestProductPurchaseAsync with two parameter is obsolete. Leave the true parameter out and you get PurchaseResults instance as the result, which contains the receipt in the ReceiptXML property.


这有点奇怪。这是否意味着如果我们在商店中设置试用版,就不能使用应用内购买? - Emil

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

获取Xml文件

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接