Search Unity

Unity IAP restore Subscription on IOS

Discussion in 'Unity IAP' started by alex1312, Mar 5, 2019.

  1. alex1312

    alex1312

    Joined:
    Jan 3, 2015
    Posts:
    16
    I have problem with restore Subscription on IOS. When I try restore In-App Unity call ProcessPurchase in IStoreListener a lot of times for subscription.
    I use Unity 2018.3.0f2, Unity IAP 1.20.1.

    Code (CSharp):
    1.  internal sealed class StoreInternal : IStoreListener
    2.     {
    3.         public IStoreExtensionProvider ExtensionProvider { get; private set; }
    4.  
    5.         private readonly IDictionary<Product, StoreItem> shopItems = new Dictionary<Product, StoreItem>();
    6.  
    7.         private const string Prefix = "";
    8.         private const string GooglePostfix = "";
    9.         private const string ApplePostfix = "";
    10.  
    11.         private IStoreController storeController; // Reference to the Purchasing system.
    12.         private IExtensionProvider storeExtensionProvider;
    13.         private string googlePlayKey;
    14.  
    15.         private List<StoreItem> storeItems;
    16.  
    17.         public void OnInitializeFailed(InitializationFailureReason error)
    18.         {
    19.             // Purchasing set-up has not succeeded. Check error for reason. Consider sharing this reason with the user.
    20.             Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
    21.         }
    22.  
    23.         public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    24.         {
    25.             // Purchasing has succeeded initializing. Collect our Purchasing references.
    26.             Debug.Log("Store initialization: PASS");
    27.  
    28.             // Overall Purchasing system, configured with products for this application.
    29.             this.storeController = controller;
    30.             // Store specific subsystem, for accessing device-specific store features.
    31.             this.storeExtensionProvider = extensions;
    32.  
    33.             ExtensionProvider = new StoreExtensionProvider(storeExtensionProvider);
    34.  
    35.             foreach (var item in storeItems)
    36.             {
    37.                 var product = storeController.products.WithID(item.Id);
    38.  
    39.                 if (product != null)
    40.                 {
    41.                     shopItems[product] = item;
    42.                     item.Product = product;
    43.                 }
    44.             }
    45.         }
    46.  
    47.         public void Start(List<StoreItem> storeItems)
    48.         {
    49.             // If we haven't set up the Unity Purchasing reference
    50.             if (storeController == null)
    51.             {
    52.                 // Begin to configure our connection to Purchasing
    53.                 this.storeItems = storeItems;
    54.                 InitializePurchasing();
    55.             }
    56.         }
    57.  
    58.         public void InitializePurchasing()
    59.         {
    60.             // If we have already connected to Purchasing ...
    61.             if (IsInitialized())
    62.             {
    63.                 return;
    64.             }
    65.  
    66.             // Create a builder, first passing in a suite of Unity provided stores.
    67.             var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    68.  
    69.             googlePlayKey ="googlePlayKey";
    70.             builder.Configure<IGooglePlayConfiguration>().SetPublicKey(this.googlePlayKey);
    71.  
    72.             foreach (var shopItem in storeItems)
    73.             {
    74.                 builder.AddProduct(
    75.                     shopItem.Id,
    76.                     ToProductType(shopItem.Type),
    77.                     new IDs
    78.                     {
    79.                         {Prefix + shopItem.Id + ApplePostfix, AppleAppStore.Name},
    80.                         {Prefix + shopItem.Id + GooglePostfix, GooglePlay.Name},
    81.                     }
    82.                 );
    83.             }
    84.  
    85.             // Kick off the remainder of the set-up with an asynchrounous call, passing the configuration and this class' instance. Expect a response either in OnInitialized or OnInitializeFailed.
    86.             UnityPurchasing.Initialize(this, builder);
    87.         }
    88.  
    89.  
    90.         public bool IsInitialized()
    91.         {
    92.             // Only say we are initialized if both the Purchasing references are set.
    93.             return storeController != null && storeExtensionProvider != null;
    94.         }
    95.  
    96.         public Product GetProduct(string productId)
    97.         {
    98.             return storeController.products.WithID(productId);
    99.         }
    100.  
    101.         public void BuyProductId(Product product)
    102.         {
    103.             // If the stores throw an unexpected exception, use try..catch to protect my logic here.
    104.             try
    105.             {
    106.                 // If Purchasing has been initialized ...
    107.                 if (IsInitialized())
    108.                 {
    109.                     // ... look up the Product reference with the general product identifier and the Purchasing system's products collection.
    110.                     //var product = this.storeController.products.WithID(productId);
    111.  
    112.  
    113.                     // If the look up found a product for this device's store and that product is ready to be sold ...
    114.                     if (product != null && product.availableToPurchase)
    115.                     {
    116.                         Debug.Log($"Purchasing product asychronously: '{product.definition.id}'");
    117.                         // ... buy the product. Expect a response either through ProcessPurchase or OnPurchaseFailed asynchronously.
    118.                         this.storeController.InitiatePurchase(product);
    119.                     }
    120.                     // Otherwise ...
    121.                     else
    122.                     {
    123.                         // ... report the product look-up failure situation
    124.                         Debug.Log(
    125.                             "BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
    126.                     }
    127.                 }
    128.                 // Otherwise ...
    129.                 else
    130.                 {
    131.                     // ... report the fact Purchasing has not succeeded initializing yet. Consider waiting longer or retrying initiailization.
    132.                     Debug.Log("BuyProductID FAIL. Not initialized.");
    133.                 }
    134.             }
    135.             // Complete the unexpected exception handling ...
    136.             catch (Exception e)
    137.             {
    138.                 // ... by reporting any unexpected exception for later diagnosis.
    139.                 Debug.Log("BuyProductID: FAIL. Exception during purchase. " + e);
    140.             }
    141.         }
    142.  
    143.         public void RestorePurchases()
    144.         {
    145.             // If Purchasing has not yet been set up ...
    146.             if (!IsInitialized())
    147.             {
    148.                 // ... report the situation and stop restoring. Consider either waiting longer, or retrying initialization.
    149.                 Debug.Log("RestorePurchases FAIL. Not initialized.");
    150.                 return;
    151.             }
    152.  
    153.             // If we are running on an Apple device ...
    154.             if (Application.platform == RuntimePlatform.IPhonePlayer ||
    155.                 Application.platform == RuntimePlatform.OSXPlayer)
    156.             {
    157.                 // ... begin restoring purchases
    158.                 Debug.Log("RestorePurchases started ...");
    159.  
    160.                 // Fetch the Apple store-specific subsystem.
    161.                 var apple = this.storeExtensionProvider.GetExtension<IAppleExtensions>();
    162.                 // 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.
    163.                 apple.RestoreTransactions(result =>
    164.                 {
    165.                     // The first phase of restoration. If no more responses are received on ProcessPurchase then no purchases are available to be restored.
    166.                     Debug.Log("RestorePurchases continuing: " + result +
    167.                               ". If no further messages, no purchases available to restore.");
    168.                 });
    169.             }
    170.             // Otherwise ...
    171.             else
    172.             {
    173.                 // We are not running on an Apple device. No work is necessary to restore purchases.
    174.                 Debug.Log("RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform);
    175.             }
    176.         }
    177.  
    178.         public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    179.         {
    180.             Debug.Log($"Processing purchase...");
    181.             var product = args.purchasedProduct;
    182.  
    183.             Debug.Log($"hasReceipt = '{product.hasReceipt}'");
    184.             Debug.Log($"receipt = '{product.receipt}'");
    185.             Debug.Log($"transactionID = '{product.transactionID}'");
    186.             Debug.Log($"availableToPurchase = '{product.availableToPurchase}'");
    187.  
    188.             Debug.Log($"definition.id = '{product.definition?.id}'");
    189.             Debug.Log($"definition.type = '{product.definition?.type}'");
    190.             Debug.Log($"definition.payout.data = '{product.definition?.payout?.data}'");
    191.             Debug.Log($"definition.payout.storeSpecificId = '{product.definition?.storeSpecificId}'");
    192.  
    193.             var item = shopItems[product];
    194.             item.GiveToPlayer();
    195.             return PurchaseProcessingResult.Complete;
    196.         }
    197.      
    198.         public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    199.         {
    200.             // A product purchase attempt did not succeed. Check failureReason for more detail. Consider sharing this reason with the user.
    201.             Debug.Log(
    202.                 $"OnPurchaseFailed: FAIL. Product: '{product.definition.storeSpecificId}', PurchaseFailureReason: {failureReason}");
    203.         }
    204.      
    205.          private ProductType ToProductType(StoreItemType type)
    206.         {
    207.             switch (type)
    208.             {
    209.                 case StoreItemType.Consumable:
    210.                     return ProductType.Consumable;
    211.                 case StoreItemType.NonConsumable:
    212.                     return ProductType.NonConsumable;
    213.                 case StoreItemType.Subscription:
    214.                     return ProductType.Subscription;
    215.                 default:
    216.                     throw new ArgumentOutOfRangeException(nameof(type), type, null);
    217.             }
    218.         }
    219.     }
    and have strange logs from XCode
    2019-03-05 16:04:50.465804+0200 powerminers[7223:392201] UnityIAP UnityEarlyTransactionObserver: Created
    2019-03-05 16:04:50.466701+0200 powerminers[7223:392201] UnityIAP UnityEarlyTransactionObserver: Registered for lifecycle events
    2019-03-05 16:04:51.498005+0200 powerminers[7223:392201] UnityIAP UnityEarlyTransactionObserver: Added to the payment queue


    2019-03-05 16:05:04.087213+0200 powerminers[7223:392201] UnityIAP: Requesting 8 products
    2019-03-05 16:05:04.123641+0200 powerminers[7223:392201] UnityIAP: Requesting product data...


    2019-03-05 16:05:05.654351+0200 powerminers[7223:392201] UnityIAP: Received 8 products
    2019-03-05 16:05:05.656494+0200 powerminers[7223:392201] UnityIAP: No localized title for: com.tatemgames.powerminers.weekly. Have your products been disapproved in itunes connect?
    2019-03-05 16:05:05.656567+0200 powerminers[7223:392201] UnityIAP: No localized description for: com.tatemgames.powerminers.weekly. Have your products been disapproved in itunes connect?
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733931
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 13:35:04
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 13:38:04
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733897
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 13:38:04
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 13:41:04
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733507
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 13:41:04
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/18/2019 13:44:04
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733894
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 13:44:04
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 13:47:04
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733911
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 13:47:04
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 13:50:04
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733973
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 13:50:04
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 13:53:04
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733915
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 15:40:29
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 15:43:29
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733958
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 15:43:29
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 15:46:29
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733976
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 15:46:29
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 15:49:29
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733940
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 15:49:29
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 15:52:29
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733978
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 15:52:29
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 15:55:29
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733469
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 15:55:29
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/18/2019 15:58:29
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733981
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 16:23:18
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 16:26:18
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733907
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/18/2019 16:27:41
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/18/2019 16:30:41
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733485
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 09:41:49
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/19/2019 09:44:49
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733930
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 09:44:49
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 09:47:49
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733942
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 09:47:49
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 09:50:49
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733980
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 09:50:49
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 09:53:49
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733982
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 09:53:49
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 09:56:49
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733920
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 09:56:49
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 09:59:49
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733488
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 10:14:17
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/19/2019 10:17:17
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733927
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 11:06:32
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 11:09:32
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733955
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 11:15:44
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 11:18:44
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733935
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 11:53:14
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 11:56:14
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733904
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 11:56:14
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 11:59:14
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733962
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 11:59:14
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 12:02:14
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733932
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 12:59:00
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/19/2019 13:02:00
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733513
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/19/2019 13:04:00
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/19/2019 13:07:00
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733908
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 08:55:33
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/20/2019 08:58:33
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733925
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 08:58:33
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/20/2019 09:01:33
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733510
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 09:01:33
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/20/2019 09:04:33
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733910
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 09:04:33
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/20/2019 09:07:33
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733928
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 09:07:33
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/20/2019 09:10:33
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733977
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 09:10:33
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/20/2019 09:13:33
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733525
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 13:07:13
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/20/2019 13:10:13
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733473
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 13:10:13
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/20/2019 13:13:13
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733983
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 13:13:13
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/20/2019 13:16:13
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733900
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 13:16:13
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/20/2019 13:19:13
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733975
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 13:19:13
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/20/2019 13:22:13
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733969
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/20/2019 13:22:13
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/20/2019 13:25:13
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733449
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 08:46:05
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/21/2019 08:49:05
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733938
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 08:49:05
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 08:52:05
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733943
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 08:52:05
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 08:55:05
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733968
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 08:55:05
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 08:58:05
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733905
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 08:58:05
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 09:01:05
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733913
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 09:01:05
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 09:04:05
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733924
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 09:48:37
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 09:51:37
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733906
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 10:37:28
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 10:40:28
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733961
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 11:23:29
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 11:26:29
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733491
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 11:26:29
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/21/2019 11:29:29
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733902
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 11:29:29
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 11:32:29
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733945
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 11:32:29
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 11:35:29
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733948
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 11:37:15
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 11:40:15
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733939
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 11:47:28
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 11:50:28
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733917
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 12:31:37
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 12:34:37
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733971
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 13:20:25
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 13:23:25
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733960
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 13:24:51
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 13:27:51
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733923
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 13:36:20
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 13:39:20
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733921
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 13:39:20
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 13:42:20
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733950
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 13:50:56
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 13:53:56
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733440
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 14:27:45
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/21/2019 14:30:45
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733895
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 14:35:04
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 14:38:04
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733919
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 15:17:02
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 15:20:02
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733970
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 15:21:55
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 15:24:55
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733448
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 15:26:26
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 02/21/2019 15:29:26
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733953
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 15:30:01
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 15:33:01
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733957
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 15:34:44
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 15:37:44
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733952
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/21/2019 16:12:11
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/21/2019 16:15:11
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733896
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/22/2019 07:35:31
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/22/2019 07:38:31
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733967
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/22/2019 07:38:31
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/22/2019 07:41:31
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733916
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/22/2019 07:41:31
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/22/2019 07:44:31
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733899
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/22/2019 07:44:31
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/22/2019 07:47:31
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733941
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/22/2019 07:47:31
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/22/2019 07:50:31
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733964
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/22/2019 07:50:31
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/22/2019 07:53:31
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733901
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/22/2019 07:55:22
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/22/2019 07:58:22
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733936
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 02/22/2019 07:59:40
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 02/22/2019 08:02:40
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733934
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 09:26:07
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 09:29:07
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733929
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 09:29:07
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 09:32:07
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733512
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 09:32:07
    originalPurchaseDate: 03/05/2019 12:37:14
    subscriptionExpirationDate: 03/05/2019 09:35:07
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733912
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 09:35:07
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 09:38:07
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733949
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 09:38:07
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 09:41:07
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733979
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 10:43:53
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 10:46:53
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733898
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 11:06:04
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 11:09:04
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733926
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 11:56:58
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 11:59:58
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733956
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 11:59:58
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 12:02:58
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733909
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 12:02:58
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 12:05:58
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733944
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 12:05:58
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 12:08:58
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733954
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 12:32:16
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 12:35:16
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733824
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 12:38:16
    originalPurchaseDate: 03/05/2019 12:38:17
    subscriptionExpirationDate: 03/05/2019 12:41:16
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507749056
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 13:22:19
    originalPurchaseDate: 03/05/2019 13:22:19
    subscriptionExpirationDate: 03/05/2019 13:25:19
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507750561
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 13:27:45
    originalPurchaseDate: 03/05/2019 13:27:46
    subscriptionExpirationDate: 03/05/2019 13:30:45
    productID: com.tatemgames.powerminers.weekly
    transactionID: 1000000507733918
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 03/05/2019 09:24:07
    originalPurchaseDate: 03/05/2019 12:38:31
    subscriptionExpirationDate: 03/05/2019 09:26:07
    Store initialization: PASS
    TatemGames.Core.Shop.Store.StoreInternal:OnInitialized(IStoreController, IExtensionProvider)
    UnityEngine.Purchasing.PurchasingManager:CheckForInitialization()
    UnityEngine.Purchasing.PurchasingManager:OnProductsRetrieved(List`1)
    UnityEngine.Purchasing.AppleStoreImpl:OnProductsRetrieved(String)
    UnityEngine.Purchasing.Extension.UnityUtil:Update()
    (Filename: ./Runtime/Export/Debug.bindings.h Line: 45)
    UnityIAP: Promo interface is available for 8 items
    UnityEngine.Purchasing.Promo:provideProductsToAds(HashSet`1)
    UnityEngine.Purchasing.AppleStoreImpl:OnProductsRetrieved(String)
    UnityEngine.Purchasing.Extension.UnityUtil:Update()
    (Filename: ./Runtime/Export/Debug.bindings.h Line: 45)
    2019-03-05 16:05:05.925843+0200 powerminers[7223:392201] UnityIAP: Add transaction observer
    2019-03-05 16:05:05.926023+0200 powerminers[7223:392201] UnityIAP UnityEarlyTransactionObserver: Request to initiate queued payments

    @JeffDUnity3D I need your help =)
     
    Last edited: Mar 5, 2019
  2. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Likely once for every renew! Subscriptions renew fast in the Sandbox, test accordingly.
     
  3. alex1312

    alex1312

    Joined:
    Jan 3, 2015
    Posts:
    16
    So is it normal? Can I change it? Because, I need restore only 1 current subscription. When subscription expired I cant restore any subscription, but if I bought it I will restore more then 90 times.
     
  4. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes it is expected. Subscriptions can expire in 5 minutes, keep that in mind for your testing. If you wait 5 minutes, you'll see another ProcessPurchase, but definitely not 90. How long are you waiting to test, after making a purchase? And can you elaborate, "when subscription expired I can't restore any subscription", this is not correct. Only the expired subscription would not restore.
     
  5. alex1312

    alex1312

    Joined:
    Jan 3, 2015
    Posts:
    16
    I know we use 1 week subscription and it's equal to 3 min at sandbox.
    Step 1. Open app and buy subscription.
    Step 2. Open another app with same Apple id.
    Step 3. Restore subscription on second device. As result Unity will restore all my subscriptions for all time and it's more than 90 and ProcessPurchase will call more than 90 times.
     
  6. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Your steps are not clear. What other app on step 2? Sorry, how is this relevant? And the multiple restore only happens on the second device? It does not happen on the first device? If the second device has no purchase history, then it would be expected to restore all products, and for each subscription renew. And I suspect it's not always 90 times, please try to be more specific and test with a new user across both devices. And please answer my other questions when you can.
     
  7. alex1312

    alex1312

    Joined:
    Jan 3, 2015
    Posts:
    16
    Excuse me, I meant open the same app but on the other device.
    Please don't pay attention on this, it really doesn't matter wich device is used for restore, behavior is the same.
    0. Create a new apple id account
    1. Open the app and buy subscription.
    2. Waite for transaction to be finished, it's about 20-30 seconds.
    3. Restore In-app
    As result ProcessPurchase is called once, but if wait till subcription is expired (3 minutes in my case) and repeat 1-3 steps, ProcessPurchase will be called 2 times.
    And if we try restore more times we will receive more ProcessPurchase calls. (On my old account it's more than 90+ times for 1 restore call)
     
  8. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, this is expected behavior in the Apple Sandbox environment.
     
  9. alex1312

    alex1312

    Joined:
    Jan 3, 2015
    Posts:
    16
    So in real In-App purchases it will be called only once for all your expired and current subscriptions?
     
  10. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    No, all receipts will be restored. But obviously not as many! A user can have multiple subscriptions, perhaps one to disable ads, and another for 1 month of music. You would of course need each of these to restore. And you will receive a ProcessPurchase for each subscription period renew. You only need one ProcessPurchase to unlock a product! If you receive another ProcessPurchase, then unlock it again (if you are not saving a Boolean or similar) with no harm done. The product ends up being unlocked. Enable the product 90 times if you need, and you're done.
     
  11. alex1312

    alex1312

    Joined:
    Jan 3, 2015
    Posts:
    16
    But if this subscription has already expired, why would you try restore it?
     
  12. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    As I've mentioned, expired subscriptions won't restore. Only currently active products will restore.
     
  13. alex1312

    alex1312

    Joined:
    Jan 3, 2015
    Posts:
    16
    But problem is that ProcessPorchase would be called for all excited subscription (one type) if this subscription is active. So it seems like Unity tries to restore In-App for all subscription history.
     
  14. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    A subscription cannot be both Expired and Active at the same time. It's either one. If it's Active, it will be restored, and likely all the previous receipts for this same product even if it was at one time expired, but now is renewed and Active. And please elaborate "all excited [expired] subscriptions of one type". What is a "type"? Each subscription is a separate product.
     
  15. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    It might help if you describe the user impact. Assume I'm a user of your app, with two subscriptions for two separate products, one is active and another expired, and I wish to Restore my purchases. What issue would I see?
     
  16. alex1312

    alex1312

    Joined:
    Jan 3, 2015
    Posts:
    16
    We have only 1 subscription and when I said "type" I meant subscription with same in-app id. So, we have subscription with in-app id like: com.companyname.productname.weekly.
    0. Create new Apple account.
    1. Open app and buy subscription.
    2. Waite 3 minutes, because we use 1 week subscription and it is equals 3 minutes in sandbox.
    3. Apple auto renew this subscription, and create new transaction with will have new transactionId and same originalTransactionIdentifier (in AppleInAppPurchaseReceipt)
    If we do 2 and 3 steps few times we will have few new in-app transactions with new transactionIds.
    for example:

    current date and time = 07/03/2019 11:27:04
    I buy subscription for first time and have:
    productID: com.companyname.productname.weekly
    transactionID: 1000000507750661
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 07/03/2019 11:27:04
    subscriptionExpirationDate: 07/03/2019 11:30:04

    wait 3 minutes
    productID: com.companyname.productname.weekly
    transactionID: 1000000507750612
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 07/03/2019 11:30:04
    subscriptionExpirationDate: 07/03/2019 11:33:04

    wait another 3 minutes
    productID: com.companyname.productname.weekly
    transactionID: 1000000507750594
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 07/03/2019 11:33:04
    subscriptionExpirationDate: 07/03/2019 11:36:04

    wait another 3 minutes
    productID: com.companyname.productname.weekly
    transactionID: 1000000507750624
    originalTransactionIdentifier: 1000000503392830
    purchaseDate: 07/03/2019 11:36:04
    subscriptionExpirationDate: 07/03/2019 11:39:04

    wait 1 minute, so current time 07/03/2019 11:37:04 and current subscription is active. Restore in-app and Unity will call ProcessPurchase 4 times for product with in-app id com.companyname.productname.weekly
     
  17. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    A subscription with same in-app id is the same product, not a separate product. There are no "types" where multiple products share the same product ID. The steps that you show are expected, as mentioned. At the end of these restore operations, you will be done and you'll receive the Restore Complete callback. And if I'm the user, I get the subscription whether ProcessPurchase is called once or 4 times. You definitely do not want to pop up a dialog to the user saying "Thank you for your purchase" on each ProcessPurchase, they should fire silently from the user perspective.
     
  18. alex1312

    alex1312

    Joined:
    Jan 3, 2015
    Posts:
    16
    But we use validation server for in-app and it's bad sent to him alot "validation requests". If we sent 4 it doesn't so bad, but we use 1 week subscription and it's 48 subscription reactivations per year.
     
  19. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    That's correct, but not sure why that is an issue? If your user plays once a week, they will only get one ProcessPurchase per week. It's up to Apple if they send out the event on each renew, so you might want to contact them, we are just a pass through service for the respective stores. We don't have any control over this behavior.
     
  20. alex1312

    alex1312

    Joined:
    Jan 3, 2015
    Posts:
    16
    I just wanted to make sure, that it's not Unity bug and we can't change it.
     
  21. Lurendium

    Lurendium

    Joined:
    Nov 25, 2016
    Posts:
    8
    Hey @JeffDUnity3D, Recently I updated IAP to 1.23 and Xcode to 11.2.1 and for some reason in the sandbox environment after I buy a subscription then wait 5 min (when the first renewal should be happed) I restart the app and can't get a product with receipt anymore for some reason.

    Code:
    Code (CSharp):
    1. foreach (var item in StoreController.products.all)
    2.                 {
    3.                     if (item.availableToPurchase)
    4.                     {
    5.                         DPSubLogger.Log(ClassName, string.Join(" - ",
    6.                             new[]
    7.                             {
    8.                                 item.definition.id,
    9.                                 item.metadata.localizedTitle,
    10.                                 item.metadata.localizedDescription,
    11.                                 item.metadata.isoCurrencyCode,
    12.                                 item.metadata.localizedPrice.ToString(),
    13.                                 item.metadata.localizedPriceString,
    14.                                 item.transactionID,
    15.                                 item.receipt
    16.                             }));
    17.  
    18.                         if (item.receipt != null)
    all items have null receipt :(

    This was tested on IOS 12 and 13

    On top of that if I try to restart purchases everything works ok till next renewal.
     
  22. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    If it's a subscription and already purchased, it wouldn't be available for purchase again. So I would expect availableToPurchase to be false in your test.
     
  23. hgbimonti

    hgbimonti

    Joined:
    Dec 31, 2008
    Posts:
    19
    Yes, @Lurendium @JeffDUnity3D , same here.

    It was working fine but since this month for some reason the receipt is not been updated after the 5 minutes expiration. Only after all the automatic test renews are done and purchasing the item again I can get the new receipt and see the history of renews. Apparently it only happens on Sandbox.

    Have you found any fix for that?
     
  24. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    This would be an Apple issue, their Sandbox environment can be slow sometimes. And you mention "Purchase the item again"? You can't purchase a subscription a second time, if the first is still valid. The logs may tell more https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/
     
  25. hgbimonti

    hgbimonti

    Joined:
    Dec 31, 2008
    Posts:
    19
    Sorry, I meant purchasing again after all the automatic renews are done and the subscription is expired, and so I could buy it again and see the renews history of the previous purchase.
     
    Lurendium likes this.
  26. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Got it. So this started happening last month, and you didn't release a new version of your app? Again, this would point to Apple. User transactions do not go through any Unity services, purchases go directly from the client device to the respective stores. So any change in behavior, without an app release, would point to Apple. And could be a behavior in their Sandbox only.
     
    Lurendium and hgbimonti like this.
  27. Lurendium

    Lurendium

    Joined:
    Nov 25, 2016
    Posts:
    8
    Hi @JeffDUnity3D

    Thanks for following this up.

    In my company, we currently have 3 products(games) with a subscription IAP model (Supported platforms: iOS, Google, Amazon, Huwai 3.0 and Oppo), and we update them with new content every month(we always keep Unity IAP plugin up to date too). these problems with Apple Sandbox can be very problematic for QA as without previews receipts we can even check if the introductory offer works properly as in the current sandbox problem, the sandbox user will always be a new user :p

    Our QA team tested older builds that previously don't have this issue and had an older Unity IAP version, they stop getting a receipt, so we can confirm that this is something on the Apple side. The only thing that we can be sure of is if this is sandbox only.

    Once more thanks for the update and if I have any more information on this I will keep you guys updated here.
     
    hgbimonti likes this.
  28. itierney

    itierney

    Joined:
    Jan 28, 2019
    Posts:
    27
    Sorry to spam you @JeffDUnity3D but I'm not getting any replies on the forum of from Support. This is currently the only issue blocking my iOS app store submission.

    When you add an IAP Restore button, the preferences to set a function disappear.
    Also when I look at the IAP rockets example the restore button isn't even a IAP button!

    So just to clarify:

    1. When I use an IAP_restore button do I have to write additional code to trigger a restore? (Many tutorial say you don;t)
    2. If so where do I put this code and how to I link it to the IAP button (all options disappear when you set the button type to restore!)
    3. At the moment I am just creating an IAP button and setting it to restore (no additional code). When I look at the console while running on an iPhone it prints the following but nothing happens...so iOS sign in..nothing!

    2022-11-05 19:31:46.901607+0000 PocketBuddha[67035:5564595] UnityIAP: RestorePurchase

    2022-11-05 19:31:47.922061+0000 PocketBuddha[67035:5564595] UnityIAP: PaymentQueueRestoreCompletedTransactionsFinished"
     
  29. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    230
    Hello,

    Based on your logs, the restore transaction seems to be called properly and you get notified by Apple when it's finished.

    A few ideas to debug this on your end:
    -ProcessPurchase should be called for each restored transaction, are those being handled properly?
    -OnPurchaseFailed will be invoked if it failed
    -In IStoreCallback, if the transaction log is used (true by default), it's possible that there's nothing to restore since those restored transactions are identical to those already processed.

    You can also consult the documentation about Restoring Transactions


    Also please make a new thread in the future instead of reviving old ones. If we end up missing your thread, bump it and we will do our best to answer it.
     
  30. itierney

    itierney

    Joined:
    Jan 28, 2019
    Posts:
    27
    Thanks Yannick_Denis,
    Sorry for the spam but I did create a new thread and contact support...but no answer.

    "-ProcessPurchase should be called for each restored transaction, are those being handled properly?" - I'm not sure what you mean, as all I'm doing is creating the restore button, I haven't added any code myself.

    Could you address my questions above please?

    I'll write them again:
    • When I use an IAP_restore button do I have to write additional code to trigger a restore? (Many tutorial say you don;t)
    • If so where do I put this code and how to I link it to the IAP button (all options disappear when you set the button type to restore!)
    • At the moment I am just creating an IAP button and setting it to restore (no additional code). When I look at the console while running on an iPhone it prints the following but nothing happens...so iOS sign in..nothing!
     
  31. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    230
    I answered in the quote above.

    It seems the restore purchase is being sent to Apple correctly and you get an answer from them.
    The next step is to determine if Apple sent transactions and if they are being handled correctly.

    Are you testing on sandbox or on a live application? On Sandbox, there's no login window pop-up.
    Do you have any purchases that need to be restored? If all your purchases are up-to-date, then there's nothing to restore. Consumables are also not restored so make sure you're testing with non-consumable or subscription.

    You should normally be seeing UnityIAP: Finishing transaction for each restored transaction before the UnityIAP: PaymentQueueRestoreCompletedTransactionsFinished
     
    itierney likes this.
  32. itierney

    itierney

    Joined:
    Jan 28, 2019
    Posts:
    27
    Thanks for you help with this!

    When you say "The next step is to determine if Apple sent transactions and if they are being handled correctly", that seems to imply that I need to do something else?

    To answer your questions:
    • I am testing off TestFlight.
    • Yes I make a purchase first, so there is something to restore.
    • I only have one non-consumable to restore.
    Here's what I've done to test the restore button:
    - Downloaded off test flight.
    - Bought app
    - Deleted and re-downloaded
    - Pressed restore (nothing happens and my purchase is not restored)

    Thanks!
     
  33. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    230
    This might be a Sandbox/TestFlight issue with the account being used since there's a main and sandbox account.
    Could you try these steps to see if they help?
    1. Buy non-consumable
    2. Uninstall game
    3. Check that the main user is logged in, but Log OUT the sandbox user.
    4. Reinstall game
    5. Tap restore purchase; a system popup it will ask for credentials, enter the ones for the main user who made the purchase.

    Another thing to verify, when you reinstall the application, do you see any Finishing transaction in your logs before doing the restore purchase? If it does, this means Apple already restored it for you.

    If this doesn't work, could you include your logs?
     
  34. itierney

    itierney

    Joined:
    Jan 28, 2019
    Posts:
    27
    Ok,
    Question, when sandbox testing, do I have to install the app via Xcode (rather that testflight)?

    To be clear, I was initially logged in as a regular, (non developer) "main user"...and it wasn't even asking me to login to my apple account
    .
    I made some progress:
    I created a sandbox user. Pressed restore. It did ask me my apple login.
    After I logged in, nothing happened.

    • I then reinstalled the app,
    • used my Sandbox user to purchase the app.
    • Reinstalled it.
    • Pressed Restore
    • Didnt seem to restore
    Got this log:
    Purchase not correctly processed for product "com.buddha.BudBud.unlock". Add an active IAPButton to process this purchase, or add an IAPListener to receive any unhandled purchase events.

    UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object)

    UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])

    UnityEngine.Logger:Log(LogType, Object)

    UnityEngine.Debug:LogError(Object)

    UnityEngine.Purchasing.CodelessIAPStoreListener:processPurchase(PurchaseEventArgs)

    UnityEngine.Purchasing.StoreListenerProxy:processPurchase(PurchaseEventArgs)

    UnityEngine.Purchasing.PurchasingManager:processPurchaseIfNew(Product)

    UnityEngine.Purchasing.PurchasingManager:OnPurchaseSucceeded(String, String, String)

    UnityEngine.Purchasing.JSONStore:OnPurchaseSucceeded(String, String, String)

    UnityEngine.Purchasing.AppleStoreImpl:OnPurchaseSucceeded(String, String, String)

    UnityEngine.Purchasing.AppleStoreImpl:processMessage(String, String, String, String)

    UnityEngine.Purchasing.<>c__DisplayClass48_0:<MessageCallback>b__0()

    System.Action:Invoke()

    UnityEngine.Purchasing.Extension.UnityUtil:Update()


    2022-11-16 16:17:13.252847+0000 PocketBuddha[31569:10124675] UnityIAP: PaymentQueueRestoreCompletedTransactionsFinished
     
  35. Nimdanet

    Nimdanet

    Joined:
    Jan 19, 2013
    Posts:
    38
    I'm having the same problem. I'm trying to get the log from the device to see if matches the @itierney . My restore button just do nothing when clicked.

    I'm using Unity 2020.3.33f1 and purchasing plugin v4.4.1. I'm using Codeless Purchasing.

    (Edit)
    Here is my logs:

    Code (CSharp):
    1. 2022-11-16 14:55:47.043501-0300 KickGoal[610:10991] UnityIAP: Restore transactions
    2. 2022-11-16 14:55:47.043707-0300 KickGoal[610:10991] UnityIAP: RestorePurchase
    3. 2022-11-16 14:55:47.963335-0300 KickGoal[610:10991] UnityIAP: PaymentQueueRestoreCompletedTransactionsFinished
    (Edit 2)
    Taking a look at IAPButton.cs there is this method that is called after restoring:

    Code (CSharp):
    1. void OnTransactionsRestored(bool success)
    2. {
    3.       //TODO: Add an invocation hook here for developers.
    4. }
    Should I be concerned with this TODO? hahahha
     
    Last edited: Nov 16, 2022
  36. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    230
    You will need to add an IAP Button for each product or an IAP Listener to the scene containing the restore button!
    You can create those via the "Create IAP Button" and "Create IAP Listener" found in Services > In-App Purchasing


    Are you testing on Sandbox? If so, can you try the steps above to logout from your Sandbox account? Based on your log, the restore is successful, but Apple thinks there's nothing to be restored.

    The TODO would be to allow you to get a response when the restore is successful, but in this case, it would be a success with no transactions which wouldn't provide more information.
     
  37. itierney

    itierney

    Joined:
    Jan 28, 2019
    Posts:
    27
    Hey,
    Thanks for your ongoing help Yannick.
    To save us both time (I've been at this for weeks) could you tell me where all this is documented?
    The Restoring Transactions page doesn't mention how to add a button or a listener. In-fact all it really has is a piece of code, without mentioning what to do with this.

    Here's what I did: I added a listener to the scene, I didn't change any of its default settings:
    Screenshot 2022-11-17 at 14.08.21.png

    Both the button and listener seem to be active in the scene (In that I can press the button and I dont deactivate the listener).

    Despite this I get the following log file:

    Purchase not correctly processed for product "com.buddha.BudBud.unlock". Add an active IAPButton to process this purchase, or add an IAPListener to receive any unhandled purchase events.

    UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object)

    UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])

    UnityEngine.Logger:Log(LogType, Object)

    UnityEngine.Debug:LogError(Object)

    UnityEngine.Purchasing.CodelessIAPStoreListener:processPurchase(PurchaseEventArgs)

    UnityEngine.Purchasing.StoreListenerProxy:processPurchase(PurchaseEventArgs)

    UnityEngine.Purchasing.PurchasingManager:processPurchaseIfNew(Product)

    UnityEngine.Purchasing.PurchasingManager:OnPurchaseSucceeded(String, String, String)

    UnityEngine.Purchasing.JSONStore:OnPurchaseSucceeded(String, String, String)

    UnityEngine.Purchasing.AppleStoreImpl:OnPurchaseSucceeded(String, String, String)

    UnityEngine.Purchasing.AppleStoreImpl:processMessage(String, String, String, String)

    UnityEngine.Purchasing.<>c__DisplayClass48_0:<MessageCallback>b__0()

    System.Action:Invoke()

    UnityEngine.Purchasing.Extension.UnityUtil:Update()


    2022-11-17 14:04:38.099703+0000 PocketBuddha[36547:10485355] UnityIAP: PaymentQueueRestoreCompletedTransactionsFinished
     
  38. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    230
  39. itierney

    itierney

    Joined:
    Jan 28, 2019
    Posts:
    27

    Thanks!
    I'm trying this now.
    I have 3 questions.
    1. The IAP Listener has "On Purchase Complete"...I am not trying to purchase, I am trying to restore. Is this where I put my restore code?
    2. Why am I getting this error, I have an active IAPButton and a listener? :“Add an active IAPButton to process this purchase, or add an IAPListener to receive any unhandled purchase events.
    3. The documents say “there may be times when it is difficult or undesirable to have an active IAP Button”. But, my scene has an active IAP Button so why do I need the listener?
     
  40. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    230
    1. Yes, when restoring, Apple will send it as a new purchase which you have to process. It takes the same flow as a normal purchase so you will want to assign a script to your IAP Listener for the "On Purchase Complete".

    2. In both cases, make sure they are enabled and loaded in your current scene. In your screenshot above I don't see the IAP Button for Purchase, is it loaded in that scene?
    For the IAP Button, also make sure a Product ID was assigned to it. For the IAP Listener, you can tick the "Don't Destroy On Load" which will make it persistant through scenes.

    3. The IAP Listener can be useful if your IAP Button isn't loaded and you need to process a purchase (this might be your case since the IAP Button doesn't seem to be found). Instead of adding the "On Purchase Complete" to every IAP Button, you can add it once to the IAP Listener to handle all your purchases from that script.
     
  41. itierney

    itierney

    Joined:
    Jan 28, 2019
    Posts:
    27
    • For the IAP Button restore button, there seems to be no field, to assign Product ID. (see screen shot)
    • This more an apple question: but do you know how to change an existing user into a sandbox tester? No obvious way in app store connect
    • Do I need the IAP listener, since the IAP Restore button is active in the scene?
    • The IAP listener now calls FullVersion(), the same function as the unlock button. (theres only 1 thing to purchase)
    • The IAPButton, is in the scene and enabled, its called “Restore Button iOS
    • IAP Listener has don’t destroy on load turned on.
    Given, that this has taken weeks, is there a way to talk to you guys directly, share screen perhaps? I’m sure you could sort this out in 20 mins!



    Thanks,

    Ian

    Screenshot 2022-11-21 at 15.59.35.png
     
  42. Arnaud_Gorain

    Arnaud_Gorain

    Unity Technologies

    Joined:
    Jun 28, 2022
    Posts:
    182
    Hi @itierney,
    We do not do screen sharing support from the forum. If you have a Unity representative assigned to help your business, I suggest to reach out to that person to help you get further support.

    Thus, feel free to add detailed information here (with screenshot, code snippet, ...) so we can help you the best as we can on the forum.
    From what I see on your previous information, we could use more details.
     
  43. itierney

    itierney

    Joined:
    Jan 28, 2019
    Posts:
    27
    Thanks agorin, what do you need?...theres almost no code for restore (according to the docs you just make a button and make sire its active). I've posted screen grabs and logs.
     
  44. Arnaud_Gorain

    Arnaud_Gorain

    Unity Technologies

    Joined:
    Jun 28, 2022
    Posts:
    182
    Hi @itierney,

    If your IAPListener is disabled, you will not be notify by the CodelessIAPListener:

    Code (CSharp):
    1.         void OnDisable()
    2.         {
    3.             CodelessIAPStoreListener.Instance.RemoveListener(this);
    4.         }
    Even if it is DontDestroyOnLoad, you should check the live scene and see if the GameObject which has the IAPListener is in the hierarchy and enabled.

    Can you please provide the following for further support if you still have an issue:
    1. A screenshot of the IAP listener inspector view
    2. Both scripts: OnPurchaseComplete and OnPurchaseFailed
    3. A screenshot of the view of the scenes with the listener
    It should look like the following below:
     

    Attached Files:

  45. itierney

    itierney

    Joined:
    Jan 28, 2019
    Posts:
    27
    1. A screenshot of the IAP listener inspector view Screenshot 2022-11-30 at 17.10.02.png
    2. OnPurchaseComplete (on the IAP listener, as opposed to the initial purchase) simply calls this function. I dont have an on Purchase fail for restore:

    Code (CSharp):
    1.    
    2. public void FullVersion() {
    3.         PlayerPrefs.SetInt("Trial", 0);//changes playerpref to acknowledge full version purchase
    4.                
    5. }
    3. A screenshot of the view of the scenes with the listener
    The listener is in the settings Screen, and its all active in the scene:
    Screenshot 2022-11-30 at 17.09.48.png

    Note, that although the tutorials say all you need to do is set create an IAP button and set it to restore, I noticed there is an OnClick field for a script to be called on pressing the button. Do I need to fill this in?

    Screenshot 2022-11-30 at 17.14.29.png
     
  46. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    230
    1- For the IAP Listener, I would suggest adding a script for the On Purchase Failed to avoid getting errors if something goes wrong, but for the error you had previously, this should be good.

    2- You will want to manage it by product in the IAP Listener since this is called for any purchases made, not just the restore.

    3- I would suggest putting the IAP Listener directly under your main scene instead of the SettingsScreen since Codeless IAP is initialized on RuntimeInitializeOnLoadMethod which means you need the IAP Listener to be active from anywhere, not just the SettingsScreen.

    For the restore button, you don't need to do anything On Click (), your button is good.


    I believe with the IAP Listener directly under your main scene, this will solve your issue
     
  47. itierney

    itierney

    Joined:
    Jan 28, 2019
    Posts:
    27
    Thanks Yannick_Denis. Just so you know, I can't test in sandbox at the moment due to a bug. I'll let you know if that works.
    If a player presses restore but has never made a purchase, does our game have to display a message or is this handled by unity?
     
  48. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    230
    The user will get a pop-up from Apple to login in order to perform the restore. However, on the Unity IAP side, we won't get any transactions from Apple to process, so nothing will be returned.
    Displaying a message for this is optional.