How to differentiate Unity Purchase from Restore Purchase?

398 Views Asked by At

I'm trying to implement unity iap and I need to send PaymentSucceed event to my analytics in order to track purchases!

I'm Calling PaymentSucceed event in my

 public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)

function, but the issue is that when user re-installs application the ProcessPurchase event is called again on android to restore purchases, and sents event for my analytics, but that's not a revenue event, so that's not correct to count it as Payment, can you share please some thoughts how I can understand is it restore or actual payment in the correct way?

here is my ProcessPurchase script

public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    {
        // A consumable product has been purchased by this user.
     
        if (String.Equals(args.purchasedProduct.definition.id, kProductIDNoAds, StringComparison.Ordinal))
        {
            Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
            PlayerPrefs.SetInt("noads",1);
            BannerAdManager.Instance.HideBanner();
            CheckNoAds();
           
        var prodID = args.purchasedProduct.definition.id;
        var price = ReplaceCommas(args.purchasedProduct.metadata.localizedPrice.ToString());
        var currency = args.purchasedProduct.metadata.isoCurrencyCode;
        var receipt = args.purchasedProduct.receipt;
   
        var param = new Dictionary<string, string>();
        param["af_quantity"] = "1";
        param["af_content_type"] = "general";
           
        var recptToJSON = (Dictionary<string, object>)AFMiniJSON.Json.Deserialize(receipt);
        var receiptPayload = (Dictionary<string, object>)AFMiniJSON.Json.Deserialize((string)recptToJSON["Payload"]);
           
        var purchaseData = (string)receiptPayload["json"];
        var signature = (string)receiptPayload["signature"];

        Debug.LogError("Purchase Event Sent Start");
       
        AppsFlyerAndroid appsFlyerAndroid = new AppsFlyerAndroid();
        appsFlyerAndroid.validateAndSendInAppPurchase(
            "111",
            signature,
            purchaseData,
            price,
            currency,
            param,
            this);
       
        Debug.LogError("Purchase Event Sent Finish");
 
       PaymentSucceed(args.purchasedProduct.definition.id,args.purchasedProduct.metadata.isoCurrencyCode,(float)args.purchasedProduct.metadata.localizedPrice,"noads");
 
        }
        // Or ... an unknown product has been purchased by this user. Fill in additional products here....
        else
        {
            Debug.Log(string.Format("ProcessPurchase: FAIL. Unrecognized product: '{0}'", args.purchasedProduct.definition.id));
        }

        // Return a flag indicating whether this product has completely been received, or if the application needs
        // to be reminded of this purchase at next app launch. Use PurchaseProcessingResult.Pending when still
        // saving purchased products to the cloud, and when that save is delayed.
        return PurchaseProcessingResult.Complete;
    }
1

There are 1 best solutions below

1
On

The answer for this (i was looking for this just now) resides in the Product class (from docs):

hasReceipt

Owned Non Consumables and Subscriptions should always have receipts. Consumable's receipts are not persisted between App restarts unless it has a pending transaction. Once a consumable has been acknowledged (ConfirmPendingPurchase) the receipt is removed.

receipt

The purchase receipt for this product, if owned. For consumable purchases, this will be the most recent purchase receipt. Consumable's receipts are not set between app restarts unless it has a pending transaction. Once a consumable has been acknowledged (ConfirmPendingPurchase) the receipt is removed. Receipts is in JSON format.

If you receive a consumable product on restore phase with receipt, its a pending product. If no receipt, its just restoring a previous bought.