I have the same problem. I initialize manually and I get no Fake Store Panel. I face one more problem: The price in the editor is always zero. Is it normal, too?
EDIT: Price is not showing on Android device as well. I think there is a problem with the initialization.
I am using v 4.4.1. Here is my init script:
public class MyIAPInit : MonoBehaviour, IStoreListener
{
public MyIAPManager myIAPManager;
private IStoreController m_StoreController; // The Unity Purchasing system.
private IExtensionProvider m_StoreExtensionProvider; // The store-specific Purchasing subsystems.
private void Start()
{
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());
// Add products to sell / restore by way of its identifier, associating the general identifier
// with its store-specific identifiers.
builder.AddProduct("molly_key1", ProductType.Consumable);
builder.AddProduct("molly_key2", ProductType.Consumable);
builder.AddProduct("molly_key3", ProductType.Consumable);
builder.AddProduct("molly_key4", ProductType.Consumable);
builder.AddProduct("molly_egypt", ProductType.Consumable);
builder.AddProduct("molly_russia", ProductType.Consumable);
// 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);
}
// OUR CODE: Called in MyIAPManager.
public string GetPrice(string productID)
{
if (m_StoreController == null)
InitializePurchasing();
if (m_StoreController != null && m_StoreController.products != null)
return m_StoreController.products.WithID(productID).metadata.localizedPriceString;
else
return "Offline";
}
private bool IsInitialized()
{
// Only say we are initialized if both the Purchasing references are set.
return m_StoreController != null && m_StoreExtensionProvider != null;
}
public 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)
{
// 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
{
// ... report the product look-up failure situation
Debug.LogError("BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase " + productId);
}
}
// Otherwise ...
else
{
// ... report the fact Purchasing has not succeeded initializing yet. Consider waiting longer or
// retrying initiailization.
Debug.Log("BuyProductID FAIL. Not initialized.");
}
}
// Restore purchases previously made by this customer. Some platforms automatically restore purchases, like Google.
// Apple currently requires explicit purchase restoration for IAP, conditionally displaying a password prompt.
public void RestorePurchases()
{
// If Purchasing has not yet been set up ...
if (!IsInitialized())
{
// ... report the situation and stop restoring. Consider either waiting longer, or retrying initialization.
Debug.Log("RestorePurchases FAIL. Not initialized.");
return;
}
// If we are running on an Apple device ...
if (Application.platform == RuntimePlatform.IPhonePlayer ||
Application.platform == RuntimePlatform.OSXPlayer)
{
// ... begin restoring purchases
// Debug.Log("RestorePurchases started ...");
// Fetch the Apple store-specific subsystem.
var apple = m_StoreExtensionProvider.GetExtension<IAppleExtensions>();
// Begin the asynchronous process of restoring purchases. Expect a confirmation response in
// the Action<bool> below, and ProcessPurchase if there are previously purchased products to restore.
apple.RestoreTransactions((result) => {
// The first phase of restoration. If no more responses are received on ProcessPurchase then
// no purchases are available to be restored.
// Debug.Log("RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore.");
});
}
// Otherwise ...
else
{
// We are not running on an Apple device. No work is necessary to restore purchases.
Debug.Log("RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform);
}
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
// 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)
{
// 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)
{
// A consumable product has been purchased by this user.
switch (args.purchasedProduct.definition.id)
{
case "molly_key1":
PlayerPrefs.SetInt("ProcessPurchase", 1);
break;
case "molly_key2":
PlayerPrefs.SetInt("ProcessPurchase", 2);
break;
case "molly_key3":
PlayerPrefs.SetInt("ProcessPurchase", 3);
break;
case "molly_key4":
PlayerPrefs.SetInt("ProcessPurchase", 4);
break;
case "molly_egypt":
PlayerPrefs.SetInt("ProcessPurchase", 5);
break;
case "molly_russia":
PlayerPrefs.SetInt("ProcessPurchase", 6);
break;
default:
Debug.LogException(new Exception("qBqZMfMU3w" + " - " + "ProcessPurchase: FAIL. Unrecognized product: " + args.purchasedProduct.definition.id));
break;
}
myIAPManager.OnPurchaseSuccess();
// 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)
{
// 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));
}
}
and here is my manager script where I call myIAPInit.GetPrice
public class MyIAPManager : MonoBehaviour
{
public LanguageManager languageManager;
public AdMobController adMobController;
public MyIAPInit myIAPInit;
public CoinManagerScript coinManagerScript;
public ShopManagerScript shopManagerScript;
public PaidLevelsControlScript paidLevelsControlScript;
public GameObject paidLevelBuyPanel;
public Text[] paidLevelsPriceTexts;
public Text[] shopPriceTexts;
public Text[] shopValueTexts;
public int[] amount;
// Coin Increment Animation variables.
public float duration = 2f;
private int score = 0;
void Start()
{
// Show product price for the Shop Panel
for (int i = 0; i < shopPriceTexts.Length; i++)
{
shopPriceTexts[i].text = myIAPInit.GetPrice("molly_key" + (i + 1).ToString());
}
for (int i = 0; i < shopValueTexts.Length; i++)
{
shopValueTexts[i].text = amount[i].ToString("n0") + " " + languageManager.getString("shopCoins");
}
paidLevelsPriceTexts[0].text = myIAPInit.GetPrice("molly_egypt");
paidLevelsPriceTexts[1].text = myIAPInit.GetPrice("molly_russia");
}
public void BuyConsumable(string productID) // Called on Product Buttons !!!
{
// Buy the consumable product using its general identifier. Expect a response either
// through ProcessPurchase or OnPurchaseFailed asynchronously.
myIAPInit.BuyProductID(productID);
}
public void OnPurchaseSuccess() // Called in MyIAPInit
{
PlayerPrefs.SetInt("MadeAnyPurchase", 1); // Prevents to show Banner Ad in the future.
adMobController.DestroyBannerAd(); // Remove Banner Ad.
switch (PlayerPrefs.GetInt("ProcessPurchase", 0))
{
case 1:
shopManagerScript.CloseShop();
StartCoroutine(CoinIncrementAnimation(amount[0]));
break;
case 2:
shopManagerScript.CloseShop();
StartCoroutine(CoinIncrementAnimation(amount[1]));
break;
case 3:
shopManagerScript.CloseShop();
StartCoroutine(CoinIncrementAnimation(amount[2]));
break;
case 4:
shopManagerScript.CloseShop();
StartCoroutine(CoinIncrementAnimation(amount[3]));
break;
case 5:
PlayerPrefs.SetInt("PaidLevel0Purchased", 1);
paidLevelBuyPanel.SetActive(false);
paidLevelsControlScript.RefreshPaidButtons();
break;
case 6:
PlayerPrefs.SetInt("PaidLevel1Purchased", 1);
paidLevelBuyPanel.SetActive(false);
paidLevelsControlScript.RefreshPaidButtons();
break;
default:
Debug.LogException(new Exception("qBqZMfMU3w" + " - " + "OnPurchaseSuccess: Unknown Product ID! Purchase Failed."));
break;
}
}
IEnumerator CoinIncrementAnimation(int target)
{
int start = score;
for (float timer = 0; timer < duration; timer += Time.deltaTime)
{
float progress = timer / duration;
score = (int)Mathf.Lerp(start, target, progress);
coinManagerScript.coinScoreText.text = (coinManagerScript.coinScore + score).ToString();
yield return null;
}
coinManagerScript.IncreaseScore(target, true);
}
}
Edit: Ok, I found solution finaly. UnityPurchasing.Initialize() is an asynchrounous method. In MyIAPManager I was trying to Get Price in Start but at this moment IAP hasn’t been initialized yet.
I moved my code from start into a public function and call it in IAP Init script in OnInitialized.