[Closed] RestorePurchase on iOS not return ProcessPurchase callback

This happen on iOS with Unity 5.3.3f1

When I try to buy product, call storeController(product); And confirm to buy product

The message popup appear below

“This In-App purchase has already been bought. It will be restore for free”

After I press confirm to restore, nothing happen, there is no callback (That usually have to send back to ProcessPurchase(PurchaseEventArgs args) like android) and not even any error log appear.

I try calling RestorePurchase() method like this

 // Restore purchases previously made by this customer. Some platforms automatically restore purchases. Apple currently requires explicit purchase restoration for IAP.
        public void RestorePurchases()
        {
            // If Purchasing has not yet been set up ...
            if (!IsInitialized())
            {
                // ... report the situation and stop restoring. Consider either waiting longer, or retrying initialization.
                Debug.Log("RestorePurchases FAIL. Not initialized.");
                return;
            }
           
            // If we are running on an Apple device ...
            if (Application.platform == RuntimePlatform.IPhonePlayer ||
                Application.platform == RuntimePlatform.OSXPlayer)
            {
                // ... begin restoring purchases
                Debug.Log("RestorePurchases started ...");
               
                // Fetch the Apple store-specific subsystem.
                var apple = m_StoreExtensionProvider.GetExtension<IAppleExtensions>();
                // Begin the asynchronous process of restoring purchases. Expect a confirmation response in the Action<bool> below, and ProcessPurchase if there are previously purchased products to restore.
                apple.RestoreTransactions((result) => {
                    // The first phase of restoration. If no more responses are received on ProcessPurchase then no purchases are available to be restored.
                    Debug.Log("RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore.");
                });
            }
            // Otherwise ...
            else
            {
                // We are not running on an Apple device. No work is necessary to restore purchases.
                Debug.Log("RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform);
            }
        }

The result boolean is true… but nothing happens after that, no any callback too

Is this a bug or did I miss something? It’s work fine on Android as it will automatically restore by calling ProcessPurchase with the purchased receipt.

If you are not getting a callback it is likely that your Application has already processed that purchase and confirmed it. You can check this by looking at the XCode log, which will show ‘already recorded transaction’. If you uninstall and reinstall the app, then restore, you should get the transaction.

If you want to see what a user owns you should update to the latest store packages and use our new receipt validation and parsing library.

1 Like

@Banderous

Sorry for the late respond, for now we still cannot get the ProcessPurchase callback from restoring transaction for iOS.

Right now the shop shows the all the Consumable products to be purchased correctly from iTunes (around 5-6 ProductIDs).

Sorry, that I didn’t mention that they were Consumable products

And according to this link Unity - Manual: iOS & Mac App Stores

We try the following to RestoreTansaction, the callback of this function return “True” , but there is nothing return to the ProcessPurchase or OnPurchaseFailed.

Reinstalling application is surely not the solution as we always rebuild the code when testing.

And there are also not any ‘already recorded transaction’ text appear in XCode log.

So I’m not sure that is the RestoreTransaction function is unable to Consumable product or not?

(We also try to get the appreceipt from RefreshAppReceipt function, it’s show the appreceipt but we cant get that which transaction it belongs to.)

When trying to purchase the purchase directly (If it wasn’t struck at Pending, the callback ProcessPurchase working correctly.)

But if it is in pending status, the result still show confirm dialog with same message

“This In-App purchase has already been bought. It will be restore for free”

And when confirm, there is no any callback return. Absolutely nothing in XCode log (except active screen method after dialog gone.)

Do you still have any ideas can suggest? Or is it some kind of bugs?.

We awaits for your feedback, please help and thanks in advanced!

:face_with_spiral_eyes::face_with_spiral_eyes::face_with_spiral_eyes::face_with_spiral_eyes:

Ps.We didn’t use Validator in your reference library as we validate the receipt through server and wait callback to ConfirmPendingProduct. So I have no idea to get what user owns with that.

Or is there anyway to get which Consumable product is in Pending status?, as they can only get hasReceipt of Non Consumable and Subscription only. So that we can implement restoring purchase function by ourselves.

*Update

Now we able to get TransactionID, productId from iOS appReceipt and be able to send the neccesary data to confirm with the server but

The problem is that once we try to call

controller.ConfirmPendingPurchase(controller.products.WithID(productId));

It’s appear to be an error with cString null;

Uncaught exception: NSInvalidArgumentException: *** +[NSString stringWithUTF8String:]: NULL cString

Is the reason that it’s got null error is because we try to confirmPendingProduct directly from controller product list?, because that mostly that I search, it’s usually confirm within ProcessPurchase (PurchaseEventArgs args) with args.purchasedProduct

And, is the args.purchasedProduct have different attributes from controller.products.WithID(productId) so that it cannot be confirmed?

RestoreTransactions is not able to restore Consumable products. Only non consumables can be restored, you need to implement your own backup and restore if you want to preserve consumable purchases.

I have the same problem.

on iOS (tested on 9.3.1):

  • purchase a consumable product
  • in the ProcessPurchase callback, I start receipt validation (via server) and return PurchaseProcessingResult.Pending
  • before validation completes (and call to ConfirmPendingPurchase), quit the app
  • relaunch the app

expected result:

  • after Initialize, ProcessPurchase is called again with the pending product, so I can re-validate the receipt and ConfirmPendingPurchase

actual result:

  • ProcessPurchase is never called

  • if I purchase again the same product, iOS displays the “already bought” dialog, and when I return to the app neither ProcessPurchase nor OnPurchaseFailed is called. nothing is logged

I updated to the latest UnityPurchasing package (1.5.0)

@M_R Are you instantiating multiple ConfigurationBuilders? Otherwise, please attach an xcode trace from when you restart the app and reinitialise Unity IAP.

no I use the singleton pattern on my store listener to ensure only one exists, and do its stuff in the constructor. I use multiple PurchasingModule though

I’ll send it to you via MP

the strange thing is, I tried to create an empty project to try to reproduce the bug, built it with the same bundleId, and it restored my product instead. but in my main project it is still stuck without callbacks (on that specific id, other products work) and ios ask for itunes password at startup, before I even call iap init.
what I did:

  • bug report attempt said it restored the product
  • reinstalled main app (attached to xcode)
  • purchased bugged product
  • app stuck forever waiting for callback, ios said thanks for purchase [sandbox]
  • stopped app from xcode
  • restarted app from xcode
  • purchased normal product, it worked
  • purchased bugged product
  • ios said already bought, no callback fired

The problem is with a specific product/user account combination?

If you create a new itunes test user can you buy the product without issue?

I’m having the same problem. After adding logs to UnityPurchasing.m, it hits the updatedTransactions method, but the state is SKPaymentTransactionStatePurchasing so nothing happens

I’ve posted the flow here: [Solved] Unity IAPs ProcessPurchase not calling after purchase, only after app restart - Unity Services - Unity Discussions

@Banderous with another user I managed to purchase the product, but iOS prompted me for the old user password at startup

I forgot to tell that I delay IAP initialization after asset bundle download (to fetch products and associated coins I should give) and the password prompt is before I call Initialize (all this worked when I first implemented UnityIAP in January with 5.3.1)

Just to add to @M_R 's reply - in our case, initialisation is immediate with hardcoded IDs; we just hold off processing in ProcessPurchase() if we haven’t connected/received our products from our server yet.

I also get prompted for the password, but judging by the logs it doesn’t seem to hold anything up. UnityPurchasing.m sends a message to unity with the subject “OnProductsRetrieved”, the apple products as json payload, and the receipt containing the unfinished transaction as the receipt (verified by decoding the base64’d binary). See [Solved] Unity IAPs ProcessPurchase not calling after purchase, only after app restart - Unity Services - Unity Discussions to have an Xcode log of the startup process.

I’ve built a stand-alone with nothing but UnityIAP in it and it seems to work, so what could cause a callback being delayed/not called? Apart from UnityPurchasing.m, Unity IAP is a black box, so it’s hard to debug what’s going on inside it

If I run the UnityIAP standalone project, with the same bundle ID so it picks up on the blocked transaction, the transaction passes and Unity is notified almost before the popup to enter your password to connect to the iTunes Store is shown, so I’m not even sure what the point of that one is

Sorry, I tell a lie. If I run the UnityIAP standalone project, I see that I have a transaction waiting, but no callback is ever called (see attached log)

2638443–185633–iOS_start_with_failed_purchase_standalone.txt (46.6 KB)

adding again:

  • the same account in another device works
  • another account in the same device works
  • logging in again with the problematic account/device deadlocks
  • when asked for password, actually logging in or pressing cancel does no difference
  • in the empty/IAP project, the password prompt happens after ProcessPurchase call, and pressing cancel restores the product anyways
  • if I Debug.Log(builder.Configure().appReceipt); i have an actual receipt containing the pending product

@M_R I have occasionally observed problematic device/account combinations in the Apple sandbox which have resolved themselves after several days. I suggest you move to a new sandbox test user.

@Banderous our app is live and we received a report from one user that is affected by this problem. I hope he isn’t using a sandbox account :stuck_out_tongue:

EDIT: i replicated the problem with the other test account (purchase → kill app → open app → purchase again says restored and no callback)

I suggest you file a TSI with Apple.

with

-(void) addTransactionObserver {
    [[SKPaymentQueuedefaultQueue] addTransactionObserver:self];
    NSLog(@"Debug UnityIAP: force update transactions");
    [selfpaymentQueue:[SKPaymentQueuedefaultQueue] updatedTransactions:[SKPaymentQueuedefaultQueue].transactions];
}

I managed to get the ProcessPurchase after init, but I don’t know if it’s safe for the normal case

1 Like