简体   繁体   中英

In-App purchase trouble on Windows 10 UWP

I'm trying to enable an in-app purchase item on my app (already on Windows 10 store), but I always receive the same error message when trying to buy this item:

MyAppName中不再提供此应用内购买项目

This in-App Purchase item is no longer available in MyAppName

The code is fairly simple and just what the docs recommend:

var itemName = "app.advanced_items.full";
if (CurrentApp.LicenseInformation.ProductLicenses[itemName].IsActive) {
    return true;
}
var results = await CurrentApp.RequestProductPurchaseAsync(itemName);

if (results.Status == ProductPurchaseStatus.Succeeded ||
    results.Status == ProductPurchaseStatus.AlreadyPurchased) {
    return true;
} else { 
    return false;
}

More information:

  • I created and submited the in-app item to the store before building the package as the documentation told me
  • The name of the item is the same both on the store and the app ( itemName on code)
  • I tried this before submitting to the store
  • I tried this after submitting to the store (My app is currently broken there! -- unable to buy the item)

I suspect the problem might be related with the following:

  • The app display name (on Package.appxmanifest ) is not the same app name on the store (The name I wanted was not available so I made it longer, but the app once installed will display the original name). This shorter name is the one in the error message...

I changed the "display name" to the full name of the app, but the error was the same. I don't know if sending it to the store might change this (I and don't want to deploy another buggy version just to test this theory)

Extra: The only resources I found online about this issue were useless and related to Windows 8: link

Suggestions?

After 2 months talking to Microsoft support they finally fixed something on their side and my IAP started working.

I believe the fix was global, but if your IAP still do not work, contact them to republish it.

Below is an excerpt from the email they sent me:

We have issued a republish for your IAPs in this app. This should correct the situation as soon as the process completes. You may want to check periodically over the next few hours to see if you are able to confirm the fix worked for you. Let me know what you see.

Please check with the productId of the IAP. I guess the one you mention in your code is different from the one in the store.

If its the same, I recommend to use the method LoadListingInformationAsync which returns the list of IAP's and then select the required IAP from that list. If there's a name mismatch then you wont be able to retrieve that IAP. So we'll be able to find its because of the naming problem. I have also added a sample code for that. Give a try.

        try
        {
            var listing = await CurrentApp.LoadListingInformationAsync();
            var iap = listing.ProductListings.FirstOrDefault(p => p.Value.ProductId == "removeads");
            receipt = await CurrentApp.RequestProductPurchaseAsync(iap.Value.ProductId, true);
            if (CurrentApp.LicenseInformation.ProductLicenses[iap.Value.ProductId].IsActive)
            {
                CurrentApp.ReportProductFulfillment(iap.Value.ProductId);
                //your code after purchase is successful
            }
        }
        catch (Exception ex)
        {
            //exception 
        }

I believe the problem here is that you need to differentiate between testing and production. You cannot use production mode unless you are published in the store. See CurrentApp and CurrentAppSimulator .

From the CurrentAppSimiulator page:

Remarks

Until the app has been listed in the Windows Store, the CurrentApp object won't work in the app. Use the CurrentAppSimulator to test your app's licensing and in-app products while you develop your app. After you test your app, and before you submit it to the Windows Store, you must replace the instances of CurrentAppSimulator with CurrentApp. Your app will fail certification if it uses CurrentAppSimulator.

Here is how I solve this in my app with a #define which I change for testing/production, and a proxy class that switches between CurrentApp and CurrentAppSimulator to make my other code much easier on the eyes.

App.xaml.cs, App()

            //
            // configure in-app purchasing
            //
#if false
#warning WARNING: You are using CurrentAppProxy in TEST MODE!
            CurrentAppProxy.SetTestMode(true); // true for test, false for production
#else
            CurrentAppProxy.SetTestMode(false); // true for test, false for production

CurrentAppProxy.cs

public static class CurrentAppProxy
{
    static bool? testmode = null;
    public static async void SetTestMode(bool mode)
    {
        testmode = mode;
        if (mode)
        {
            var file = await Package.Current.InstalledLocation.GetFileAsync("WindowsStoreProxy.xml");
            if (file != null)
            {
                await CurrentAppSimulator.ReloadSimulatorAsync(file);
            }
        }
    }

