Search Unity

Error in IAP on iOS is causing APP rejection.

Discussion in 'Unity IAP' started by phpnato, Sep 27, 2018.

  1. phpnato

    phpnato

    Joined:
    Aug 16, 2013
    Posts:
    14
    AppStore review rejected the application 4 times because of the error in the IAP. When performing the test with a SandBox account the IAP works perfectly. However, if you logged in with a real user account the error occurs.

    Comments:
    • Before submitting the app for review, we've made changes to the IAPs and all are in the status of "Waiting for review"
    • In-App Purchase is active in Xcode Capabilities
    • The code works if you are logged in with a sandbox account.
    • The same code generates the error if it is logged in with a real user account.


    Error Log:

    Purchase failure description message: APPLE_Can't connect to the iTunes Store
    UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
    UnityEngine.Logger:Log(LogType, Object)
    UnityEngine.Debug:Log(Object)
    Loja:OnPurchaseFailed(Product, PurchaseFailureReason)
    UnityEngine.Purchasing.StoreListenerProxy:OnPurchaseFailed(Product, PurchaseFailureReason)
    UnityEngine.Purchasing.PurchasingManager:OnPurchaseFailed(PurchaseFailureDescription)
    UnityEngine.Purchasing.JSONStore:OnPurchaseFailed(PurchaseFailureDescription, String)
    UnityEngine.Purchasing.<>c__DisplayClass35_0:<MessageCallback>b__0()
    UnityEngine.Purchasing.Extension.UnityUtil:Update()


    Unity Versions: 2018.2.9f1, 2018.2.8f1 and 2018.2.7f1

    Unity IAP versions tested: 1.20 and 1.21

    Xcode versions: 9.4 and 10.


    Simplified source code:

    Code (CSharp):
    1. using System.Collections;
    2. using DG.Tweening;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6. using UnityEngine.Purchasing;
    7. using BestHTTP;
    8. using System.Linq;
    9. using System;
    10.  
    11.  
    12. public class Loja : MonoBehaviour, IStoreListener {
    13.  
    14.  
    15.     private IStoreController controller;
    16.     private IExtensionProvider extensions;
    17.  
    18.     private Product itemCompra;
    19.  
    20.     private ConfigurationBuilder builder;
    21.  
    22.     private IExtensionProvider Extensions { get; set; }
    23.  
    24.  
    25.  
    26.  
    27.     void Start() {
    28.        
    29.  
    30.         builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    31.  
    32.         carregarListaProdutos();
    33.  
    34.     }
    35.  
    36.     void OnEnable() {
    37.      
    38.     }
    39.  
    40.     void OnDisable() {
    41.  
    42.     }
    43.  
    44.     // Update is called once per frame
    45.     void Update() {
    46.  
    47.     }
    48.  
    49.     public void carregarListaProdutos() {
    50.        
    51.         builder.AddProduct("roleta", ProductType.Consumable);
    52.         UnityPurchasing.Initialize(this, builder);
    53.     }
    54.  
    55.  
    56.  
    57.     public void comprarRoleta() {
    58.         comprouRoleta = true;
    59.  
    60.         Product[] products = controller.products.all;
    61.  
    62.         try {
    63.             controller.InitiatePurchase(products[0]);
    64.         }
    65.         catch(Exception e) {
    66.             Debug.Log("Erro ao comprar Roleta IAP");
    67.             Debug.Log(e.StackTrace);
    68.         }
    69.  
    70.     }
    71.  
    72.  
    73.  
    74.  
    75.  
    76.     /// <summary>
    77.     /// Called when Unity IAP is ready to make purchases.
    78.     /// </summary>
    79.     public void OnInitialized(IStoreController controller, IExtensionProvider extensions) {
    80.         this.controller = controller;
    81.         this.extensions = extensions;
    82.  
    83.        
    84.         exibirBotaoLoja(false);
    85.  
    86. #if UNITY_IOS
    87.         extensions.GetExtension<IAppleExtensions>().RefreshAppReceipt(receipt => {
    88.             // This handler is invoked if the request is successful.
    89.             // Receipt will be the latest app receipt.
    90.             Console.WriteLine(receipt);
    91.            
    92.  
    93.         },
    94.             () => {
    95.                 // This handler will be invoked if the request fails,
    96.                 // such as if the network is unavailable or the user
    97.                 // enters the wrong password.
    98.  
    99.                 lojaDisponivel = false;
    100.         });
    101.  
    102.         var apple = extensions.GetExtension<IAppleExtensions>();
    103.         apple.RegisterPurchaseDeferredListener(OnDeferred);
    104.  
    105. #endif
    106.  
    107.  
    108.  
    109.     }
    110.  
    111.     /// <summary>
    112.     /// Called when Unity IAP encounters an unrecoverable initialization error.
    113.     ///
    114.     /// Note that this will not be called if Internet is unavailable; Unity IAP
    115.     /// will attempt initialization until it becomes available.
    116.     /// </summary>
    117.     public void OnInitializeFailed(InitializationFailureReason error) {
    118.  
    119.         Debug.Log("Erro ao iniciar IAP: " + error);
    120.         switch(error) {
    121.             case InitializationFailureReason.AppNotKnown:
    122.                 Debug.LogError("Is your App correctly uploaded on the relevant publisher console?");
    123.                 break;
    124.             case InitializationFailureReason.PurchasingUnavailable:
    125.                 // Ask the user if billing is disabled in device settings.
    126.                 Debug.Log("Billing disabled!");
    127.                 break;
    128.             case InitializationFailureReason.NoProductsAvailable:
    129.                 // Developer configuration error; check product metadata.
    130.                 Debug.Log("No products available for purchase!");
    131.                 break;
    132.         }
    133.  
    134.     }
    135.  
    136.     /// <summary>
    137.     /// Called when a purchase completes.
    138.     ///
    139.     /// May be called at any time after OnInitialized().
    140.     /// </summary>
    141.     public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e) {
    142.  
    143.         Debug.Log(e.purchasedProduct.metadata.localizedTitle);
    144.    
    145.  
    146.         return PurchaseProcessingResult.Complete;
    147.    
    148.     }
    149.  
    150.     /// <summary>
    151.     /// Called when a purchase fails.
    152.     /// </summary>
    153.     public void OnPurchaseFailed(Product i, PurchaseFailureReason p) {
    154.  
    155.         Debug.Log("Erro compra: " + p);
    156.        
    157.     }
    158.  
    159.  
    160.     // Restore purchases previously made by this customer. Some platforms automatically restore purchases, like Google.
    161.     // Apple currently requires explicit purchase restoration for IAP, conditionally displaying a password prompt.
    162.     public void restaurarCompras(){
    163.    
    164.         // If we are running on an Apple device ...
    165.         if (Application.platform == RuntimePlatform.IPhonePlayer ||
    166.             Application.platform == RuntimePlatform.OSXPlayer)
    167.         {
    168.             // ... begin restoring purchases
    169.             Debug.Log("RestorePurchases started ...");
    170.  
    171.  
    172.             // Fetch the Apple store-specific subsystem.
    173.             var apple = extensions.GetExtension<IAppleExtensions>();
    174.             // Begin the asynchronous process of restoring purchases. Expect a confirmation response in
    175.             // the Action<bool> below, and ProcessPurchase if there are previously purchased products to restore.
    176.             apple.RestoreTransactions((result) => {
    177.                 // The first phase of restoration. If no more responses are received on ProcessPurchase then
    178.                 // no purchases are available to be restored.
    179.                 Debug.Log("RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore.");
    180.             });
    181.         }
    182.         // Otherwise ...
    183.         else
    184.         {
    185.             // We are not running on an Apple device. No work is necessary to restore purchases.
    186.             Debug.Log("RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform);
    187.         }
    188.  
    189.     }
    190.  
    191.  
    192.     /// <summary>
    193.     /// iOS Specific.
    194.     /// This is called as part of Apple's 'Ask to buy' functionality,
    195.     /// when a purchase is requested by a minor and referred to a parent
    196.     /// for approval.
    197.     ///
    198.     /// When the purchase is approved or rejected, the normal purchase events
    199.     /// will fire.
    200.     /// </summary>
    201.     /// <param name="item">Item.</param>
    202.     private void OnDeferred(Product item) {
    203.         Debug.Log("Purchase deferred: " + item.definition.id);
    204.     }
    205.  
    206.  
    207.  
    208.  
    209. }
    210.  
     
  2. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Sounds like an issue on the Apple side "APPLE_Can't connect to the iTunes Store". This is not something we have any control over, particularly any differences between their Sandbox and Release environments, they should always behave the same. I would recommend to wait a day or so, and try to submit again. Have you submitted an appeal?
     
  3. phpnato

    phpnato

    Joined:
    Aug 16, 2013
    Posts:
    14
    We have been experiencing this problem for over 40 days. In this period we have already sent the application for review 5 times. We have already opened a support at Apple and have not yet returned. We do not know what to do. I do not know who the problem is.
     
  4. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    You will need to wait to hear from Apple. Not related, but I see a console.writeline in your code, is this intentional?
     
  5. lukos

    lukos

    Joined:
    Nov 11, 2012
    Posts:
    22
    @JeffDUnity3D We have the similar issue. This issue is definitely on the Unity IAP side.
    We are using 1.20

    Interesting fact. IAP are working as expected with UK account and failing in USA, unfortunately, this is where apps are tested. We have been rejected twice for this reason.

    @nicholasr can you assist with this? We can submit the bug report. Urgent
     
  6. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    @lukos Rejected for what reason, you mean Failed to connect to Apple store? We are simply a pass through for the Apple store. For clarity, may I ask, why are you saying it is "definitely on the Unity IAP side"? Any country specific behavior would be on the Apple side. I'm assuming because it works in UK and failing in USA? Please provide the device logs when you see the issue https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/