Search Unity

[Closed] Google Play IAP Button no response.

Discussion in 'Unity IAP' started by rogaroga, Jan 27, 2017.

Thread Status:
Not open for further replies.
  1. rogaroga

    rogaroga

    Joined:
    Oct 30, 2016
    Posts:
    10
    Description of issue:
    I've put my project into Alpha publication on the Google Play store, and I'm not able to get the codeless IAP buttons to respond. In the editor, they do respond and send me to Fake Store as expected (Although I should note that in editor I am having THIS separate issue, that maybe is related????).

    Purchasing Script:
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Purchasing;
    5.  
    6. // Placing the Purchaser class in the CompleteProject namespace allows it to interact with other scripts.
    7. namespace CompleteProject
    8. {
    9.     // Deriving the Purchaser class from IStoreListener enables it to receive messages from Unity Purchasing.
    10.     public class Purchaser : MonoBehaviour, IStoreListener
    11.     {
    12.         private static IStoreController m_StoreController;          // The Unity Purchasing system.
    13.         private static IExtensionProvider m_StoreExtensionProvider; // The store-specific Purchasing subsystems.
    14.  
    15.         // Product identifiers for all products capable of being purchased:
    16.         // "convenience" general identifiers for use with Purchasing, and their store-specific identifier
    17.         // counterparts for use with and outside of Unity Purchasing. Define store-specific identifiers
    18.         // also on each platform's publisher dashboard (iTunes Connect, Google Play Developer Console, etc.)
    19.  
    20.         // General product identifiers for the consumable, non-consumable, and subscription products.
    21.         // Use these handles in the code to reference which product to purchase. Also use these values
    22.         // when defining the Product Identifiers on the store. Except, for illustration purposes, the
    23.         // kProductIDSubscription - it has custom Apple and Google identifiers. We declare their store-
    24.         // specific mapping to Unity Purchasing's AddProduct, below.
    25.         public static string Coins150 = "150coins";
    26.         public static string Coins900 = "900coins";
    27.         public static string Coins2000 = "2000coins";
    28.         public static string Coins5000 = "5000coins";
    29.         public static string Coins30000 = "30000coins";
    30.  
    31.         // Apple App Store-specific product identifier.
    32.  
    33.         // Google Play Store-specific product identifier.
    34.  
    35.  
    36.         void Start()
    37.         {
    38.             // If we haven't set up the Unity Purchasing reference
    39.             if (m_StoreController == null)
    40.             {
    41.                 // Begin to configure our connection to Purchasing
    42.                 InitializePurchasing();
    43.             }
    44.         }
    45.  
    46.         public void InitializePurchasing()
    47.         {
    48.             // If we have already connected to Purchasing ...
    49.             if (IsInitialized())
    50.             {
    51.                 // ... we are done here.
    52.                 return;
    53.             }
    54.  
    55.             // Create a builder, first passing in a suite of Unity provided stores.
    56.             var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    57.  
    58.             // Add a product to sell / restore by way of its identifier, associating the general identifier
    59.             // with its store-specific identifiers.
    60.             builder.AddProduct(Coins150, ProductType.Consumable);
    61.             builder.AddProduct(Coins900, ProductType.Consumable);
    62.             builder.AddProduct(Coins2000, ProductType.Consumable);
    63.             builder.AddProduct(Coins5000, ProductType.Consumable);
    64.             builder.AddProduct(Coins30000, ProductType.Consumable);
    65.             // Continue adding the non-consumable product.
    66.  
    67.             // And finish adding the subscription product.
    68.             // if the Product ID was configured differently between Apple and Google stores note that
    69.             // the store-specific IDs must only be referenced here.
    70.  
    71.             // Kick off the remainder of the set-up with an asynchrounous call, passing the configuration
    72.             // and this class' instance. Expect a response either in OnInitialized or OnInitializeFailed.
    73.             UnityPurchasing.Initialize(this, builder);
    74.         }
    75.  
    76.  
    77.         private bool IsInitialized()
    78.         {
    79.             // Only say we are initialized if both the Purchasing references are set.
    80.             return m_StoreController != null && m_StoreExtensionProvider != null;
    81.         }
    82.  
    83.  
    84.         public void Buy150Coins()
    85.         {
    86.             // Buy the consumable product using its general identifier. Expect a response either
    87.             // through ProcessPurchase or OnPurchaseFailed asynchronously.
    88.             BuyProductID(Coins150);
    89.         }
    90.         public void Buy900Coins()
    91.         {
    92.             // Buy the consumable product using its general identifier. Expect a response either
    93.             // through ProcessPurchase or OnPurchaseFailed asynchronously.
    94.             BuyProductID(Coins900);
    95.         }
    96.         public void Buy2000Coins()
    97.         {
    98.             // Buy the consumable product using its general identifier. Expect a response either
    99.             // through ProcessPurchase or OnPurchaseFailed asynchronously.
    100.             BuyProductID(Coins2000);
    101.         }
    102.         public void Buy5000Coins()
    103.         {
    104.             // Buy the consumable product using its general identifier. Expect a response either
    105.             // through ProcessPurchase or OnPurchaseFailed asynchronously.
    106.             BuyProductID(Coins5000);
    107.         }
    108.         public void Buy30000Coins()
    109.         {
    110.             // Buy the consumable product using its general identifier. Expect a response either
    111.             // through ProcessPurchase or OnPurchaseFailed asynchronously.
    112.             BuyProductID(Coins30000);
    113.         }
    114.  
    115.  
    116.         void BuyProductID(string productId)
    117.         {
    118.             // If Purchasing has been initialized ...
    119.             if (IsInitialized())
    120.             {
    121.                 // ... look up the Product reference with the general product identifier and the Purchasing
    122.                 // system's products collection.
    123.                 Product product = m_StoreController.products.WithID(productId);
    124.  
    125.                 // If the look up found a product for this device's store and that product is ready to be sold ...
    126.                 if (product != null && product.availableToPurchase)
    127.                 {
    128.                     Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
    129.                     // ... buy the product. Expect a response either through ProcessPurchase or OnPurchaseFailed
    130.                     // asynchronously.
    131.                     m_StoreController.InitiatePurchase(product);
    132.                 }
    133.                 // Otherwise ...
    134.                 else
    135.                 {
    136.                     // ... report the product look-up failure situation
    137.                     Debug.Log("BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
    138.                 }
    139.             }
    140.             // Otherwise ...
    141.             else
    142.             {
    143.                 // ... report the fact Purchasing has not succeeded initializing yet. Consider waiting longer or
    144.                 // retrying initiailization.
    145.                 Debug.Log("BuyProductID FAIL. Not initialized.");
    146.             }
    147.         }
    148.  
    149.  
    150.         // Restore purchases previously made by this customer. Some platforms automatically restore purchases, like Google.
    151.         // Apple currently requires explicit purchase restoration for IAP, conditionally displaying a password prompt.
    152.         public void RestorePurchases()
    153.         {
    154.             // If Purchasing has not yet been set up ...
    155.             if (!IsInitialized())
    156.             {
    157.                 // ... report the situation and stop restoring. Consider either waiting longer, or retrying initialization.
    158.                 Debug.Log("RestorePurchases FAIL. Not initialized.");
    159.                 return;
    160.             }
    161.  
    162.             // If we are running on an Apple device ...
    163.             if (Application.platform == RuntimePlatform.IPhonePlayer ||
    164.                 Application.platform == RuntimePlatform.OSXPlayer)
    165.             {
    166.                 // ... begin restoring purchases
    167.                 Debug.Log("RestorePurchases started ...");
    168.  
    169.                 // Fetch the Apple store-specific subsystem.
    170.                 var apple = m_StoreExtensionProvider.GetExtension<IAppleExtensions>();
    171.                 // Begin the asynchronous process of restoring purchases. Expect a confirmation response in
    172.                 // the Action<bool> below, and ProcessPurchase if there are previously purchased products to restore.
    173.                 apple.RestoreTransactions((result) => {
    174.                     // The first phase of restoration. If no more responses are received on ProcessPurchase then
    175.                     // no purchases are available to be restored.
    176.                     Debug.Log("RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore.");
    177.                 });
    178.             }
    179.             // Otherwise ...
    180.             else
    181.             {
    182.                 // We are not running on an Apple device. No work is necessary to restore purchases.
    183.                 Debug.Log("RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform);
    184.             }
    185.         }
    186.  
    187.  
    188.         //
    189.         // --- IStoreListener
    190.         //
    191.  
    192.         public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    193.         {
    194.             // Purchasing has succeeded initializing. Collect our Purchasing references.
    195.             Debug.Log("OnInitialized: PASS");
    196.  
    197.             // Overall Purchasing system, configured with products for this application.
    198.             m_StoreController = controller;
    199.             // Store specific subsystem, for accessing device-specific store features.
    200.             m_StoreExtensionProvider = extensions;
    201.         }
    202.  
    203.  
    204.         public void OnInitializeFailed(InitializationFailureReason error)
    205.         {
    206.             // Purchasing set-up has not succeeded. Check error for reason. Consider sharing this reason with the user.
    207.             Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
    208.         }
    209.  
    210.  
    211.         public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    212.         {
    213.             // A consumable product has been purchased by this user.
    214.             if (String.Equals(args.purchasedProduct.definition.id, Coins150, StringComparison.Ordinal))
    215.             {
    216.                 Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
    217.                 // The consumable item has been successfully purchased, optional, add code here to grant item.
    218.             }
    219.             if (String.Equals(args.purchasedProduct.definition.id, Coins900, StringComparison.Ordinal))
    220.             {
    221.                 Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
    222.                 // The consumable item has been successfully purchased, optional, add code here to grant item.
    223.             }
    224.             if (String.Equals(args.purchasedProduct.definition.id, Coins2000, StringComparison.Ordinal))
    225.             {
    226.                 Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
    227.                 // The consumable item has been successfully purchased, optional, add code here to grant item.
    228.             }
    229.             if (String.Equals(args.purchasedProduct.definition.id, Coins5000, StringComparison.Ordinal))
    230.             {
    231.                 Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
    232.                 // The consumable item has been successfully purchased, optional, add code here to grant item.
    233.             }
    234.             if (String.Equals(args.purchasedProduct.definition.id, Coins30000, StringComparison.Ordinal))
    235.             {
    236.                 Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
    237.                 // The consumable item has been successfully purchased, optional, add code here to grant item.
    238.             }
    239.             // Or ... an unknown product has been purchased by this user.
    240.             else
    241.             {
    242.                 Debug.Log(string.Format("ProcessPurchase: FAIL. Unrecognized product: '{0}'", args.purchasedProduct.definition.id));
    243.             }
    244.  
    245.             // Return a flag indicating whether this product has completely been received, or if the application needs
    246.             // to be reminded of this purchase at next app launch. Use PurchaseProcessingResult.Pending when still
    247.             // saving purchased products to the cloud, and when that save is delayed.
    248.             return PurchaseProcessingResult.Complete;
    249.         }
    250.  
    251.  
    252.         public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
    253.         {
    254.             // A product purchase attempt did not succeed. Check failureReason for more detail. Consider sharing
    255.             // this reason with the user to guide their troubleshooting actions.
    256.             Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
    257.         }
    258.  
    259.         public void BankPurchase (int howMany){
    260.             int currentCoins = Keepers.keepers.bank;
    261.             Keepers.keepers.bank = currentCoins + howMany;
    262.             Keepers.keepers.Save ();
    263.         }
    264.     }
    265. }


    Device Logs:
    Code (csharp):
    1. 01-26 16:06:07.829  1358  2150 I InputDispatcher: Delivering touch to (28673): a
    2. ction: 0x1, toolType: 1
    3. 01-26 16:06:07.829 28673 28673 D ViewRootImpl: ViewPostImeInputStage processPoin
    4. ter 1
    5. 01-26 16:06:07.859 28673 28686 I Unity   : IAPButton.PurchaseProduct() with prod
    6. uct ID: 150coins
    7. 01-26 16:06:07.859 28673 28686 I Unity   :
    8. 01-26 16:06:07.859 28673 28686 I Unity   : (Filename: ./artifacts/generated/comm
    9. on/runtime/DebugBindings.gen.cpp Line: 51)
    10. 01-26 16:06:07.859 28673 28686 I Unity   :
    11. 01-26 16:06:07.869 28673 28686 I Unity   : NullReferenceException: Object refere
    12. nce not set to an instance of an object
    13. 01-26 16:06:07.869 28673 28686 I Unity   :   at UnityEngine.Purchasing.IAPButton
    14. +IAPButtonStoreManager.InitiatePurchase (System.String productID) [0x00000] in <
    15. filename unknown>:0
    16. 01-26 16:06:07.869 28673 28686 I Unity   :   at UnityEngine.Purchasing.IAPButton
    17. .PurchaseProduct () [0x00000] in <filename unknown>:0
    18. 01-26 16:06:07.869 28673 28686 I Unity   :   at UnityEngine.Events.InvokableCall
    19. .Invoke (System.Object[] args) [0x00000] in <filename unknown>:0
    20. 01-26 16:06:07.869 28673 28686 I Unity   :   at UnityEngine.Events.InvokableCall
    21. List.Invoke (System.Object[] parameters) [0x00000] in <filename unknown>:0
    22. 01-26 16:06:07.869 28673 28686 I Unity   :   at UnityEngine.Events.UnityEventBas
    23. e.Invoke (System.Object[] parameters) [0x00000] in <filename unknown>:0
    24. 01-26 16:06:07.869 28673 28686 I Unity   :   at UnityEngine.Events.UnityEvent.In
    25. voke () [0x00000] in <filename unknown>:0
    26. 01-26 16:06:07.869 28673 28686 I Unity   :   at UnityEngine.UI.Button.Press () [
    27. 0x00000] in <filename unknown>:0
    28. 01-26 16:06:07.869 28673 28686 I Unity   :   at UnityEngine.UI.Button.OnPointerC
    29. lick (UnityEngine.EventSystems.PointerEventData eventData) [0x00000] in <filenam
    30. e unknown>:0
    31. 01-26 16:06:07.869 28673 28686 I Unity   :   at UnityEngine.EventSystems.Execute
    32. Events.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.

    Unity Version: 5.5.0f3

    Unity IAP Version: 1.9.3

    Platforms/Stores targeting: Android right now, iOS next.
     
  2. rogaroga

    rogaroga

    Joined:
    Oct 30, 2016
    Posts:
    10
    Sorry to reply to my own thread, but reading and reading to find my mistake, I came across the following, and think it may be my mistake... can anyone confirm that the behavior described above would be caused by this:

    SOURCE

    EDIT: Nope, not my problem, non publisher account does same thing.
     
    Last edited: Jan 27, 2017
  3. ap-unity

    ap-unity

    Unity Technologies

    Joined:
    Aug 3, 2016
    Posts:
    1,519
    @rogaroga,

    Your log is showing a Null Reference Exception when clicking the button. Could you double check that all of your references are set properly.
     
  4. rogaroga

    rogaroga

    Joined:
    Oct 30, 2016
    Posts:
    10
    In the editor pressing the button pops open the Fake Store with the option to buy or cancel. How can that be happening and then still have a null reference in game after building?
     
  5. rogaroga

    rogaroga

    Joined:
    Oct 30, 2016
    Posts:
    10
    I found my problem with the references. In my above code, I didn't specifically reference my googleplay ID for each product, just the general handler for each product. Updated code that does work:
    Code (CSharp):
    1.     public static string Coins150 = "150coins";
    2.         public static string Coins900 = "900coins";
    3.         public static string Coins2000 = "2000coins";
    4.         public static string Coins5000 = "5000coins";
    5.         public static string Coins30000 = "30000coins";
    6.  
    7.         // Apple App Store-specific product identifier.
    8.  
    9.         // Google Play Store-specific product identifier.
    10.         private static string kProductNameGooglePlayCoins150 = "150coins";
    11.         private static string kProductNameGooglePlayCoins900 = "900coins";
    12.         private static string kProductNameGooglePlayCoins2000 = "2000coins";
    13.         private static string kProductNameGooglePlayCoins5000 = "5000coins";
    14.         private static string kProductNameGooglePlayCoins30000 = "30000coins";
    15.  
    16.         void Start()
    17.         {
    18.             // If we haven't set up the Unity Purchasing reference
    19.             if (m_StoreController == null)
    20.             {
    21.                 // Begin to configure our connection to Purchasing
    22.                 InitializePurchasing();
    23.             }
    24.         }
    25.  
    26.         public void InitializePurchasing()
    27.         {
    28.             // If we have already connected to Purchasing ...
    29.             if (IsInitialized())
    30.             {
    31.                 // ... we are done here.
    32.                 return;
    33.             }
    34.  
    35.             // Create a builder, first passing in a suite of Unity provided stores.
    36.             var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    37.  
    38.             // Add a product to sell / restore by way of its identifier, associating the general identifier
    39.             // with its store-specific identifiers.
    40.             builder.AddProduct(Coins150, ProductType.Consumable, new IDs(){ {kProductNameGooglePlayCoins150, GooglePlay.Name} });
    41.             builder.AddProduct(Coins900, ProductType.Consumable, new IDs(){ {kProductNameGooglePlayCoins900, GooglePlay.Name} });
    42.             builder.AddProduct(Coins2000, ProductType.Consumable, new IDs(){ {kProductNameGooglePlayCoins2000, GooglePlay.Name} });
    43.             builder.AddProduct(Coins5000, ProductType.Consumable, new IDs(){ {kProductNameGooglePlayCoins5000, GooglePlay.Name} });
    44.             builder.AddProduct(Coins30000, ProductType.Consumable, new IDs(){ {kProductNameGooglePlayCoins30000, GooglePlay.Name} });
     
  6. ap-unity

    ap-unity

    Unity Technologies

    Joined:
    Aug 3, 2016
    Posts:
    1,519
    @rogaroga,

    This doesn't look like any error I've seen before. Would you be able to send a sample project where this happens?
    https://analytics.cloud.unity3d.com/support/

    The FakeStore only works in the editor. The FakeStore is meant to simulate the platform stores that aren't available in the Editor. Once you create a build for Android and iOS, you must use the product IDs that you created in the store.
    https://docs.unity3d.com/Manual/UnityIAPAppleConfiguration.html
    https://docs.unity3d.com/Manual/UnityIAPGoogleConfiguration.html

    Another thing I didn't notice before, if you are using Codeless IAP, then you don't need to create a purchasing script. That is all handled by setting up the IAP Catalog and creating individual buttons.

    This shouldn't be necessary. The store-specific IDs are only needed in cases where you don't have the same product ID across stores. For example, if your 500 gold coin product is called "500gold" in Google Play but "gold500" in iTunes, then you would need a store-specific ID to reconcile this. In your example, there should be no benefit to adding them.

    If you are using the Codeless IAP, then you can see the purchasing script that is used in:
    Plugins/UnityPurchasing/script/IAPButton.cs
     
Thread Status:
Not open for further replies.