    public static LicenseInformation LicenseInformation
    {
        get
        {
            if (testmode == null) throw new NotSupportedException();
            else if (testmode.Value) return CurrentAppSimulator.LicenseInformation;
            else return CurrentApp.LicenseInformation;
        }
    }

    public static IAsyncOperation<IReadOnlyList<UnfulfilledConsumable>> GetUnfulfilledConsumablesAsync()
    {
        if (testmode == null) throw new NotSupportedException();
        else if (testmode.Value) return CurrentAppSimulator.GetUnfulfilledConsumablesAsync();
        else return CurrentApp.GetUnfulfilledConsumablesAsync();
    }

    public static IAsyncOperation<ListingInformation> LoadListingInformationAsync()
    {
        if (testmode == null) throw new NotSupportedException();
        else if (testmode.Value) return CurrentAppSimulator.LoadListingInformationAsync();
        else return CurrentApp.LoadListingInformationAsync();
    }

    public static IAsyncOperation<FulfillmentResult> ReportConsumableFulfillmentAsync(string productId, Guid transactionId)
    {
        if (testmode == null) throw new NotSupportedException();
        else if (testmode.Value) return CurrentAppSimulator.ReportConsumableFulfillmentAsync(productId, transactionId);
        else return CurrentApp.ReportConsumableFulfillmentAsync(productId, transactionId);
    }

    public static IAsyncOperation<PurchaseResults> RequestProductPurchaseAsync(string productId)
    {
        if (testmode == null) throw new NotSupportedException();
        else if (testmode.Value) return CurrentAppSimulator.RequestProductPurchaseAsync(productId);
        else return CurrentApp.RequestProductPurchaseAsync(productId);
    }
}

Usage in my app...

    private async Task RefreshInAppOffers()
    {
        // in-app offers
        List<KeyValuePair<string, ProductListing>> products = null;
        UnfulfilledConsumable unfulfilledConsumable = null;

        InAppOffers.Children.Clear();

        try
        {
            var listinginfo = await CurrentAppProxy.LoadListingInformationAsync();
            products = listinginfo.ProductListings.ToList();
            products.Sort((p1, p2) => p1.Value.FormattedPrice.CompareTo(p2.Value.FormattedPrice));

CurrentAppProxy is they key here. If it works with the simulator, it should work with your production items. You just need to have all the other pieces in place for all the various conditions. Some testing is easiest to do in the debugger.

I tried contacting Microsoft about this issue and they asked me to make the IAP unavailable and then make it available again. I must say it did not solve my issue , but if you want to give it a try, follow these steps:

  1. Create an update for the IAP
  2. Under Distribution and Visibility set the IAP to Not available for purchase
  3. Submit the update
  4. Wait for update to publish
  5. Create a new update for IAP
  6. Set Distribution and Visibility back to Available for purchase
  7. Submit the update
  8. Once this update publishes, retest the IAP

After that, they told me to try making the whole app unavailable to all countries and publish it. Then do the opposite. No success either...

i've got the same problem. In my situation the solution is to add all language description in IAP and then it's works fine

I had similar issue with my new UWP app, "Midi Player". IAP was available for purchase on WP 8.1 right after certification and publishing but shows same error on W10M (Windows 10 Mobile) platform (I believe, all Windows 10 UWP apps has the same store). I've opened issue with Microsoft but they can't help me. Fortunately, the issue now is gone :) What I did:

  • published initial app revision
  • created IAP
  • tested IAP (works on WP8.1, not working on W10M)
  • I found that my Package.appxmanifest file was changed slightly (that string mp:PhoneIdentity PhoneProductId="7f32ab79-xxx-xxx-aff3-ce228745b36f" PhonePublisherId="00000000-0000-0000-0000-000000000000" ) after publishing
  • I changed version (minor number) and submitted new release with changed Package.appxmanifest
  • today, I checked IAP on W10M Lumia 950 and it works.

So, my conclusion:

  • you need to re-publish app after creating IAP
  • you should wait for a little

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM