jamesmontemagno / InAppBillingPlugin

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

iOS: What should happen when server-side receipt verification fails? #496

Closed sachinkanadia closed 2 years ago

sachinkanadia commented 2 years ago

InAppBilling Plugin Version: 5.6.1 Xamarin Forms Version: 5.0.0.2515 OS Concerned: iOS

Hello There,

I am currently implementing in-app purchases for auto-renewing subscriptions within my Xamarin Forms app. So far Android implementation is working in Test however, I am having difficulties with the iOS implementation.

Currently, the flow of purchasing and restoring a subscription on iOS is as follows:

A. Subscribe

  1. Set InAppBillingImplementation.FinishAllTransactions = false;
  2. Call PurchaseAsync().
  3. Verify Apple Receipt using server-side validation.
  4. If the server-side Apple Receipt Validation completes successfully, I call FinalizePurchaseAsync().

B. Restore purchase on the initial, first-time load of the App.

  1. Set InAppBillingImplementation.FinishAllTransactions = false;
  2. Call GetPurchasesAsync().
  3. ??

Herein, at B3 the process gets a little tricky. If A3 failed then FinalizePurchaseAsync() would never have been called. Even so, as I understand it, the IsAcknowledged flag doesn't apply to iOS. So there is no way of knowing if Receipt Validation failed or succeeded on iOS when restoring the subscription.

Please, could someone advise what the correct steps should be?

If I have been unclear or more information is required, please let me know.

Many Thanks

jamesmontemagno commented 2 years ago

Even if you FinalizePurchase the purchase will still show up when you GetPurchasesAsync.

So your steps 3 and 4 would be the same in B.

sachinkanadia commented 2 years ago

Hi @jamesmontemagno,

I have implemented a new server-side validation method for restoring iOS purchases to resolve this issue. It checks the state of the original purchase verification which is saved to my database at the time of purchase. The solution is almost complete except for one issue.

For renewals, against the Sandbox environment, I am receiving the same Transaction Id for each receipt after calling GetPurchasesAsync() within the App. I have flagged this up to Apple and I am awaiting their response.

The odd thing is that when calling https://sandbox.itunes.apple.com/verifyReceipt, from my server, it returns a different Transaction Id for each renewal - which is correct.

I have ensured that I am calling FinalizePurchase on the original purchase and I am quite sure the iOS subscription is set up correctly as it is showing under Auto-Renewing subscriptions in iTunes Connect.

I'd be thankful for any help on this.

sachinkanadia commented 2 years ago

https://github.com/jamesmontemagno/InAppBillingPlugin/blob/master/src/Plugin.InAppBilling/InAppBilling.apple.cs#:~:text=allTransactions.Add(original)%3B

I found this in the inappbilling source code:

    foreach (var trans in SKPaymentQueue.DefaultQueue.Transactions)
    {
        var original = FindOriginalTransaction(trans);
        if (original == null)
            continue;

        allTransactions.Add(original);
    }

It seems as though it only ever adds the original transaction and not renewals?

Many Thanks.