jamesmontemagno / InAppBillingPlugin

Cross-platform In App Billing Plugin for .NET
MIT License
651 stars 152 forks source link

Restore Transactions Failed #60

Closed sillerjp closed 7 years ago

sillerjp commented 7 years ago

If you are creating an issue for a BUG please fill out this information. If you are asking a question or requesting a feature you can delete the sections below.

Failure to fill out this information will result in this issue being closed. If you post a full stack trace in a bug it will be closed, please post it to http://gist.github.com and then post the link here.

Bug Information

Hi James, I'm having a strange error. I previously used your plugin and it worked both in iOS and Android. I uploaded my app to both stores and it was approved. Now Apple is rejecting an update saying the in app purchase is failing. I deployed my app using Ad-Hoc to my device. When I click the purchase button in my app it fails when trying to get the purchases (to see if it is already purchased). The error reported is: "Restore Transactions Failed". I did not change anything in the code. I tested with different linker options with no success. Could it be something that changed in the iOS side? It works in android (and it was working in iOS).

Version Number of Plugin: 1.2.1 Device Tested On: Iphone 7 Simulator Tested On: Iphone 6s 10.3 Version of VS: 2017 Community Version of Xamarin: Latest Versions of other things you are using:

Steps to reproduce the Behavior

Execute the following line: var purchases = await CrossInAppBilling.Current.GetPurchasesAsync(ItemType.InAppPurchase);

Expected Behavior

Get purchases.

Actual Behavior

Exception: "Restore Transactions Failed"

Code snippet

var purchases = await CrossInAppBilling.Current.GetPurchasesAsync(ItemType.InAppPurchase);

Screenshotst

jamesmontemagno commented 7 years ago

Does it throw an exception or a specific type of in app billing exception?

Do you have your exception handling code and where it breaks?

jamesmontemagno commented 7 years ago

I wasn't able to reproduce this with 1.2.1;

My steps:

  1. Download from test flight then sign out from app store
  2. go into app and sign in with sand box account
  3. Make purchase
  4. uninstall app
  5. repeat 1 and 2
  6. purchase was restored

Here is my code:

 async Task LoadItemsAsync()
            {
                try
                {
                    IsBusy = true;
                    var connected = await CrossInAppBilling.Current.ConnectAsync();

#if DEBUG
                    CrossInAppBilling.Current.InTestingMode = true;
#endif

                    if(!connected)
                    {
                        await DependencyService.Get<IDialogs>().DisplayAlert("Can't connect", "Unable to connect to the app store, please check internet connection.");
                        return;
                    }

                    IEnumerable<InAppBillingPurchase> purchases = null;
                    try
                    {
                        purchases = await CrossInAppBilling.Current.GetPurchasesAsync(ItemType.InAppPurchase);
                    }
                    catch(Exception ex)
                    {
                               //just incase something goes wrong with internet connection or something
                    }

                    var ids = purchases?.Select(p => p.ProductId) ?? new List<string>();

                    var donate1 = Device.RuntimePlatform == Device.iOS ? "donate0" : "donate1";
                    var donate2 = "donate2";
                    var donate3 = "donate3";
                    var items = await CrossInAppBilling.Current.GetProductInfoAsync(ItemType.InAppPurchase, donate1, donate2, donate3);

                    Items.Clear();
                    foreach (var item in items)
                    {
                        var purchased = ids.Contains(item.ProductId);
                        if(purchased)
                            Settings.ShowAds = false;
                        Items.Add(new IAP
                        {
                            Product = item,
                            Purchased = purchased
                        });
                    }
                }
                catch (InAppBillingPurchaseException purchaseEx)
                {
                    var message = string.Empty;
                    switch (purchaseEx.PurchaseError)
                    {
                        case PurchaseError.AppStoreUnavailable:
                            message = "Currently the app store seems to be unavailble. Try again later.";
                            break;
                        case PurchaseError.BillingUnavailable:
                            message = "Billing seems to be unavailable, please try again later.";
                            break;
                        case PurchaseError.PaymentInvalid:
                            message = "Payment seems to be invalid, please try again.";
                            break;
                        case PurchaseError.PaymentNotAllowed:
                            message = "Payment does not seem to be enabled/allowed, please try again.";
                            break;
                    }

                    if (string.IsNullOrWhiteSpace(message))
                        return;

                    await DependencyService.Get<IDialogs>().DisplayAlert("Purchase Problem", message);

                }
                catch (Exception ex)
                {
                    PluginsForXamarin.Helpers.Utils.LogException(ex, "InAppBilling");
                    await DependencyService.Get<IDialogs>().DisplayAlert("Uh oh", "Something went wrong, but don't worry we captured for analysis! Thanks.");
                }
                finally
                {
                    await CrossInAppBilling.Current.DisconnectAsync();
                    IsBusy = false;
                }
            }
sillerjp commented 7 years ago

Hi James,

My example is pretty much the same and yes it is an InAppBilllingPurchaseException: PurchaseError.RestoreFailed.

