Search Unity

Ios iap purchase buttons responds late.

Discussion in 'Unity IAP' started by ozgurdemm17, Sep 10, 2019.

  1. ozgurdemm17

    ozgurdemm17

    Joined:
    Jun 7, 2019
    Posts:
    4
    Hello.
    I use iap for auto renewal subscriptions. This problem is just happening in ios. No problem on the Android side. And they both use the same code. I've been investigating for a long time, but I can't come to a conclusion. Buttons work with a 10-15 second delay. In application sandbox tests I read that the buttons react late. However, the application is published and the problem persists. You can see the codes I use below.

    Code (CSharp):
    1. #if UNITY_PURCHASING
    2.  
    3. #if UNITY_ANDROID || UNITY_IPHONE || UNITY_STANDALONE_OSX || UNITY_TVOS
    4. // You must obfuscate your secrets using Window > Unity IAP > Receipt Validation Obfuscator
    5. // before receipt validation will compile in this sample.
    6. //#define RECEIPT_VALIDATION
    7. #endif
    8.  
    9. //#define DELAY_CONFIRMATION // Returns PurchaseProcessingResult.Pending from ProcessPurchase, then calls ConfirmPendingPurchase after a delay
    10. //#define USE_PAYOUTS // Enables use of PayoutDefinitions to specify what the player should receive when a product is purchased
    11. //#define INTERCEPT_PROMOTIONAL_PURCHASES // Enables intercepting promotional purchases that come directly from the Apple App Store
    12. //#define SUBSCRIPTION_MANAGER //Enables subscription product manager for AppleStore and GooglePlay store
    13.  
    14. using System;
    15. using System.Collections;
    16. using System.Collections.Generic;
    17. using UnityEngine;
    18. using UnityEngine.UI;
    19. using UnityEngine.Purchasing;
    20. using UnityEngine.Store; // UnityChannel
    21.  
    22. #if RECEIPT_VALIDATION
    23. using UnityEngine.Purchasing.Security;
    24. #endif
    25.  
    26. /// <summary>
    27. /// An example of Unity IAP functionality.
    28. /// To use with your account, configure the product ids (AddProduct).
    29. /// </summary>
    30. [AddComponentMenu("Unity IAP/Demo")]
    31. public class IAPDemo : MonoBehaviour, IStoreListener
    32. {
    33.     // Unity IAP objects
    34.     private IStoreController m_Controller;
    35.  
    36.     private IAppleExtensions m_AppleExtensions;
    37.     private IMoolahExtension m_MoolahExtensions;
    38.     private ISamsungAppsExtensions m_SamsungExtensions;
    39.     private IMicrosoftExtensions m_MicrosoftExtensions;
    40.     private IUnityChannelExtensions m_UnityChannelExtensions;
    41.     private ITransactionHistoryExtensions m_TransactionHistoryExtensions;
    42.     private IGooglePlayStoreExtensions m_GooglePlayStoreExtensions;
    43.     bool premium_cont;
    44.  
    45. #pragma warning disable 0414
    46.     private bool m_IsGooglePlayStoreSelected;
    47. #pragma warning restore 0414
    48.     private bool m_IsSamsungAppsStoreSelected;
    49.     private bool m_IsCloudMoolahStoreSelected;
    50.     private bool m_IsUnityChannelSelected;
    51.  
    52.     private string m_LastTransactionID;
    53.     private bool m_IsLoggedIn;
    54.     private UnityChannelLoginHandler unityChannelLoginHandler; // Helper for interfacing with UnityChannel API
    55.     private bool m_FetchReceiptPayloadOnPurchase = false;
    56.  
    57.     private bool m_PurchaseInProgress;
    58.  
    59.     private Dictionary<string, IAPDemoProductUI> m_ProductUIs = new Dictionary<string, IAPDemoProductUI>();
    60.  
    61.     //public GameObject productUITemplate;
    62.     //public RectTransform contentRect;
    63.  
    64.     //public Button restoreButton;
    65.     //public Button loginButton;
    66.     //public Button validateButton;
    67.  
    68.     //public Text versionText;
    69.  
    70. #if RECEIPT_VALIDATION
    71.     private CrossPlatformValidator validator;
    72. #endif
    73.  
    74.     /// <summary>
    75.     /// This will be called when Unity IAP has finished initialising.
    76.     /// </summary>
    77.     public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    78.     {
    79.         m_Controller = controller;
    80.         m_AppleExtensions = extensions.GetExtension<IAppleExtensions>();
    81.         m_SamsungExtensions = extensions.GetExtension<ISamsungAppsExtensions>();
    82.         m_MoolahExtensions = extensions.GetExtension<IMoolahExtension>();
    83.         m_MicrosoftExtensions = extensions.GetExtension<IMicrosoftExtensions>();
    84.         m_UnityChannelExtensions = extensions.GetExtension<IUnityChannelExtensions>();
    85.         m_TransactionHistoryExtensions = extensions.GetExtension<ITransactionHistoryExtensions>();
    86.         m_GooglePlayStoreExtensions = extensions.GetExtension<IGooglePlayStoreExtensions>();
    87.         // Sample code for expose product sku details for google play store
    88.         // Key is product Id (Sku), value is the skuDetails json string
    89.         //Dictionary<string, string> google_play_store_product_SKUDetails_json = m_GooglePlayStoreExtensions.GetProductJSONDictionary();
    90.         // Sample code for manually finish a transaction (consume a product on GooglePlay store)
    91.         //m_GooglePlayStoreExtensions.FinishAdditionalTransaction(productId, transactionId);
    92.  
    93.         //InitUI(controller.products.all); Değişti
    94.  
    95.         // On Apple platforms we need to handle deferred purchases caused by Apple's Ask to Buy feature.
    96.         // On non-Apple platforms this will have no effect; OnDeferred will never be called.
    97.         m_AppleExtensions.RegisterPurchaseDeferredListener(OnDeferred);
    98.  
    99. #if UNITY_IOS
    100.         Dictionary<string, string> introductory_info_dict = m_AppleExtensions.GetIntroductoryPriceDictionary();
    101. #elif UNITY_ANDROID
    102.         Dictionary<string, string> introductory_info_dict = m_GooglePlayStoreExtensions.GetProductJSONDictionary();
    103. #endif
    104.         // Sample code for expose product sku details for apple store
    105.         //Dictionary<string, string> product_details = m_AppleExtensions.GetProductDetails();
    106.  
    107.         premium_cont = false;
    108.         Debug.Log("Available items:");
    109.         foreach (var item in controller.products.all)
    110.         {
    111.             if (item.availableToPurchase)
    112.             {
    113.                 Debug.Log(string.Join(" - ",
    114.                     new[]
    115.                     {
    116.                         item.metadata.localizedTitle,
    117.                         item.metadata.localizedDescription,
    118.                         item.metadata.isoCurrencyCode,
    119.                         item.metadata.localizedPrice.ToString(),
    120.                         item.metadata.localizedPriceString,
    121.                         item.transactionID,
    122.                         item.receipt
    123.                     }));
    124. #if INTERCEPT_PROMOTIONAL_PURCHASES
    125.                 // Set all these products to be visible in the user's App Store according to Apple's Promotional IAP feature
    126.                 // https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/PromotingIn-AppPurchases/PromotingIn-AppPurchases.html
    127.                 m_AppleExtensions.SetStorePromotionVisibility(item, AppleStorePromotionVisibility.Show);
    128. #endif
    129.                
    130.                 // this is the usage of SubscriptionManager class
    131.                 if (item.receipt != null) {
    132.                     if (item.definition.type == ProductType.Subscription) {
    133.                         if (checkIfProductIsAvailableForSubscriptionManager(item.receipt)) {
    134.                             Debug.Log("Sub ");
    135.                             string intro_json = (introductory_info_dict == null || !introductory_info_dict.ContainsKey(item.definition.storeSpecificId)) ? null : introductory_info_dict[item.definition.storeSpecificId];
    136.                             SubscriptionManager p = new SubscriptionManager(item, intro_json);
    137.                             SubscriptionInfo info = p.getSubscriptionInfo();
    138.                             Debug.Log("product id is: " + info.getProductId());
    139.                             Debug.Log("purchase date is: " + info.getPurchaseDate());
    140.                             Debug.Log("subscription next billing date is: " + info.getExpireDate());
    141.                             Debug.Log("is subscribed? " + info.isSubscribed().ToString());
    142.                             Debug.Log("is expired? " + info.isExpired().ToString());
    143.                             Debug.Log("is cancelled? " + info.isCancelled());
    144.                             Debug.Log("product is in free trial peroid? " + info.isFreeTrial());
    145.                             Debug.Log("product is auto renewing? " + info.isAutoRenewing());
    146.                             Debug.Log("subscription remaining valid time until next billing date is: " + info.getRemainingTime());
    147.                             Debug.Log("is this product in introductory price period? " + info.isIntroductoryPricePeriod());
    148.                             Debug.Log("the product introductory localized price is: " + info.getIntroductoryPrice());
    149.                             Debug.Log("the product introductory price period is: " + info.getIntroductoryPricePeriod());
    150.                             Debug.Log("the number of product introductory price period cycles is: " + info.getIntroductoryPricePeriodCycles());
    151.  
    152.                             if (info.isSubscribed().ToString() == "True")
    153.                             {
    154.                                 PlayerPrefs.SetInt("Premium",1);
    155.                                 premium_cont = true;
    156.                             }
    157.  
    158.                         } else {
    159.                             Debug.Log("This product is not available for SubscriptionManager class, only products that are purchase by 1.19+ SDK can use this class.");
    160.                         }
    161.                     } else {
    162.                         Debug.Log("the product is not a subscription product");
    163.  
    164.                     }
    165.                 } else {
    166.                     Debug.Log("the product should have a valid receipt");
    167.                     if(!premium_cont)
    168.                     {
    169.                         PlayerPrefs.SetInt("Premium",0);
    170.                     }
    171.                 }
    172.             }
    173.         }
    174.  
    175.         // Populate the product menu now that we have Products
    176.         //AddProductUIs(m_Controller.products.all);
    177.  
    178.         LogProductDefinitions();
    179.     }
    180.  
    181.     private bool checkIfProductIsAvailableForSubscriptionManager(string receipt) {
    182.         var receipt_wrapper = (Dictionary<string, object>)MiniJson.JsonDecode(receipt);
    183.         if (!receipt_wrapper.ContainsKey("Store") || !receipt_wrapper.ContainsKey("Payload")) {
    184.             Debug.Log("The product receipt does not contain enough information");
    185.             return false;
    186.         }
    187.         var store = (string)receipt_wrapper ["Store"];
    188.         var payload = (string)receipt_wrapper ["Payload"];
    189.  
    190.         if (payload != null ) {
    191.             switch (store) {
    192.             case GooglePlay.Name:
    193.                 {
    194.                     var payload_wrapper = (Dictionary<string, object>)MiniJson.JsonDecode(payload);
    195.                     if (!payload_wrapper.ContainsKey("json")) {
    196.                         Debug.Log("The product receipt does not contain enough information, the 'json' field is missing");
    197.                         return false;
    198.                     }
    199.                     var original_json_payload_wrapper = (Dictionary<string, object>)MiniJson.JsonDecode((string)payload_wrapper["json"]);
    200.                     if (original_json_payload_wrapper == null || !original_json_payload_wrapper.ContainsKey("developerPayload")) {
    201.                         Debug.Log("The product receipt does not contain enough information, the 'developerPayload' field is missing");
    202.                         return false;
    203.                     }
    204.                     var developerPayloadJSON = (string)original_json_payload_wrapper["developerPayload"];
    205.                     var developerPayload_wrapper = (Dictionary<string, object>)MiniJson.JsonDecode(developerPayloadJSON);
    206.                     if (developerPayload_wrapper == null || !developerPayload_wrapper.ContainsKey("is_free_trial") || !developerPayload_wrapper.ContainsKey("has_introductory_price_trial")) {
    207.                         Debug.Log("The product receipt does not contain enough information, the product is not purchased using 1.19 or later");
    208.                         return false;
    209.                     }
    210.                     return true;
    211.                 }
    212.             case AppleAppStore.Name:
    213.             case AmazonApps.Name:
    214.             case MacAppStore.Name:
    215.                 {
    216.                     return true;
    217.                 }
    218.             default:
    219.                 {
    220.                     return false;
    221.                 }
    222.             }
    223.         }
    224.         return false;
    225.     }
    226.  
    227.     /// <summary>
    228.     /// This will be called when a purchase completes.
    229.     /// </summary>
    230.     public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
    231.     {
    232.         Debug.Log("Purchase OK: " + e.purchasedProduct.definition.id);
    233.         Debug.Log("Receipt: " + e.purchasedProduct.receipt);
    234.  
    235.         PlayerPrefs.SetInt("Premium",1);
    236.         m_LastTransactionID = e.purchasedProduct.transactionID;
    237.         m_PurchaseInProgress = false;
    238.  
    239.         // Decode the UnityChannelPurchaseReceipt, extracting the gameOrderId
    240.         if (m_IsUnityChannelSelected)
    241.         {
    242.             var unifiedReceipt = JsonUtility.FromJson<UnifiedReceipt>(e.purchasedProduct.receipt);
    243.             if (unifiedReceipt != null && !string.IsNullOrEmpty(unifiedReceipt.Payload))
    244.             {
    245.                 var purchaseReceipt = JsonUtility.FromJson<UnityChannelPurchaseReceipt>(unifiedReceipt.Payload);
    246.                 Debug.LogFormat(
    247.                     "UnityChannel receipt: storeSpecificId = {0}, transactionId = {1}, orderQueryToken = {2}",
    248.                     purchaseReceipt.storeSpecificId, purchaseReceipt.transactionId, purchaseReceipt.orderQueryToken);
    249.             }
    250.         }
    251.  
    252. #if RECEIPT_VALIDATION // Local validation is available for GooglePlay, Apple, and UnityChannel stores
    253.         if (m_IsGooglePlayStoreSelected ||
    254.             (m_IsUnityChannelSelected && m_FetchReceiptPayloadOnPurchase) ||
    255.             Application.platform == RuntimePlatform.IPhonePlayer ||
    256.             Application.platform == RuntimePlatform.OSXPlayer ||
    257.             Application.platform == RuntimePlatform.tvOS) {
    258.             try {
    259.                 var result = validator.Validate(e.purchasedProduct.receipt);
    260.                 Debug.Log("Receipt is valid. Contents:");
    261.                 foreach (IPurchaseReceipt productReceipt in result) {
    262.                     Debug.Log(productReceipt.productID);
    263.                     Debug.Log(productReceipt.purchaseDate);
    264.                     Debug.Log(productReceipt.transactionID);
    265.  
    266.                     GooglePlayReceipt google = productReceipt as GooglePlayReceipt;
    267.                     if (null != google) {
    268.                         Debug.Log(google.purchaseState);
    269.                         Debug.Log(google.purchaseToken);
    270.                     }
    271.  
    272.                     UnityChannelReceipt unityChannel = productReceipt as UnityChannelReceipt;
    273.                     if (null != unityChannel) {
    274.                         Debug.Log(unityChannel.productID);
    275.                         Debug.Log(unityChannel.purchaseDate);
    276.                         Debug.Log(unityChannel.transactionID);
    277.                     }
    278.  
    279.                     AppleInAppPurchaseReceipt apple = productReceipt as AppleInAppPurchaseReceipt;
    280.                     if (null != apple) {
    281.                         Debug.Log(apple.originalTransactionIdentifier);
    282.                         Debug.Log(apple.subscriptionExpirationDate);
    283.                         Debug.Log(apple.cancellationDate);
    284.                         Debug.Log(apple.quantity);
    285.                     }
    286.  
    287.                     // For improved security, consider comparing the signed
    288.                     // IPurchaseReceipt.productId, IPurchaseReceipt.transactionID, and other data
    289.                     // embedded in the signed receipt objects to the data which the game is using
    290.                     // to make this purchase.
    291.                 }
    292.             } catch (IAPSecurityException ex) {
    293.                 Debug.Log("Invalid receipt, not unlocking content. " + ex);
    294.                 return PurchaseProcessingResult.Complete;
    295.             }
    296.         }
    297.         #endif
    298.  
    299.         // Unlock content from purchases here.
    300. #if USE_PAYOUTS
    301.         if (e.purchasedProduct.definition.payouts != null) {
    302.             Debug.Log("Purchase complete, paying out based on defined payouts");
    303.             foreach (var payout in e.purchasedProduct.definition.payouts) {
    304.                 Debug.Log(string.Format("Granting {0} {1} {2} {3}", payout.quantity, payout.typeString, payout.subtype, payout.data));
    305.             }
    306.         }
    307. #endif
    308.         // Indicate if we have handled this purchase.
    309.         //   PurchaseProcessingResult.Complete: ProcessPurchase will not be called
    310.         //     with this product again, until next purchase.
    311.         //   PurchaseProcessingResult.Pending: ProcessPurchase will be called
    312.         //     again with this product at next app launch. Later, call
    313.         //     m_Controller.ConfirmPendingPurchase(Product) to complete handling
    314.         //     this purchase. Use to transactionally save purchases to a cloud
    315.         //     game service.
    316. #if DELAY_CONFIRMATION
    317.         StartCoroutine(ConfirmPendingPurchaseAfterDelay(e.purchasedProduct));
    318.         return PurchaseProcessingResult.Pending;
    319. #else
    320.         UpdateProductUI(e.purchasedProduct);
    321.         return PurchaseProcessingResult.Complete;
    322. #endif
    323.     }
    324.  
    325. #if DELAY_CONFIRMATION
    326.     private HashSet<string> m_PendingProducts = new HashSet<string>();
    327.  
    328.     private IEnumerator ConfirmPendingPurchaseAfterDelay(Product p)
    329.     {
    330.         m_PendingProducts.Add(p.definition.id);
    331.         Debug.Log("Delaying confirmation of " + p.definition.id + " for 5 seconds.");
    332.  
    333.         var end = Time.time + 5f;
    334.  
    335.         while (Time.time < end) {
    336.             yield return null;
    337.             var remaining = Mathf.CeilToInt (end - Time.time);
    338.             UpdateProductPendingUI (p, remaining);
    339.         }
    340.  
    341.         Debug.Log("Confirming purchase of " + p.definition.id);
    342.         m_Controller.ConfirmPendingPurchase(p);
    343.         m_PendingProducts.Remove(p.definition.id);
    344.         UpdateProductUI (p);
    345.     }
    346. #endif
    347.  
    348.     /// <summary>
    349.     /// This will be called if an attempted purchase fails.
    350.     /// </summary>
    351.     public void OnPurchaseFailed(Product item, PurchaseFailureReason r)
    352.     {
    353.         Debug.Log("Purchase failed: " + item.definition.id);
    354.         Debug.Log(r);
    355.  
    356.         // Detailed debugging information
    357.         Debug.Log("Store specific error code: " + m_TransactionHistoryExtensions.GetLastStoreSpecificPurchaseErrorCode());
    358.         if (m_TransactionHistoryExtensions.GetLastPurchaseFailureDescription() != null)
    359.         {
    360.             Debug.Log("Purchase failure description message: " +
    361.                       m_TransactionHistoryExtensions.GetLastPurchaseFailureDescription().message);
    362.         }
    363.  
    364.         if (m_IsUnityChannelSelected)
    365.         {
    366.             var extra = m_UnityChannelExtensions.GetLastPurchaseError();
    367.             var purchaseError = JsonUtility.FromJson<UnityChannelPurchaseError>(extra);
    368.  
    369.             if (purchaseError != null && purchaseError.purchaseInfo != null)
    370.             {
    371.                 // Additional information about purchase failure.
    372.                 var purchaseInfo = purchaseError.purchaseInfo;
    373.                 Debug.LogFormat(
    374.                     "UnityChannel purchaseInfo: productCode = {0}, gameOrderId = {1}, orderQueryToken = {2}",
    375.                     purchaseInfo.productCode, purchaseInfo.gameOrderId, purchaseInfo.orderQueryToken);
    376.             }
    377.  
    378.             // Determine if the user already owns this item and that it can be added to
    379.             // their inventory, if not already present.
    380. #if UNITY_5_6_OR_NEWER
    381.             if (r == PurchaseFailureReason.DuplicateTransaction)
    382.             {
    383.                 // Unlock `item` in inventory if not already present.
    384.                 Debug.Log("Duplicate transaction detected, unlock this item");
    385.             }
    386. #else // Building using Unity strictly less than 5.6; e.g 5.3-5.5.
    387.             // In Unity 5.3 the enum PurchaseFailureReason.DuplicateTransaction
    388.             // may not be available (is available in 5.6 ... specifically
    389.             // 5.5.1p1+, 5.4.4p2+) and can be substituted with this call.
    390.             if (r == PurchaseFailureReason.Unknown)
    391.             {
    392.                 if (purchaseError != null && purchaseError.error != null &&
    393.                     purchaseError.error.Equals("DuplicateTransaction"))
    394.                 {
    395.                     // Unlock `item` in inventory if not already present.
    396.                     Debug.Log("Duplicate transaction detected, unlock this item");
    397.                 }
    398.             }
    399. #endif
    400.         }
    401.  
    402.         m_PurchaseInProgress = false;
    403.     }
    404.  
    405.     public void OnInitializeFailed(InitializationFailureReason error)
    406.     {
    407.         Debug.Log("Billing failed to initialize!");
    408.         switch (error)
    409.         {
    410.             case InitializationFailureReason.AppNotKnown:
    411.                 Debug.LogError("Is your App correctly uploaded on the relevant publisher console?");
    412.                 break;
    413.             case InitializationFailureReason.PurchasingUnavailable:
    414.                 // Ask the user if billing is disabled in device settings.
    415.                 Debug.Log("Billing disabled!");
    416.                 break;
    417.             case InitializationFailureReason.NoProductsAvailable:
    418.                 // Developer configuration error; check product metadata.
    419.                 Debug.Log("No products available for purchase!");
    420.                 break;
    421.         }
    422.     }
    423.  
    424.     [Serializable]
    425.     public class UnityChannelPurchaseError
    426.     {
    427.         public string error;
    428.         public UnityChannelPurchaseInfo purchaseInfo;
    429.     }
    430.  
    431.     [Serializable]
    432.     public class UnityChannelPurchaseInfo
    433.     {
    434.         public string productCode; // Corresponds to storeSpecificId
    435.         public string gameOrderId; // Corresponds to transactionId
    436.         public string orderQueryToken;
    437.     }
    438.  
    439.     public void Awake()
    440.     {
    441.         var module = StandardPurchasingModule.Instance();
    442.  
    443.         module.useFakeStoreUIMode = FakeStoreUIMode.StandardUser;
    444.  
    445.         var builder = ConfigurationBuilder.Instance(module);
    446.  
    447.         builder.Configure<IMicrosoftConfiguration>().useMockBillingSystem = false;
    448.  
    449.         m_IsGooglePlayStoreSelected =
    450.             Application.platform == RuntimePlatform.Android && module.appStore == AppStore.GooglePlay;
    451.         builder.Configure<IMoolahConfiguration>().appKey = "d93f4564c41d463ed3d3cd207594ee1b";
    452.         builder.Configure<IMoolahConfiguration>().hashKey = "cc";
    453.         builder.Configure<IMoolahConfiguration>().SetMode(CloudMoolahMode.AlwaysSucceed);
    454.         m_IsCloudMoolahStoreSelected =
    455.             Application.platform == RuntimePlatform.Android && module.appStore == AppStore.CloudMoolah;
    456.  
    457.         m_IsUnityChannelSelected =
    458.             Application.platform == RuntimePlatform.Android && module.appStore == AppStore.XiaomiMiPay;
    459.         builder.Configure<IUnityChannelConfiguration>().fetchReceiptPayloadOnPurchase = m_FetchReceiptPayloadOnPurchase;
    460.  
    461.         var catalog = ProductCatalog.LoadDefaultCatalog();
    462.  
    463.         foreach (var product in catalog.allValidProducts)
    464.         {
    465.             if (product.allStoreIDs.Count > 0)
    466.             {
    467.                 var ids = new IDs();
    468.                 foreach (var storeID in product.allStoreIDs)
    469.                 {
    470.                     ids.Add(storeID.id, storeID.store);
    471.                 }
    472.                 builder.AddProduct(product.id, product.type, ids);
    473.             }
    474.             else
    475.             {
    476.                 builder.AddProduct(product.id, product.type);
    477.             }
    478.         }
    479.         builder.Configure<ISamsungAppsConfiguration>().SetMode(SamsungAppsMode.AlwaysSucceed);
    480.         m_IsSamsungAppsStoreSelected =
    481.             Application.platform == RuntimePlatform.Android && module.appStore == AppStore.SamsungApps;
    482.  
    483.  
    484.         builder.Configure<ITizenStoreConfiguration>().SetGroupId("100000085616");
    485.  
    486. #if INTERCEPT_PROMOTIONAL_PURCHASES
    487.         builder.Configure<IAppleConfiguration>().SetApplePromotionalPurchaseInterceptorCallback(OnPromotionalPurchase);
    488.         Debug.Log("Setting Apple promotional purchase interceptor callback");
    489. #endif
    490.  
    491. #if RECEIPT_VALIDATION
    492.         string appIdentifier;
    493.         #if UNITY_5_6_OR_NEWER
    494.         appIdentifier = Application.identifier;
    495.         #else
    496.         appIdentifier = Application.bundleIdentifier;
    497.         #endif
    498.         validator = new CrossPlatformValidator(GooglePlayTangle.Data(), AppleTangle.Data(),
    499.             UnityChannelTangle.Data(), appIdentifier);
    500.         #endif
    501.  
    502.         Action initializeUnityIap = () =>
    503.         {
    504.             // Now we're ready to initialize Unity IAP.
    505.             UnityPurchasing.Initialize(this, builder);
    506.         };
    507.  
    508.         bool needExternalLogin = m_IsUnityChannelSelected;
    509.  
    510.         if (!needExternalLogin)
    511.         {
    512.             initializeUnityIap();
    513.         }
    514.         else
    515.         {
    516.          
    517.  
    518.             AppInfo unityChannelAppInfo = new AppInfo();
    519.             unityChannelAppInfo.appId = "abc123appId";
    520.             unityChannelAppInfo.appKey = "efg456appKey";
    521.             unityChannelAppInfo.clientId = "hij789clientId";
    522.             unityChannelAppInfo.clientKey = "klm012clientKey";
    523.             unityChannelAppInfo.debug = false;
    524.  
    525.             unityChannelLoginHandler = new UnityChannelLoginHandler();
    526.             unityChannelLoginHandler.initializeFailedAction = (string message) =>
    527.             {
    528.                 Debug.LogError("Failed to initialize and login to UnityChannel: " + message);
    529.             };
    530.             unityChannelLoginHandler.initializeSucceededAction = () => { initializeUnityIap(); };
    531.  
    532.             StoreService.Initialize(unityChannelAppInfo, unityChannelLoginHandler);
    533.         }
    534.     }
    535.  
    536.     // For handling initialization and login of UnityChannel, returning control to our store after.
    537.     class UnityChannelLoginHandler : ILoginListener
    538.     {
    539.         internal Action initializeSucceededAction;
    540.         internal Action<string> initializeFailedAction;
    541.         internal Action<UserInfo> loginSucceededAction;
    542.         internal Action<string> loginFailedAction;
    543.  
    544.         public void OnInitialized()
    545.         {
    546.             initializeSucceededAction();
    547.         }
    548.  
    549.         public void OnInitializeFailed(string message)
    550.         {
    551.             initializeFailedAction(message);
    552.         }
    553.  
    554.         public void OnLogin(UserInfo userInfo)
    555.         {
    556.             loginSucceededAction(userInfo);
    557.         }
    558.  
    559.         public void OnLoginFailed(string message)
    560.         {
    561.             loginFailedAction(message);
    562.         }
    563.     }
    564.  
    565.     /// <summary>
    566.     /// This will be called after a call to IAppleExtensions.RestoreTransactions().
    567.     /// </summary>
    568.     private void OnTransactionsRestored(bool success)
    569.     {
    570.         Debug.Log("Transactions restored." + success);
    571.     }
    572.  
    573.     /// <summary>
    574.     /// iOS Specific.
    575.     /// This is called as part of Apple's 'Ask to buy' functionality,
    576.     /// when a purchase is requested by a minor and referred to a parent
    577.     /// for approval.
    578.     ///
    579.     /// When the purchase is approved or rejected, the normal purchase events
    580.     /// will fire.
    581.     /// </summary>
    582.     /// <param name="item">Item.</param>
    583.     private void OnDeferred(Product item)
    584.     {
    585.         Debug.Log("Purchase deferred: " + item.definition.id);
    586.     }
    587.  
    588. #if INTERCEPT_PROMOTIONAL_PURCHASES
    589.     private void OnPromotionalPurchase(Product item) {
    590.         Debug.Log("Attempted promotional purchase: " + item.definition.id);
    591.  
    592.         // Promotional purchase has been detected. Handle this event by, e.g. presenting a parental gate.
    593.         // Here, for demonstration purposes only, we will wait five seconds before continuing the purchase.
    594.         StartCoroutine(ContinuePromotionalPurchases());
    595.     }
    596.  
    597.     private IEnumerator ContinuePromotionalPurchases()
    598.     {
    599.         Debug.Log("Continuing promotional purchases in 5 seconds");
    600.         yield return new WaitForSeconds(5);
    601.         Debug.Log("Continuing promotional purchases now");
    602.         m_AppleExtensions.ContinuePromotionalPurchases (); // iOS and tvOS only; does nothing on Mac
    603.     }
    604. #endif
    605.     /* Değişti
    606.     private void InitUI(IEnumerable<Product> items)
    607.     {
    608.         // Show Restore, Register, Login, and Validate buttons on supported platforms
    609.         restoreButton.gameObject.SetActive(true);
    610.         loginButton.gameObject.SetActive(NeedLoginButton());
    611.         validateButton.gameObject.SetActive(NeedValidateButton());
    612.  
    613.         ClearProductUIs();
    614.  
    615.         restoreButton.onClick.AddListener(RestoreButtonClick);
    616.         loginButton.onClick.AddListener(LoginButtonClick);
    617.         validateButton.onClick.AddListener(ValidateButtonClick);
    618.  
    619.         versionText.text = "Unity version: " + Application.unityVersion + "\n" +
    620.                            "IAP version: " + StandardPurchasingModule.k_PackageVersion;
    621.     }
    622.     */
    623.  
    624.     public void PurchaseButtonClick(string productID)
    625.     {
    626.         if (m_PurchaseInProgress == true)
    627.         {
    628.             Debug.Log("Please wait, purchase in progress");
    629.             return;
    630.         }
    631.  
    632.         if (m_Controller == null)
    633.         {
    634.             Debug.LogError("Purchasing is not initialized");
    635.             return;
    636.         }
    637.  
    638.         if (m_Controller.products.WithID(productID) == null)
    639.         {
    640.             Debug.LogError("No product has id " + productID);
    641.             return;
    642.         }
    643.  
    644.         if (NeedLoginButton() && m_IsLoggedIn == false)
    645.         {
    646.             Debug.LogWarning("Purchase notifications will not be forwarded server-to-server. Login incomplete.");
    647.         }
    648.  
    649.         m_PurchaseInProgress = true;
    650.  
    651.         m_Controller.InitiatePurchase(m_Controller.products.WithID(productID), "developerPayload");
    652.  
    653.     }
    654.  
    655.     public void RestoreButtonClick()
    656.     {
    657.         if (m_IsCloudMoolahStoreSelected)
    658.         {
    659.             if (m_IsLoggedIn == false)
    660.             {
    661.                 Debug.LogError("CloudMoolah purchase restoration aborted. Login incomplete.");
    662.             }
    663.             else
    664.             {
    665.                 m_MoolahExtensions.RestoreTransactionID((RestoreTransactionIDState restoreTransactionIDState) =>
    666.                 {
    667.                     Debug.Log("restoreTransactionIDState = " + restoreTransactionIDState.ToString());
    668.                     bool success =
    669.                         restoreTransactionIDState != RestoreTransactionIDState.RestoreFailed &&
    670.                         restoreTransactionIDState != RestoreTransactionIDState.NotKnown;
    671.                     OnTransactionsRestored(success);
    672.                 });
    673.             }
    674.         }
    675.         else if (m_IsSamsungAppsStoreSelected)
    676.         {
    677.             m_SamsungExtensions.RestoreTransactions(OnTransactionsRestored);
    678.         }
    679.         else if (Application.platform == RuntimePlatform.WSAPlayerX86 ||
    680.                  Application.platform == RuntimePlatform.WSAPlayerX64 ||
    681.                  Application.platform == RuntimePlatform.WSAPlayerARM)
    682.         {
    683.             m_MicrosoftExtensions.RestoreTransactions();
    684.         }
    685.         else if (m_IsGooglePlayStoreSelected)
    686.         {
    687.             m_GooglePlayStoreExtensions.RestoreTransactions(OnTransactionsRestored);
    688.         }
    689.         else
    690.         {
    691.             m_AppleExtensions.RestoreTransactions(OnTransactionsRestored);
    692.         }
    693.     }
    694.  
    695.     public void LoginButtonClick()
    696.     {
    697.         if (!m_IsUnityChannelSelected)
    698.         {
    699.             Debug.Log("Login is only required for the Xiaomi store");
    700.             return;
    701.         }
    702.  
    703.         unityChannelLoginHandler.loginSucceededAction = (UserInfo userInfo) =>
    704.         {
    705.             m_IsLoggedIn = true;
    706.             Debug.LogFormat("Succeeded logging into UnityChannel. channel {0}, userId {1}, userLoginToken {2} ",
    707.                 userInfo.channel, userInfo.userId, userInfo.userLoginToken);
    708.         };
    709.  
    710.         unityChannelLoginHandler.loginFailedAction = (string message) =>
    711.         {
    712.             m_IsLoggedIn = false;
    713.             Debug.LogError("Failed logging into UnityChannel. " + message);
    714.         };
    715.  
    716.         StoreService.Login(unityChannelLoginHandler);
    717.     }
    718.  
    719.     public void ValidateButtonClick()
    720.     {
    721.         // For local validation, see ProcessPurchase.
    722.  
    723.         if (!m_IsUnityChannelSelected)
    724.         {
    725.             Debug.Log("Remote purchase validation is only supported for the Xiaomi store");
    726.             return;
    727.         }
    728.  
    729.         string txId = m_LastTransactionID;
    730.         m_UnityChannelExtensions.ValidateReceipt(txId, (bool success, string signData, string signature) =>
    731.         {
    732.             Debug.LogFormat("ValidateReceipt transactionId {0}, success {1}, signData {2}, signature {3}",
    733.                 txId, success, signData, signature);
    734.  
    735.             // May use signData and signature results to validate server-to-server
    736.         });
    737.     }
    738.  
    739.     private void ClearProductUIs()
    740.     {
    741.         foreach (var productUIKVP in m_ProductUIs)
    742.         {
    743.             GameObject.Destroy(productUIKVP.Value.gameObject);
    744.         }
    745.         m_ProductUIs.Clear();
    746.     }
    747.     /*
    748.     private void AddProductUIs(Product[] products)
    749.     {
    750.         ClearProductUIs();
    751.  
    752.         var templateRectTransform = productUITemplate.GetComponent<RectTransform>();
    753.         var height = templateRectTransform.rect.height;
    754.         var currPos = templateRectTransform.localPosition;
    755.  
    756.         contentRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, products.Length * height);
    757.  
    758.         foreach (var p in products)
    759.         {
    760.             var newProductUI = GameObject.Instantiate(productUITemplate.gameObject) as GameObject;
    761.             newProductUI.transform.SetParent(productUITemplate.transform.parent, false);
    762.             var rect = newProductUI.GetComponent<RectTransform>();
    763.             rect.localPosition = currPos;
    764.             currPos += Vector3.down * height;
    765.             newProductUI.SetActive(true);
    766.             var productUIComponent = newProductUI.GetComponent<IAPDemoProductUI>();
    767.             productUIComponent.SetProduct(p, PurchaseButtonClick);
    768.  
    769.             m_ProductUIs[p.definition.id] = productUIComponent;
    770.         }
    771.     }
    772.     */
    773.  
    774.     private void UpdateProductUI(Product p)
    775.     {
    776.         if (m_ProductUIs.ContainsKey(p.definition.id))
    777.         {
    778.             m_ProductUIs[p.definition.id].SetProduct(p, PurchaseButtonClick);
    779.         }
    780.     }
    781.  
    782.     private void UpdateProductPendingUI(Product p, int secondsRemaining)
    783.     {
    784.         if (m_ProductUIs.ContainsKey(p.definition.id))
    785.         {
    786.             m_ProductUIs[p.definition.id].SetPendingTime(secondsRemaining);
    787.         }
    788.     }
    789.  
    790.     private bool NeedRestoreButton()
    791.     {
    792.         return Application.platform == RuntimePlatform.IPhonePlayer ||
    793.                Application.platform == RuntimePlatform.OSXPlayer ||
    794.                Application.platform == RuntimePlatform.tvOS ||
    795.                Application.platform == RuntimePlatform.WSAPlayerX86 ||
    796.                Application.platform == RuntimePlatform.WSAPlayerX64 ||
    797.                Application.platform == RuntimePlatform.WSAPlayerARM ||
    798.                m_IsSamsungAppsStoreSelected ||
    799.                m_IsCloudMoolahStoreSelected;
    800.     }
    801.  
    802.  
    803.     private bool NeedLoginButton()
    804.     {
    805.         return m_IsUnityChannelSelected;
    806.     }
    807.  
    808.     private bool NeedValidateButton()
    809.     {
    810.         return m_IsUnityChannelSelected;
    811.     }
    812.  
    813.     private void LogProductDefinitions()
    814.     {
    815.         var products = m_Controller.products.all;
    816.         foreach (var product in products)
    817.         {
    818. #if UNITY_5_6_OR_NEWER
    819.             Debug.Log(string.Format("id: {0}\nstore-specific id: {1}\ntype: {2}\nenabled: {3}\n", product.definition.id, product.definition.storeSpecificId, product.definition.type.ToString(), product.definition.enabled ? "enabled" : "disabled"));
    820. #else
    821.             Debug.Log(string.Format("id: {0}\nstore-specific id: {1}\ntype: {2}\n", product.definition.id,
    822.                 product.definition.storeSpecificId, product.definition.type.ToString()));
    823. #endif
    824.         }
    825.     }
    826. }
    827.  
    828. #endif // UNITY_PURCHASING
    829.  
     
  2. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Since it reproduces for you, you can debug directly from XCode to see where it is taking longer time. Or add the appropriate Debug.Log statements with an elapsed time calculation or similar. I do have concerns around ConfirmPendingPurchaseAfterDelay, I have never seen that type of logic required. You are purposely waiting 5 seconds in the co-routine? You might want to test without this in place to compare.
     
  3. ozgurdemm17

    ozgurdemm17

    Joined:
    Jun 7, 2019
    Posts:
    4
    No. sometimes 10, sometimes waiting longer.

    //
    Clicking the button, I see these logs. Just tihs code start "m_Controller.InitiatePurchase(m_Controller.products.WithID(productID), "developerPayload");".
    How to can i optimize this code? And I can't see the trouble in the logs. Can you help me?




    Code (CSharp):
    1.     12:51:35.882320 +0300    palmistry    Here
    2. Button_Subs:Weakly()
    3. UnityEngine.Events.UnityEvent:Invoke()
    4. UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1)
    5. UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchPress(PointerEventData, Boolean, Boolean)
    6. UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchEvents()
    7. UnityEngine.EventSystems.StandaloneInputModule:Process()
    8. (Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/DebugBindings.gen.cpp Line: 51)
    9.     12:51:39.329972 +0300    palmistry    UnityIAP: PurchaseProduct: subh
    10.     12:51:39.331389 +0300    palmistry    purchase({0}): subh
    11. UnityEngine.Events.UnityEvent:Invoke()
    12. UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1)
    13. UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchPress(PointerEventData, Boolean, Boolean)
    14. UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchEvents()
    15. UnityEngine.EventSystems.StandaloneInputModule:Process()
    16. (Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/DebugBindings.gen.cpp Line: 51)
    17.     12:51:39.395778 +0300    palmistry    UnityIAP: UpdatedTransactions
    18.     12:51:41.508908 +0300    palmistry    Task <AE8FAF40-CE37-42A6-ACFC-255C4BBF7508>.<1> resuming, QOS(0x21)
    19.     12:51:41.532568 +0300    palmistry    Task <AE8FAF40-CE37-42A6-ACFC-255C4BBF7508>.<1> {strength 0, tls 4, ct 0, sub 0, sig 1, ciphers 0, bundle 0, builtin 0}
    20.     12:51:41.549884 +0300    palmistry    nw_endpoint_flow_protocol_connected [C46.1 IPv4#54c8f94a:443 in_progress channel-flow (satisfied)] Transport protocol connected
    21.     12:51:41.574116 +0300    palmistry    TIC TLS Event [46:0x280945e00]: 1, Pending(0)
    22.     12:51:41.763836 +0300    palmistry    Task <AE8FAF40-CE37-42A6-ACFC-255C4BBF7508>.<1> received response, status 200 content K
    23.     12:51:41.766569 +0300    palmistry    Task <AE8FAF40-CE37-42A6-ACFC-255C4BBF7508>.<1> response ended
    24.     12:51:41.771829 +0300    palmistry    removing all entries config 0x283c3d5c0
    25.     12:51:41.772129 +0300    palmistry    removing all entries config 0x283c3d5c0
    26.     12:51:41.773401 +0300    palmistry    TIC TCP Conn Cancel [46:0x280945e00]
    27.     12:51:41.774384 +0300    palmistry    [C46 Hostname#85bce954:443 tcp, url hash: 5c1cb8ab, tls] cancel
    28.     12:51:41.774984 +0300    palmistry    [C46 Hostname#85bce954:443 tcp, url hash: 5c1cb8ab, tls] cancelled
    29.     [C46.1 <private> 192.168.1.27:61636<->IPv4#54c8f94a:443]
    30.     Connected Path: satisfied (Path is satisfied), interface: en0, ipv4, dns
    31.     Duration: 0.709s, DNS @0.023s took 0.027s, TCP @0.070s took 0.030s, TLS took 0.175s
    32.     bytes in/out: 4254/1817, packets in/out: 9/8, rtt: 0.070s, retransmitted packets: 0, out-of-order packets: 0
    33.     12:51:41.775479 +0300    palmistry    0.018s [C46 <private> Hostname#85bce954:443 resolver] path:start
    34.     12:51:41.782885 +0300    palmistry    0.019s [C46 <private> Hostname#85bce954:443 resolver] path:satisfied
    35.     12:51:41.783507 +0300    palmistry    0.023s [C46 <private> Hostname#85bce954:443 resolver] resolver:start_dns
    36.     12:51:41.785850 +0300    palmistry    0.050s [C46 <private> Hostname#85bce954:443 resolver] resolver:receive_dns
    37.     12:51:41.786480 +0300    palmistry    0.052s [C46.1 <private> 192.168.1.27:61636<->IPv4#54c8f94a:443 channel-flow] path:start
    38.     12:51:41.786967 +0300    palmistry    0.052s [C46.1 <private> 192.168.1.27:61636<->IPv4#54c8f94a:443 channel-flow] path:satisfied
    39.     12:51:41.787347 +0300    palmistry    0.054s [C46.1 <private> 192.168.1.27:61636<->IPv4#54c8f94a:443 channel-flow] flow:start_nexus
    40.     12:51:41.787802 +0300    palmistry    0.065s [C46.1 <private> 192.168.1.27:61636<->IPv4#54c8f94a:443 channel-flow] flow:receive_nexus
    41.     12:51:41.788730 +0300    palmistry    0.070s [C46.1 <private> 192.168.1.27:61636<->IPv4#54c8f94a:443 channel-flow] flow:start_connect
    42.     12:51:41.789221 +0300    palmistry    0.100s [C46.1 <private> 192.168.1.27:61636<->IPv4#54c8f94a:443 channel-flow] flow:finish_transport
    43.     12:51:41.789915 +0300    palmistry    0.100s [C46 <private> Hostname#85bce954:443 resolver] flow:finish_transport
    44.     12:51:41.790677 +0300    palmistry    0.275s [C46.1 <private> 192.168.1.27:61636<->IPv4#54c8f94a:443 channel-flow] flow:finish_connect
    45.     12:51:41.791124 +0300    palmistry    0.275s [C46 <private> Hostname#85bce954:443 resolver] flow:finish_connect
    46.     12:51:41.791754 +0300    palmistry    0.276s [C46.1 <private> 192.168.1.27:61636<->IPv4#54c8f94a:443 channel-flow] flow:changed_viability
    47.     12:51:41.792196 +0300    palmistry    0.276s [C46 <private> Hostname#85bce954:443 resolver] flow:changed_viability
    48.     12:51:41.796998 +0300    palmistry    0.709s [C46] path:cancel
    49.     12:51:41.803930 +0300    palmistry    nw_protocol_tcp_log_summary [C46.1:3]
    50.     [<private> <private>:61636<-><private>:443]
    51.     Init: 1, Conn_Time: 23.427ms, Syn's: 1, WR_T: 0/0, RD_T: 0/0, TFO: 0/0/0, ECN: 0/0/0, TS: 1
    52.    RTT_Cache: kernel, rtt_upd: 6, rtt: 70.781ms, rtt_var: 46.000ms rtt_nc: 50.125ms, rtt_var_nc: 44.687ms
    53.    12:51:41.805571 +0300    palmistry    nw_endpoint_flow_protocol_disconnected [C46.1 IPv4#54c8f94a:443 cancelled channel-flow (null)] Output protocol disconnected
    54.    12:51:41.806612 +0300    palmistry    nw_connection_report_state_with_handler_locked [C46] reporting state cancelled
    55. hata    12:51:41.806950 +0300    palmistry    nw_protocol_boringssl_get_output_frames(1301) <private>[0x123372d40] get output frames failed, state 8196
    56. hata    12:51:41.807637 +0300    palmistry    nw_protocol_boringssl_get_output_frames(1301) <private>[0x123372d40] get output frames failed, state 8196
    57.    12:51:41.824695 +0300    palmistry    TIC TCP Conn Destroyed [46:0x280945e00]
    58. hata    12:51:41.825270 +0300    palmistry    TIC Read Status [46:0x0]: 1:57
    59. hata    12:51:41.825591 +0300    palmistry    TIC Read Status [46:0x0]: 1:57
    60.    12:51:48.504335 +0300    palmistry    Task <BE4D749B-49FB-4535-A1A5-53A704331D96>.<11> received response, status 200 content U
    61.    12:51:48.504438 +0300    palmistry    Task <BE4D749B-49FB-4535-A1A5-53A704331D96>.<11> done using Connection 34
    62.    12:51:48.504556 +0300    palmistry    Task <BE4D749B-49FB-4535-A1A5-53A704331D96>.<11> response ended
    63.    12:51:48.504682 +0300    palmistry    VERBOSE: network response (OSRequestOnFocus): {
    64.    id = "f6352133-f190-4865-9671-75e759c74b3b";
    65.    success = 1;
    66. }
    67.    12:51:48.637949 +0300    palmistry    Task <31B600F3-7754-437E-A39F-45E08129A7C6>.<0> {strength 0, tls 4, ct 0, sub 0, sig 1, ciphers 0, bundle 0, builtin 0}
    68.    12:51:48.638030 +0300    palmistry    Task <31B600F3-7754-437E-A39F-45E08129A7C6>.<0> now using Connection 44
    69.    12:51:48.638229 +0300    palmistry    Task <31B600F3-7754-437E-A39F-45E08129A7C6>.<0> sent request, body D
    70.    12:51:48.789846 +0300    palmistry    Task <31B600F3-7754-437E-A39F-45E08129A7C6>.<0> received response, status 200 content K
    71.    12:51:48.790105 +0300    palmistry    Task <31B600F3-7754-437E-A39F-45E08129A7C6>.<0> response ended
    72.    12:51:48.790435 +0300    palmistry    Task <31B600F3-7754-437E-A39F-45E08129A7C6>.<0> done using Connection 44
    73.    12:52:00.914878 +0300    palmistry    TIC TCP Conn Cancel [42:0x280942f40]
    74.    12:52:00.915325 +0300    palmistry    [C42 Hostname#5449a048:443 tcp, url hash: acb2098e, tls] cancel
    75.    12:52:00.915886 +0300    palmistry    [C42 Hostname#5449a048:443 tcp, url hash: acb2098e, tls] cancelled
    76.    [C42.1 <private> 192.168.1.27:61632<->IPv4#bc351a21:443]
    77.    Connected Path: satisfied (Path is satisfied), interface: en0, ipv4, dns
    78.    Duration: 61.538s, DNS @0.000s took 0.095s, TCP @0.101s took 0.017s, TLS took 0.067s
    79.    bytes in/out: 3496/2810, packets in/out: 6/6, rtt: 0.043s, retransmitted packets: 0, out-of-order packets: 0
    80.    12:52:00.916065 +0300    palmistry    0.000s [C42 <private> Hostname#5449a048:443 resolver] path:start
    81.    12:52:00.916819 +0300    palmistry    0.000s [C42 <private> Hostname#5449a048:443 resolver] path:satisfied
    82.    12:52:00.917135 +0300    palmistry    0.000s [C42 <private> Hostname#5449a048:443 resolver] resolver:start_dns
    83.    12:52:00.917336 +0300    palmistry    0.095s [C42 <private> Hostname#5449a048:443 resolver] resolver:receive_dns
    84.    12:52:00.917528 +0300    palmistry    0.097s [C42.1 <private> 192.168.1.27:61632<->IPv4#bc351a21:443 channel-flow] path:start
    85.    12:52:00.917681 +0300    palmistry    0.098s [C42.1 <private> 192.168.1.27:61632<->IPv4#bc351a21:443 channel-flow] path:satisfied
    86.    12:52:00.917867 +0300    palmistry    0.098s [C42.1 <private> 192.168.1.27:61632<->IPv4#bc351a21:443 channel-flow] flow:start_nexus
    87.    12:52:00.918123 +0300    palmistry    0.099s [C42.1 <private> 192.168.1.27:61632<->IPv4#bc351a21:443 channel-flow] flow:receive_nexus
    88.    12:52:00.918295 +0300    palmistry    0.101s [C42.1 <private> 192.168.1.27:61632<->IPv4#bc351a21:443 channel-flow] flow:start_connect
    89.    12:52:00.918424 +0300    palmistry    0.118s [C42.1 <private> 192.168.1.27:61632<->IPv4#bc351a21:443 channel-flow] flow:finish_transport
    90.    12:52:00.918761 +0300    palmistry    0.118s [C42 <private> Hostname#5449a048:443 resolver] flow:finish_transport
    91.    12:52:00.919039 +0300    palmistry    0.185s [C42.1 <private> 192.168.1.27:61632<->IPv4#bc351a21:443 channel-flow] flow:finish_connect
    92.    12:52:00.919284 +0300    palmistry    0.187s [C42 <private> Hostname#5449a048:443 resolver] flow:finish_connect
    93.    12:52:00.919713 +0300    palmistry    0.187s [C42.1 <private> 192.168.1.27:61632<->IPv4#bc351a21:443 channel-flow] flow:changed_viability
    94.    12:52:00.920619 +0300    palmistry    0.188s [C42 <private> Hostname#5449a048:443 resolver] flow:changed_viability
    95.    12:52:00.920823 +0300    palmistry    61.538s [C42] path:cancel
    96.    12:52:00.922323 +0300    palmistry    nw_protocol_tcp_log_summary [C42.1:3]
    97.    [<private> <private>:61632<-><private>:443]
    98.    Init: 1, Conn_Time: 17.483ms, Syn's: 1, WR_T: 0/0, RD_T: 0/0, TFO: 0/0/0, ECN: 0/0/0, TS: 1
    99.     RTT_Cache: kernel, rtt_upd: 5, rtt: 43.250ms, rtt_var: 31.937ms rtt_nc: 28.531ms, rtt_var_nc: 24.562ms
    100.     12:52:00.922702 +0300    palmistry    nw_endpoint_flow_protocol_disconnected [C42.1 IPv4#bc351a21:443 cancelled channel-flow (null)] Output protocol disconnected
    101.     12:52:00.922965 +0300    palmistry    nw_connection_report_state_with_handler_locked [C42] reporting state cancelled
    102.     12:52:00.923558 +0300    palmistry    TIC TCP Conn Destroyed [42:0x280942f40]
    103.     12:52:19.215732 +0300    palmistry    TIC TCP Conn Cancel [44:0x280942940]
    104.     12:52:19.216534 +0300    palmistry    [C44 Hostname#a3b7939f:443 tcp, url hash: accf730b, tls] cancel
    105.     12:52:19.217594 +0300    palmistry    [C44 Hostname#a3b7939f:443 tcp, url hash: accf730b, tls] cancelled
    106.     [C44.1 <private> 192.168.1.27:61634<->IPv4#088b26e6:443]
    107.     Connected Path: satisfied (Path is satisfied), interface: en0, ipv4, dns
    108.     Duration: 59.856s, DNS @0.004s took 1.244s, TCP @1.261s took 0.025s, TLS took 0.157s
    109.     bytes in/out: 3886/3012, packets in/out: 6/6, rtt: 0.042s, retransmitted packets: 0, out-of-order packets: 0
    110.     12:52:19.217832 +0300    palmistry    0.003s [C44 <private> Hostname#a3b7939f:443 resolver] path:start
    111.     12:52:19.218099 +0300    palmistry    0.004s [C44 <private> Hostname#a3b7939f:443 resolver] path:satisfied
    112.     12:52:19.218312 +0300    palmistry    0.004s [C44 <private> Hostname#a3b7939f:443 resolver] resolver:start_dns
    113.     12:52:19.218558 +0300    palmistry    1.248s [C44 <private> Hostname#a3b7939f:443 resolver] resolver:receive_dns
    114.     12:52:19.220148 +0300    palmistry    1.251s [C44.1 <private> 192.168.1.27:61634<->IPv4#088b26e6:443 channel-flow] path:start
    115.     12:52:19.220393 +0300    palmistry    1.252s [C44.1 <private> 192.168.1.27:61634<->IPv4#088b26e6:443 channel-flow] path:satisfied
    116.     12:52:19.220653 +0300    palmistry    1.252s [C44.1 <private> 192.168.1.27:61634<->IPv4#088b26e6:443 channel-flow] flow:start_nexus
    117.     12:52:19.220892 +0300    palmistry    1.254s [C44.1 <private> 192.168.1.27:61634<->IPv4#088b26e6:443 channel-flow] flow:receive_nexus
    118.     12:52:19.221203 +0300    palmistry    1.261s [C44.1 <private> 192.168.1.27:61634<->IPv4#088b26e6:443 channel-flow] flow:start_connect
    119.     12:52:19.221426 +0300    palmistry    1.286s [C44.1 <private> 192.168.1.27:61634<->IPv4#088b26e6:443 channel-flow] flow:finish_transport
    120.     12:52:19.221849 +0300    palmistry    1.286s [C44 <private> Hostname#a3b7939f:443 resolver] flow:finish_transport
    121.     12:52:19.222212 +0300    palmistry    1.443s [C44.1 <private> 192.168.1.27:61634<->IPv4#088b26e6:443 channel-flow] flow:finish_connect
    122.     12:52:19.223369 +0300    palmistry    1.445s [C44 <private> Hostname#a3b7939f:443 resolver] flow:finish_connect
    123.     12:52:19.223694 +0300    palmistry    1.445s [C44.1 <private> 192.168.1.27:61634<->IPv4#088b26e6:443 channel-flow] flow:changed_viability
    124.     12:52:19.223987 +0300    palmistry    1.446s [C44 <private> Hostname#a3b7939f:443 resolver] flow:changed_viability
    125.     12:52:19.224902 +0300    palmistry    59.856s [C44] path:cancel
    126.     12:52:19.229667 +0300    palmistry    nw_protocol_tcp_log_summary [C44.1:3]
    127.     [<private> <private>:61634<-><private>:443]
    128.     Init: 1, Conn_Time: 23.273ms, Syn's: 1, WR_T: 0/0, RD_T: 0/0, TFO: 0/0/0, ECN: 0/0/0, TS: 1
    129.    RTT_Cache: process, rtt_upd: 5, rtt: 42.500ms, rtt_var: 19.750ms rtt_nc: 34.218ms, rtt_var_nc: 19.562ms
    130.    12:52:19.230264 +0300    palmistry    nw_endpoint_flow_protocol_disconnected [C44.1 IPv4#088b26e6:443 cancelled channel-flow (null)] Output protocol disconnected
    131.    12:52:19.231189 +0300    palmistry    nw_connection_report_state_with_handler_locked [C44] reporting state cancelled
    132.    12:52:19.232401 +0300    palmistry    TIC TCP Conn Destroyed [44:0x280942940]
     
  4. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    We have no control over the timing. We are simply a pass through service for the store APIs. The logs do not look familiar. As mentioned, I would first remove the delay in your code. Or just arbitrarily increase it to 15 seconds from 5, to rule it out. Did you add elapsed time calculations to a Debug.Log statement or similar? Where is it taking the time?
     
  5. ozgurdemm17

    ozgurdemm17

    Joined:
    Jun 7, 2019
    Posts:
    4
    IAP sdk works with android no problem. And delay code not start after press button. The delay is not caused by that code. Now I will try to install a different sdk.
     
  6. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Without the requested information, unfortunately I would not have additional suggestions. Good luck on your project!
     
  7. ozgurdemm17

    ozgurdemm17

    Joined:
    Jun 7, 2019
    Posts:
    4
    Sorry for taking your time. The problem stems from apple servers. Thank You. :)
     
    Ontario likes this.