DETAILS
-
Unity 5.6.0f3
-
Unity IAP version 1.10.1
-
Android version 5
I DID
- Published app in alpha testing
- Confirmed alpha tester
- Set up product in store
- Also tried more 2 different scripts/plugins(from assetstore) and none of them worked
- I saw the other topic about this issue, but moderators said that it will be fixed in next version, but it seems to persist
DESCRIPTION
- Ok, when someone is trying to buy a NON-Consumable product, it’s working fine till next restart of app;
- On second start, game triggers OnPurchaseFailed with error “Dublicate Transaction”, not showing what i want(a message for success loading)
- I’m just trying to find if the following product is purchased.
USER EXPERIENCE
- Part one(before purchasing), you can see logs - Dropbox - File Deleted - Simplify your life
- Part two(after purchasing), see logs for more info - Dropbox - File Deleted - Simplify your life
IAPManager, connector with purchasing system
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;
// Deriving the Purchaser class from IStoreListener enables it to receive messages from Unity Purchasing.
public class IAPManager : MonoBehaviour, IStoreListener
{
public static IAPManager Instance { set; get; }
private static IStoreController m_StoreController; // The Unity Purchasing system.
private static IExtensionProvider m_StoreExtensionProvider; // The store-specific Purchasing subsystems.
public static string EXTRA_FEATURES = "features_1";
private void Awake()
{
Instance = this;
}
private void Start()
{
SetReference ();
}
public bool CheckBuyState(string id)
{
SetReference ();
Product product = m_StoreController.products.WithID(id);
if (product != null && product.hasReceipt) { return true; }
else { return false; }
}
private void SetReference()
{
// If we haven't set up the Unity Purchasing reference
if (m_StoreController == null)
{
// Begin to configure our connection to Purchasing
InitializePurchasing();
}
}
public void InitializePurchasing()
{
// If we have already connected to Purchasing ...
if (IsInitialized())
{
// ... we are done here.
return;
}
// Create a builder, first passing in a suite of Unity provided stores.
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.AddProduct(EXTRA_FEATURES, ProductType.NonConsumable);
// Kick off the remainder of the set-up with an asynchrounous call, passing the configuration
// and this class' instance. Expect a response either in OnInitialized or OnInitializeFailed.
UnityPurchasing.Initialize(this, builder);
}
private bool IsInitialized()
{
// Only say we are initialized if both the Purchasing references are set.
return m_StoreController != null && m_StoreExtensionProvider != null;
}
public void BuyExtraFeatures()
{
BuyProductID(EXTRA_FEATURES);
}
private void BuyProductID(string productId)
{
// If Purchasing has been initialized ...
if (IsInitialized())
{
// ... look up the Product reference with the general product identifier and the Purchasing
// system's products collection.
Product product = m_StoreController.products.WithID(productId);
// If the look up found a product for this device's store and that product is ready to be sold ...
if (product != null && product.availableToPurchase)
{
GM.logText.text += string.Format ("Purchasing product asychronously: '{0}'\n", product.definition.id);
Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
// ... buy the product. Expect a response either through ProcessPurchase or OnPurchaseFailed
// asynchronously.
m_StoreController.InitiatePurchase(product);
}
// Otherwise ...
else
{
GM.logText.text += "BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase\n";
// ... report the product look-up failure situation
Debug.Log("BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
}
}
// Otherwise ...
else
{
GM.logText.text += "BuyProductID FAIL. Not initialized.\n";
// ... report the fact Purchasing has not succeeded initializing yet. Consider waiting longer or
// retrying initiailization.
Debug.Log("BuyProductID FAIL. Not initialized.");
}
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
GM.logText.text += "OnInitialized: PASS\n";
// Purchasing has succeeded initializing. Collect our Purchasing references.
Debug.Log("OnInitialized: PASS");
// Overall Purchasing system, configured with products for this application.
m_StoreController = controller;
// Store specific subsystem, for accessing device-specific store features.
m_StoreExtensionProvider = extensions;
}
public void OnInitializeFailed(InitializationFailureReason error)
{
GM.logText.text += "OnInitializeFailed InitializationFailureReason:" + error + "\n";
// Purchasing set-up has not succeeded. Check error for reason. Consider sharing this reason with the user.
Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
}
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
{
if (String.Equals(args.purchasedProduct.definition.id, EXTRA_FEATURES, StringComparison.Ordinal))
{
gameObject.GetComponent<GM> ().premiumIcon.SetActive (true);
GM.logText.text += string.Format("ProcessPurchase: PASS. Product: '{0}'\n", args.purchasedProduct.definition.id);
Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
PlayerPrefs.SetInt ("premium", 1);
AndroidNativeFunctions.ShowToast ("Purchase confirmed, reload apk", false);
}
else
{
GM.logText.text += string.Format("ProcessPurchase: FAIL. Unrecognized product: '{0}'\n", args.purchasedProduct.definition.id);
Debug.Log(string.Format("ProcessPurchase: FAIL. Unrecognized product: '{0}'", args.purchasedProduct.definition.id));
}
// Return a flag indicating whether this product has completely been received, or if the application needs
// to be reminded of this purchase at next app launch. Use PurchaseProcessingResult.Pending when still
// saving purchased products to the cloud, and when that save is delayed.
return PurchaseProcessingResult.Complete;
}
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
GM.logText.text += string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}\n", product.definition.storeSpecificId, failureReason);
// A product purchase attempt did not succeed. Check failureReason for more detail. Consider sharing
// this reason with the user to guide their troubleshooting actions.
Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
}
}
GameManager, script of the game
using UnityEngine;
using UnityEngine.UI;
public class GM : MonoBehaviour {
public GameObject premiumIcon;
public static Text logText;
void Awake()
{
logText = GameObject.Find ("Log").GetComponent<Text> ();
}
void Start()
{
if (IAPManager.Instance.CheckBuyState (IAPManager.EXTRA_FEATURES)) {
EnablePremium (0);
return;
}
if (PlayerPrefs.GetInt("premium") == 1)
{
EnablePremium (1);
}
}
void EnablePremium(int i)
{
premiumIcon.SetActive (true);
if (i == 0) {
logText.text += "Loaded from IAPManager\n";
Debug.Log ("Loaded from IAPManager");
AndroidNativeFunctions.ShowToast ("Loaded from IAPManager", false);
} else if (i == 1) {
logText.text += "Loaded from PlayerPrefs\n";
Debug.Log ("Loaded from PlayerPrefs");
AndroidNativeFunctions.ShowToast ("Loaded from PlayerPrefs", false);
}
}
public void BuyExtra()
{
IAPManager.Instance.BuyExtraFeatures ();
}
public void ClearPrefs()
{
if (PlayerPrefs.HasKey ("premium")) {
PlayerPrefs.DeleteKey ("premium");
logText.text += "Premium key record was successfuly deleted\n";
premiumIcon.SetActive (false);
} else {
logText.text += "Key not found, maybe already deleted\n";
}
}
}
Please help me, i really need to solve this problem, i had to update my app on store in nearly future.