Now, I may be doing my test incorrectly I did not have the "InTestingMode". Does that allow me to test in simulator? To be honest I think it would work but Apple testing team does something wrong, since the first time it was approved and everything was working fine. The way I'm trying to test is creating an Ad-Hoc release and trying to use a test user but I get the same error.

Thanks

sillerjp commented 7 years ago

`try { string productId = "productid";

            switch (Device.RuntimePlatform)
            {
                case Device.Android:
                    productId = "productid";
                    break;
                case Device.iOS:
                    productId = "productIdiOS";
                    break;
            }

            var connected = await CrossInAppBilling.Current.ConnectAsync();

            if (!connected)
            {
                UserDialogs.Instance.Alert(Resources.ServiceUnavailable);
                return;
            }

            var purchases = await CrossInAppBilling.Current.GetPurchasesAsync(ItemType.InAppPurchase);
            if (purchases?.Any(p => p.ProductId == productId) ?? false)
            {
                Settings settings = DataRepository.GetSettings();
                settings.Purchased = true;
                DataRepository.UpsertSettings(settings);
                Messenger.Default.Send(new NotificationMessage(this, ""), "RemoveAdvertisement");
            }
            else
            {
                var purchase = await CrossInAppBilling.Current.PurchaseAsync(productId, ItemType.InAppPurchase, "apppayload");
                UserDialogs.Instance.Alert("Purchase: " + purchase);
                if (purchase == null)
                {
                    UserDialogs.Instance.Alert(Resources.PurchaseProcessFailed);
                }
                else
                {
                    Settings settings = DataRepository.GetSettings();
                    settings.Purchased = true;
                    DataRepository.UpsertSettings(settings);
                    Messenger.Default.Send(new NotificationMessage(this, ""), "RemoveAdvertisement");
                }
            }
        }
        catch (Exception)
        {
            UserDialogs.Instance.Alert(Resources.PurchaseProcessFailed);
        }
        finally
        {
            await CrossInAppBilling.Current.DisconnectAsync();
        }`
jamesmontemagno commented 7 years ago

InTestingMode is only for UWP, you can not test on a simulator, you need to test on a real device.

Essentiall, I am getting nothing back from Apple: https://github.com/jamesmontemagno/InAppBillingPlugin/blob/master/src/Plugin.InAppBilling.iOS/InAppBillingImplementation.cs#L116

Perhaps you are popping up a dialog and showing that.. You could just log it. Didsomeone actually buy something?

sillerjp commented 7 years ago

So what happened, is that I uploaded my app and everything was great, 2 purchases were made (One was actually me) then I created an update, again everything worked out. Then last update they are telling me that in app purchase is not working. I did not make any change to the code which is why I find it so strange. I schedule a call with them, maybe they'll give me more information.

So, suppose no purchases have been made. Should an exception be thrown or purchases should be null? What I'm trying to do is first check if there are purchases, if there aren't then make the purchase. Is that handle automatically by apple?

Thanks

jamesmontemagno commented 7 years ago

I would change your code like this currently:

    IEnumerable<InAppBillingPurchase> purchases = null;
                    try
                    {
                        purchases = await CrossInAppBilling.Current.GetPurchasesAsync(ItemType.InAppPurchase);
                    }
                    catch(Exception ex)
                    {
                               //just incase something goes wrong with internet connection or something
                    }

                    if (purchases?.Any(p => p.ProductId == productId) ?? false)

I don't think it will throw null if none come back, but possible.

sillerjp commented 7 years ago

Ok, I'll give it a try and submit for review again. Thank you.

jamesmontemagno commented 7 years ago

Closing this out as I have updated documentation and have tested a bunch. Open a new issue if it happens again so we can investigate further.

PonyOny commented 1 year ago

I'm occasionally getting this error as well PurchaseError.RestoreFailed in iOs sandbox environment, i think it's something to do with apple as this happens sometimes with no changes done, and after some minutes it's working again.

satish-dnv commented 1 year ago

we are also getting the same error from last week and the app being rejected while submitting in App store. This issue is intermittent when we tested with TestFlight builds. Previous submissions were successful with the same code. We haven't changed any code related to InAppBilling plug-in. @jamesmontemagno Could you please let us know what is causing the error and can you please reopen this issue?

nishitgupta3 commented 1 year ago

I'm facing the same issue "Restore Failed" since the past couple of days. I searched everywhere online but did not find anything about this. I thought I was alone facing this. I wonder if this issue is only faced by the ones using InAppBilling plugin. @jamesmontemagno can you please reopen this issue and assist us in this?

monty250 commented 1 year ago

We are having the same issue utilizing the InAppBilling plug-in. After submitting our build to Apple for release to Production, Apple keeps rejecting the build as they keep conveying during their testing they are receiving the "RestoreFailed" error when they try to Sign In to our App. We are not able to reproduce it. Further, we have had no issues like this over the past year and we have made no changes to the Sign In code and have been submitting new builds at least once per month. @jamesmontemagno - please help and provide your feedback.

jamesmontemagno commented 1 year ago

I would dtry https://www.nuget.org/packages/Plugin.InAppBilling/6.7.1-beta may have a fix in there for completing transactions