> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Introdução ao Economy v2, Unity IAP e Android

> Conecte o Unity IAP e a Android Billing API aos pacotes do PlayFab Economy v2 para que os jogadores possam comprar itens com dinheiro real e resgatá-los no inventário.

# Introdução ao Economy v2, Unity e Android

<Info>
  O Economy v2 agora está em disponibilidade geral. Para obter suporte e enviar comentários, acesse o [Fórum do PlayFab](https://community.playfab.com).
</Info>

Este tutorial mostra como configurar compras no aplicativo (IAP) usando o PlayFab, o Unity + IAP Service e a Android Billing API.

## Antes de começar

A Android Billing API e o PlayFab trabalham juntos para fornecer uma experiência de IAP para o seu cliente:

<img src="https://mintcdn.com/microsoft-4404708b/68AB2fedpk3M7e-n/images/playfab/economy-monetization/economy-v2/playfab-economyv2-redemption-timeline.png?fit=max&auto=format&n=68AB2fedpk3M7e-n&q=85&s=498ccac2bdd047ef019555cf9edfee34" alt="PlayFab Economy v2 - Linha do tempo de resgate" width="855" height="390" data-path="images/playfab/economy-monetization/economy-v2/playfab-economyv2-redemption-timeline.png" />

Comece configurando suas **IDs de produto** e **Preços** por meio do PlayMarket. Inicialmente, todos os produtos são *sem identidade* - entidades digitais que o seu jogador pode comprar - mas sem significado para os jogadores do PlayFab.

Para tornar essas entidades úteis, precisamos espelhá-las nos catálogos de itens do PlayFab. O PlayFab transforma entidades sem identidade em pacotes, contêineres e itens individuais.

Cada um tem sua própria identidade exclusiva, com:

* **Títulos**
* **Descrições**
* **Marcas**
* **Tipos**
* **Imagens**
* **Comportamentos**

Todos os itens são vinculados aos produtos do marketplace por meio de IDs compartilhadas.

A melhor maneira de acessar os itens de dinheiro real disponíveis para compra é usar [GetItems](https://learn.microsoft.com/en-us/rest/api/playfab/economy/catalog/get-items).

A ID do item é o vínculo entre o PlayFab e qualquer sistema de IAP externo. Portanto, passamos a ID do item para o serviço de IAP.

Nesse ponto, o processo de compra começa. O jogador interage com a interface de IAP e - se a compra for bem-sucedida - você obtém um recibo.

O PlayFab valida o recibo e registra a compra, concedendo ao jogador do PlayFab os itens que ele acabou de comprar.

## Configurando um aplicativo cliente

Esta seção mostra como configurar um aplicativo para testar IAP usando o PlayFab, o UnityIAP e a Android Billing API.

Pré-requisitos:

* Um projeto do Unity.
* O [SDK do PlayFab para Unity](/pt-BR/services/playfab/sdks/unity3d) importado e configurado para funcionar com o seu título.
* Um editor como o [Visual Studio](https://learn.microsoft.com/en-us/visualstudio/gamedev/unity/get-started/getting-started-with-visual-studio-tools-for-unity) instalado e configurado para funcionar com o seu projeto do Unity.

Nossa primeira etapa é configurar o UnityIAP:

1. Navegue até **Services**.
2. Verifique se a guia **Services** está selecionada.
3. Selecione seu perfil ou organização do **Unity Services**.
4. Selecione o botão **Create**.

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-setting-up-service.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=c74b3cd003f67bb4998e4f0b36b24db6" alt="Configurando o serviço UnityIAP" width="570" height="693" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-setting-up-service.png" />

1. Em seguida, navegue até o serviço **In-App Purchasing (IAP)**.

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-navigate-to-service.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=b5a4f77ba599c1368e2a9b7185ff2dfe" alt="Navegar até o serviço UnityIAP" width="500" height="862" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-navigate-to-service.png" />

1. Habilite o **Service** ativando a opção **Simplify cross-platform IAP**.
2. Em seguida, selecione o botão **Continue**.

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-enable-service.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=dbb412be4fe8ab0d42d8417b12f4113d" alt="Habilitar o serviço UnityIAP" width="428" height="325" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-enable-service.png" />

Uma página com uma lista de plug-ins é exibida.

1. Selecione o botão **Import**.

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-import-plugins.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=9c25924c7488ebef1c63f914fad0ab60" alt="Serviço UnityIAP - Importar plug-ins" width="444" height="525" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-import-plugins.png" />

Continue o procedimento de instalação e importação do Unity até o ponto em que todos os plug-ins tenham sido importados.

1. Verifique se os plug-ins estão no lugar.
2. Em seguida, crie um novo script chamado **AndroidIAPExample.cs**.

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-create-new-script.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=3bca6b55a46e1a1ef00ee671a9e47c90" alt="UnityIAP - Criar novo script" width="407" height="330" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-create-new-script.png" />

`AndroidIAPExample.cs` contendo o código a seguir (consulte os comentários do código para obter mais explicações).

```csharp theme={null}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Purchasing.Extension;

using PlayFab;
using PlayFab.ClientModels;
using PlayFab.EconomyModels;

/// <summary>
/// Unity behavior that implements the Unity IAP Store interface.
/// Attach as an asset to your Scene.
/// </summary>
public class AndroidIAPExample : MonoBehaviour, IDetailedStoreListener
{
    // Bundles for sale on the Google Play Store.
    private Dictionary<string, PlayFab.EconomyModels.CatalogItem> _googlePlayCatalog;

    // In-game items for sale at the example vendor.
    private Dictionary<string, PlayFab.EconomyModels.CatalogItem> _storefrontCatalog;

    private string _purchaseIdempotencyId = null;

    private PlayFabEconomyAPIAsyncResult _lastAPICallResult = null;

    private static readonly PlayFabEconomyAPIAsync s_economyAPI = new();

    private static IStoreController s_storeController;

    // TODO: This callback is for illustrations purposes, you should create one that fits your needs
    public delegate void PlayFabProcessPurchaseCallback(PurchaseProcessingResult result);

    /// <summary>
    /// Event that is triggered when a purchase is processed.
    /// </summary>
    /// <remarks>
    /// TODO: Subscribe to this event in your game code to handle purchase results.
    /// </remarks>
    public event PlayFabProcessPurchaseCallback PlayFabProcessPurchaseEvent;

    /// <summary>
    /// True if the Store Controller, extensions, and Catalog are set.
    /// </summary>
    public bool IsInitialized => s_storeController != null
                             && _googlePlayCatalog != null
                             && _storefrontCatalog != null;

    // Start is called before the first frame update.
    public void Start()
    {
        Login();
    }

    /// <summary>
    /// Attempts to log the player in via the Android Device ID.
    /// </summary>
    private void Login()
    {
        // TODO: it is better to use LoginWithGooglePlayGamesService or a similar platform-specific login method for final game code.

        // SystemInfo.deviceUniqueIdentifier will prompt for permissions on newer devices.
        // Using a non-device specific GUID and saving to a local file
        // is a better approach. PlayFab does allow you to link multiple
        // Android device IDs to a single PlayFab account.
        PlayFabClientAPI.LoginWithCustomID(new LoginWithCustomIDRequest()
        {
            CreateAccount = true,
            CustomId = SystemInfo.deviceUniqueIdentifier
        }, result => RefreshIAPItems(), PlayFabSampleUtil.OnPlayFabError);
    }

    /// <summary>
    /// Queries the PlayFab Economy Catalog V2 for updated listings
    /// and then fills the local catalog objects.
    /// </summary>
    private async void RefreshIAPItems()
    {
        _googlePlayCatalog = new Dictionary<string, PlayFab.EconomyModels.CatalogItem>();
        SearchItemsRequest googlePlayCatalogRequest = new()
        {
            Count = 50,
            Filter = "AlternateIds/any(t: t/type eq 'GooglePlay')"
        };

        SearchItemsResponse googlePlayCatalogResponse;
        do
        {
            googlePlayCatalogResponse = await s_economyAPI.SearchItemsAsync(googlePlayCatalogRequest);
            Debug.Log("Search response: " + JsonUtility.ToJson(googlePlayCatalogResponse));

            foreach (PlayFab.EconomyModels.CatalogItem item in googlePlayCatalogResponse.Items)
            {
                _googlePlayCatalog.Add(item.Id, item);
            }

        } while (!string.IsNullOrEmpty(googlePlayCatalogResponse.ContinuationToken));

        Debug.Log($"Completed pulling from PlayFab Economy v2 googleplay Catalog: {_googlePlayCatalog.Count()} items retrieved");

        _storefrontCatalog = new Dictionary<string, PlayFab.EconomyModels.CatalogItem>();
        GetItemRequest storeCatalogRequest = new()
        {
            AlternateId = new CatalogAlternateId()
            {
                Type = "FriendlyId",
                Value = "villagerstore"
            }
        };

        GetItemResponse storeCatalogResponse;
        storeCatalogResponse = await s_economyAPI.GetItemAsync(storeCatalogRequest);
        List<string> itemIds = new();

        foreach (CatalogItemReference item in storeCatalogResponse.Item.ItemReferences)
        {
            itemIds.Add(item.Id);
        }

        GetItemsRequest itemsCatalogRequest = new()
        {
            Ids = itemIds
        };

        GetItemsResponse itemsCatalogResponse = await s_economyAPI.GetItemsAsync(itemsCatalogRequest);
        foreach (PlayFab.EconomyModels.CatalogItem item in itemsCatalogResponse.Items)
        {
            _storefrontCatalog.Add(item.Id, item);
        }

        Debug.Log($"Completed pulling from PlayFab Economy v2 villagerstore store: {_storefrontCatalog.Count()} items retrieved");

        InitializePurchasing();
    }

    /// <summary>
    /// Initializes the Unity IAP system for the Google Play Store.
    /// </summary>
    private void InitializePurchasing()
    {
        if (IsInitialized) return;

        var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance(AppStore.GooglePlay));

        foreach (PlayFab.EconomyModels.CatalogItem item in _googlePlayCatalog.Values)
        {
            string googlePlayItemId = item.AlternateIds.FirstOrDefault(item => item.Type == "GooglePlay")?.Value;
            if (!string.IsNullOrWhiteSpace(googlePlayItemId))
            {
                builder.AddProduct(googlePlayItemId, ProductType.Consumable);
            }
        }

        UnityPurchasing.Initialize(this, builder);
    }

    /// <summary>
    /// Draw a debug IMGUI for testing examples.
    /// Use UI Toolkit for your production game runtime UI instead.
    /// </summary>
    public void OnGUI()
    {
        // Support high-res devices.
        GUI.matrix = Matrix4x4.TRS(new Vector3(0, 0, 0), Quaternion.identity, new Vector3(3, 3, 3));

        if (!IsInitialized)
        {
            GUILayout.Label("Initializing IAP and logging in...");
            return;
        }

        if (!string.IsNullOrEmpty(_purchaseIdempotencyId) && (!string.IsNullOrEmpty(_lastAPICallResult?.Message)
                                                           || !string.IsNullOrEmpty(_lastAPICallResult?.Error)))
        {
            GUILayout.Label(_lastAPICallResult?.Message + _lastAPICallResult?.Error);
        }

        GUILayout.Label("Shop for game currency bundles.");
        // Draw a purchase menu for each catalog item.
        foreach (PlayFab.EconomyModels.CatalogItem item in _googlePlayCatalog.Values)
        {
            // Use a dictionary to select the proper language.
            if (GUILayout.Button("Get " + (item.Title.ContainsKey("en-US") ? item.Title["en-US"] : item.Title["NEUTRAL"])))
            {
                BuyProductById(item.AlternateIds.FirstOrDefault(item => item.Type == "GooglePlay").Value);
            }
        }

        GUILayout.Label("Hmmm. (Translation: Welcome to my humble Villager store.)");
        // Draw a purchase menu for each catalog item.
        foreach (PlayFab.EconomyModels.CatalogItem item in _storefrontCatalog.Values)
        {
            // Use a dictionary to select the proper language.
            if (GUILayout.Button("Buy "
                + (item.Title.ContainsKey("en-US") ? item.Title["en-US"] : item.Title["NEUTRAL"]
                + ": "
                + item.PriceOptions.Prices.FirstOrDefault().Amounts.FirstOrDefault().Amount.ToString()
                + " Diamonds"
                )))
            {
                Task.Run(() => PlayFabPurchaseItemById(item.Id));
            }
        }
    }

    /// <summary>
    /// Integrates game purchasing with the Unity IAP API.
    /// </summary>
    public void BuyProductById(string productId)
    {
        if (!IsInitialized)
        {
            Debug.LogError("IAP Service is not initialized!");
            return;
        }

        s_storeController.InitiatePurchase(productId);
    }

    /// <summary>
    /// Purchases a PlayFab inventory item by ID.
    /// See the <see cref="PlayFabEconomyAPIAsync"/> class for details on error handling
    /// and calling patterns.
    /// </summary>
    async public Task<bool> PlayFabPurchaseItemById(string itemId)
    {
        if (!IsInitialized)
        {
            Debug.LogError("IAP Service is not initialized!");
            return false;
        }

        _lastAPICallResult = new();

        Debug.Log("Player buying product " + itemId);

        if (string.IsNullOrEmpty(_purchaseIdempotencyId))
        {
            _purchaseIdempotencyId = Guid.NewGuid().ToString();
        }

        GetItemRequest getVillagerStoreRequest = new()
        {
            AlternateId = new CatalogAlternateId()
            {
                Type = "FriendlyId",
                Value = "villagerstore"
            }
        };

        GetItemResponse getStoreResponse = await s_economyAPI.GetItemAsync(getVillagerStoreRequest);
        if (getStoreResponse == null || string.IsNullOrEmpty(getStoreResponse?.Item?.Id))
        {
            _lastAPICallResult.Error = "Unable to contact the store. Check your internet connection and try again in a few minutes.";
            return false;
        }

        CatalogPriceAmount price = _storefrontCatalog.FirstOrDefault(item => item.Key == itemId).Value.PriceOptions.Prices.FirstOrDefault().Amounts.FirstOrDefault();
        PurchaseInventoryItemsRequest purchaseInventoryItemsRequest = new()
        {
            Amount = 1,
            Item = new InventoryItemReference()
            {
                Id = itemId
            },
            PriceAmounts = new List<PurchasePriceAmount>
            {
                new()
                {
                    Amount = price.Amount,
                    ItemId = price.ItemId
                }
            },
            IdempotencyId = _purchaseIdempotencyId,
            StoreId = getStoreResponse.Item.Id
        };

        PurchaseInventoryItemsResponse purchaseInventoryItemsResponse = await s_economyAPI.PurchaseInventoryItemsAsync(purchaseInventoryItemsRequest);
        if (purchaseInventoryItemsResponse == null || purchaseInventoryItemsResponse?.TransactionIds.Count < 1)
        {
            _lastAPICallResult.Error = "Unable to purchase. Try again in a few minutes.";
            return false;
        }

        _purchaseIdempotencyId = "";
        _lastAPICallResult.Message = "Purchasing!";
        return true;
    }

    private void OnRegistration(LoginResult result)
    {
        PlayFabSettings.staticPlayer.ClientSessionTicket = result.SessionTicket;
    }

    public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    {
        s_storeController = controller;

        extensions.GetExtension<IGooglePlayStoreExtensions>().RestoreTransactions((result, error) => {
            if (result)
            {
                Debug.LogWarning("Restore transactions succeeded.");
            }
            else
            {
                Debug.LogWarning("Restore transactions failed.");
            }
        });
    }

    public void OnInitializeFailed(InitializationFailureReason error)
    {
        Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
    }

    public void OnInitializeFailed(InitializationFailureReason error, string message)
    {
        Debug.Log("OnInitializeFailed InitializationFailureReason:" + error + message);
    }

    public void OnPurchaseFailed(UnityEngine.Purchasing.Product product, PurchaseFailureReason failureReason)
    {
        Debug.Log($"OnPurchaseFailed: FAIL. Product: '{product.definition.storeSpecificId}', PurchaseFailureReason: {failureReason}");
    }

    public void OnPurchaseFailed(UnityEngine.Purchasing.Product product, PurchaseFailureDescription failureDescription)
    {
        Debug.Log($"OnPurchaseFailed: FAIL. Product: '{product.definition.storeSpecificId}', PurchaseFailureReason: {failureDescription}");
    }

    /// <summary>
    /// Callback for Store purchases. Subscribe to PlayFabProcessPurchaseEvent to handle the final PurchaseProcessingResult.
    /// <see href="https://docs.unity3d.com/Packages/com.unity.purchasing@4.8/api/UnityEngine.Purchasing.PurchaseProcessingResult.html"/>
    /// </summary>
    /// <remarks>
    /// This code does not account for purchases that were pending and are
    /// delivered on application start. Production code should account for these cases.
    /// </remarks>
    /// <returns>Complete immediately upon error. Pending if PlayFab Economy is handling final processing and will trigger PlayFabProcessPurchaseEvent with the final result.</returns>
    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
    {
        if (!IsInitialized)
        {
            Debug.LogWarning("Not initialized. Ignoring.");
            return PurchaseProcessingResult.Complete;
        }

        if (purchaseEvent.purchasedProduct == null)
        {
            Debug.LogWarning("Attempted to process purchase with unknown product. Ignoring.");
            return PurchaseProcessingResult.Complete;
        }

        if (string.IsNullOrEmpty(purchaseEvent.purchasedProduct.receipt))
        {
            Debug.LogWarning("Attempted to process purchase with no receipt. Ignoring.");
            return PurchaseProcessingResult.Complete;
        }

        Debug.Log("Attempting purchase with receipt " + purchaseEvent.purchasedProduct.receipt);
        GooglePurchase purchasePayload = GooglePurchase.FromJson(purchaseEvent.purchasedProduct.receipt);
        RedeemGooglePlayInventoryItemsRequest request = new()
        {
            Purchases = new List<GooglePlayProductPurchase>
            {
                new()
                {
                    ProductId = purchasePayload.PayloadData?.JsonData?.productId,
                    Token = purchasePayload.PayloadData?.JsonData?.purchaseToken
                }
            }
        };

        PlayFabEconomyAPI.RedeemGooglePlayInventoryItems(request, result =>
        {
            Debug.Log("Processed receipt validation.");

            if (result?.Failed.Count > 0)
            {
                Debug.Log($"Validation failed for {result.Failed.Count} receipts.");
                Debug.Log(JsonUtility.ToJson(result.Failed));
                PlayFabProcessPurchaseEvent?.Invoke(PurchaseProcessingResult.Pending);
            }
            else
            {
                Debug.Log("Validation succeeded!");
                PlayFabProcessPurchaseEvent?.Invoke(PurchaseProcessingResult.Complete);
                s_storeController.ConfirmPendingPurchase(purchaseEvent.purchasedProduct);
                Debug.Log("Confirmed purchase with Google Marketplace.");
            }
        },
        PlayFabSampleUtil.OnPlayFabError);

        return PurchaseProcessingResult.Pending;
    }
}

/// <summary>
/// Utility classes for the sample.
/// </summary>
public class PlayFabEconomyAPIAsyncResult
{
    public string Error { get; set; } = null;

    public string Message { get; set; } = null;
}

public static class PlayFabSampleUtil
{
    public static void OnPlayFabError(PlayFabError error)
    {
        Debug.LogError(error.GenerateErrorReport());
    }
}

/// <summary>
/// Example Async wrapper for PlayFab API's.
/// 
/// This is just a quick sample for example purposes.
/// 
/// Write your own customer Logger implementation to log and handle errors
/// for user-facing scenarios. Use tags and map which PlayFab errors require your
/// game to handle GUI or gameplay updates vs which should be logged to crash and
/// error reporting services.
/// </summary>
public class PlayFabEconomyAPIAsync
{
    /// <summary>
    /// <see href="https://learn.microsoft.com/rest/api/playfab/economy/catalog/get-item"/>
    /// </summary>
    public Task<GetItemResponse> GetItemAsync(GetItemRequest request)
    {
        TaskCompletionSource<GetItemResponse> getItemAsyncTaskSource = new();
        PlayFabEconomyAPI.GetItem(request, (response) => getItemAsyncTaskSource.SetResult(response), error => 
        {
            PlayFabSampleUtil.OnPlayFabError(error);
            getItemAsyncTaskSource.SetResult(default);
        });
        return getItemAsyncTaskSource.Task;
    }

    /// <summary>
    /// <see href="https://learn.microsoft.com/rest/api/playfab/economy/catalog/get-items"/>
    /// </summary>
    public Task<GetItemsResponse> GetItemsAsync(GetItemsRequest request)
    {
        TaskCompletionSource<GetItemsResponse> getItemsAsyncTaskSource = new();
        PlayFabEconomyAPI.GetItems(request, (response) => getItemsAsyncTaskSource.SetResult(response), error => 
        {
            PlayFabSampleUtil.OnPlayFabError(error);
            getItemsAsyncTaskSource.SetResult(default);
        });
        return getItemsAsyncTaskSource.Task;
    }

    /// <summary>
    /// <see href="https://learn.microsoft.com/rest/api/playfab/economy/inventory/purchase-inventory-items"/>
    /// </summary>
    public Task<PurchaseInventoryItemsResponse> PurchaseInventoryItemsAsync(PurchaseInventoryItemsRequest request)
    {
        TaskCompletionSource<PurchaseInventoryItemsResponse> purchaseInventoryItemsAsyncTaskSource = new();
        PlayFabEconomyAPI.PurchaseInventoryItems(request, (response) => purchaseInventoryItemsAsyncTaskSource.SetResult(response), error => 
        {
            PlayFabSampleUtil.OnPlayFabError(error);
            purchaseInventoryItemsAsyncTaskSource.SetResult(default);
        });
        return purchaseInventoryItemsAsyncTaskSource.Task;
    }

    /// <summary>
    /// <see href="https://learn.microsoft.com/rest/api/playfab/economy/catalog/search-items"/>
    /// </summary>
    public Task<SearchItemsResponse> SearchItemsAsync(SearchItemsRequest request)
    {
        TaskCompletionSource<SearchItemsResponse> searchItemsAsyncTaskSource = new();
        PlayFabEconomyAPI.SearchItems(request, (response) => searchItemsAsyncTaskSource.SetResult(response), error => 
        {
            PlayFabSampleUtil.OnPlayFabError(error);
            searchItemsAsyncTaskSource.SetResult(default);
        });
        return searchItemsAsyncTaskSource.Task;
    }
}

[Serializable]
public class PurchaseJsonData
{
    public string orderId;
    public string packageName;
    public string productId;
    public string purchaseToken;
    public long   purchaseTime;
    public int    purchaseState;
}

[Serializable]
public class PurchasePayloadData
{
    public PurchaseJsonData JsonData;

    public string signature;
    public string json;

    public static PurchasePayloadData FromJson(string json)
    {
        var payload = JsonUtility.FromJson<PurchasePayloadData>(json);
        payload.JsonData = JsonUtility.FromJson<PurchaseJsonData>(payload.json);
        return payload;
    }
}

[Serializable]
public class GooglePurchase
{
    public PurchasePayloadData PayloadData;

    public string Store;
    public string TransactionID;
    public string Payload;

    public static GooglePurchase FromJson(string json)
    {
        var purchase = JsonUtility.FromJson<GooglePurchase>(json);

        // Only fake receipts are returned in Editor play.
        if (Application.isEditor)
        {
            return purchase;
        }

        purchase.PayloadData = PurchasePayloadData.FromJson(purchase.Payload);
        return purchase;
    }
}
```

1. Crie um novo **GameObject** chamado **Code**.
2. Adicione o componente `AndroidIAPExample` a ele (clique e arraste, ou).
3. Certifique-se de **salvar** a cena.

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-create-example-game-object.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=49dafb0589b810b6585f17cd073725df" alt="UnityIAP - Criar objeto de jogo de exemplo" width="1105" height="757" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-create-example-game-object.png" />

Por fim, navegue até **Build Settings**.

1. Verifique se a sua cena foi adicionada à área **Scenes In Build**.
2. Verifique se a plataforma **Android** foi selecionada.
3. Vá para a área **Player Settings**.
4. Atribua o seu **Package Name**.

<Note>
  Crie o seu *próprio* nome de pacote para evitar conflitos no **PlayMarket**.
</Note>

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-add-example-game-object.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=3475d7ac21193c6f4d8056e600146400" alt="UnityIAP - Adicionar objeto de jogo de exemplo" width="1089" height="749" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-add-example-game-object.png" />

Por fim, compile o aplicativo como de costume e verifique se há um APK.

Para testar, precisamos configurar o PlayMarket e o PlayFab.

## Configurando um aplicativo do PlayMarket para IAP

Esta seção descreve os detalhes de como habilitar IAP para o seu aplicativo do PlayMarket.

<Note>
  A configuração do aplicativo em si está além do escopo deste tutorial. Presumimos que você já *tenha* um aplicativo e que ele esteja configurado para publicar pelo menos versões Alpha.
</Note>

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-enable-playmarket-application.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=471e393f3ea7553f6af3b71ad48d0d42" alt="Habilitar aplicativo do PlayMarket" width="608" height="157" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-enable-playmarket-application.png" />

Observações úteis:

* Chegar a esse ponto exige que você tenha carregado um APK. Use o APK que construímos na seção anterior.
* Carregue o APK como um aplicativo *Alpha* ou *Beta* para habilitar a área restrita de IAP.
* A configuração de **Content Rating** inclui perguntas sobre como o IAP está habilitado no aplicativo.
* O PlayMarket *não* permite que os editores usem ou testem IAP. Escolha *outra* conta do Google para fins de teste e adicione-a como testador da sua versão Alpha/Beta.

1. Publique a versão do aplicativo.
2. Selecione **In-app products** no menu.
   * Se for solicitada uma **Merchant Account**, vincule ou crie uma.
3. Selecione o botão **Add New Product**. <img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-new-product.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=c1456178bcaf5cb88175f567c9d59ad8" alt="PlayMarket - adicionar novo produto" width="1151" height="640" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-new-product.png" />
4. Na tela do novo produto, selecione **Managed Product**.
5. Dê a ele uma *ID de produto* descritiva, como `100diamonds`.
6. Selecione **Continue**. <img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-id.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=271b7344e7069d7f072e6ef975d574bf" alt="PlayMarket - adicionar ID do produto" width="639" height="482" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-id.png" />
7. O PlayMarket exige que você preencha um **Title (1)** e uma **Description (2)**, por exemplo, `100 Diamonds` e `A pack of 100 diamonds to spend in-game`. Os dados do **Data Item** vêm exclusivamente do serviço PlayFab e só exigem que as IDs correspondam. <img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-title-description.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=d35ca3f5054934ee2e0805a743e95538" alt="PlayMarket - adicionar título e descrição do produto" width="852" height="511" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-title-description.png" />
8. Role mais para baixo e selecione o botão **Add a price**. <img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-price.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=904804be3624244921d814200f47bf77" alt="PlayMarket - adicionar preço do produto" width="850" height="378" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-price.png" />
9. Insira um preço válido, como "\$0.99" (observe como o preço é convertido para cada país/região de forma independente).
10. Selecione o botão **Apply**. <img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-apply-local-prices.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=2c65bd319208f9c6fc0dedd3f2d6c4af" alt="PlayMarket - aplicar preços locais do produto" width="897" height="779" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-apply-local-prices.png" />
11. Por fim, role de volta até o topo da tela e altere o status do item para **Active**. <img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-make-product-active.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=efd16c08827556f36b5f5921fdf2f338" alt="PlayMarket - ativar o produto" width="671" height="417" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-make-product-active.png" />
12. Salve a **Licensing Key** para vincular o PlayFab ao PlayMarket.
13. Navegue até **Services & APIs** no menu.
14. Em seguida, localize e salve a versão **Base64** da **Key**.

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-save-product-licensing-key.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=6e1c10d2a1f96480ef9c080247e640f5" alt="PlayMarket - salvar chave de licenciamento do produto" width="717" height="350" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-save-product-licensing-key.png" />

A próxima etapa é habilitar o teste de IAP. Embora a área restrita seja habilitada automaticamente para versões Alpha e Beta, precisamos configurar as contas autorizadas a testar o aplicativo:

1. Navegue até **Home**.
2. Localize e selecione **Account details** no menu à esquerda.
3. Localize a área **License Testing**.
4. Verifique se as suas **Test Accounts** estão na lista.
5. Verifique se **License Test Response** está definido como **RESPOND\_NORMALLY**.

Não se esqueça de aplicar as configurações!

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-enable-iap-testing.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=87b433152c575bc304935d1980a7b011" alt="PlayMarket - habilitar teste de IAP" width="562" height="657" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-enable-iap-testing.png" />

O lado do Play Market da integração deve estar configurado neste ponto.

## Configurando um título do PlayFab

Nossa última etapa é configurar um título do PlayFab para refletir nossos produtos e integrá-lo à Google Billing API.

1. Selecione **Add-ons**.
2. Em seguida, selecione o complemento **Google**.

<img src="https://mintcdn.com/microsoft-4404708b/mLCHf0iQv3VidfBe/images/playfab/identity/player-identity/platform-specific-authentication/tutorials/google-html5/open-google-add-on.png?fit=max&auto=format&n=mLCHf0iQv3VidfBe&q=85&s=1b0af874b0d7e46cf30337e322f0004a" alt="PlayFab - abrir o complemento do Google" width="1589" height="1043" data-path="images/playfab/identity/player-identity/platform-specific-authentication/tutorials/google-html5/open-google-add-on.png" />

1. Preencha a sua **Package ID**.
2. Preencha a **Google App License Key** que você obteve na seção anterior.
3. Confirme suas alterações selecionando o botão **Install Google**.

Nossa próxima etapa é refletir nosso pacote de 100 diamantes no PlayFab:

### Game Manager

1. Crie uma nova Moeda do Economy Catalog (V2).
2. Edite o **Title** e adicione uma **Description** - por exemplo, `Diamonds`, `Our in-game currency of choice.`.
3. Adicione uma **Friendly ID** para facilitar a localização da sua moeda, `diamonds`.
4. Selecione **Save and publish** para concluir suas alterações.
5. Observe sua moeda na lista **Currency**.
6. Em seguida, crie um novo Pacote do Economy Catalog (V2).
7. Edite o **Title** e adicione uma **Description** - por exemplo, `100 Diamonds Bundle`, `A pack of 100 diamonds to spend in-game.`.
   ```JSON theme={null}
   {
       "NEUTRAL": "100 Diamonds Bundle",
       "en-US": "100 Diamonds Bundle",
       "en-GB": "100 Diamonds Bundle",
       "de-DE": "100 Diamantenbüschel"
   }
   ```

<Note>
  Lembre-se de que esses dados *não têm nada a ver* com o **Title** e a **Description** do item no Play Market; eles são independentes.
</Note>

1. Você pode usar o tipo de conteúdo para organizar seus pacotes - por exemplo, `appstorebundles`. Os tipos de conteúdo são gerenciados em ⚙️ > Title Settings > Economy (V2).
2. Acompanhe os preços do mundo real adicionando preços localizados às propriedades de exibição.
   ```json theme={null}
   {
       "prices": [
           "en-us": 0.99,
           "en-gb": 0.85,
           "de-de": 0.45
       ]
   }
   ```
3. Adicione um novo item ao pacote. Selecione Currencies no filtro e escolha a moeda que você criou na etapa anterior. Defina Quantity para corresponder à quantidade de moeda que você deseja vender neste pacote.
4. Adicione uma nova plataforma para o marketplace "GooglePlay". Se você ainda não tiver o marketplace GooglePlay, poderá criá-lo na página Economy Settings. Defina a **Marketplace ID** para corresponder à ID do produto do Google Play Console que você criou na seção anterior.
5. Selecione **Save and publish** para concluir suas alterações.
6. Observe seu pacote na lista **Bundles**.

### API REST

***

Em seguida, podemos definir compras no jogo para os jogadores gastarem sua moeda, com uma loja do PlayFab representando um vendedor NPC no jogo:

### Game Manager

1. Crie um novo Item do Economy Catalog (V2).
2. Edite o **Title** e adicione uma **Description** - por exemplo, "Golden Sword", "A sword made of gold.".
3. Você pode adicionar palavras-chave localizadas para ajudar os jogadores a encontrar seu item na loja. Adicione marcas e um tipo de conteúdo para ajudar a organizar seus itens para recuperação posterior por meio da API. Use as propriedades de exibição para armazenar dados do jogo, como valores de armadura, um caminho relativo para ativos de arte ou quaisquer outros dados que você precise armazenar para o seu jogo.
4. Adicione um novo preço e selecione a moeda que você criou na etapa anterior. Defina Amount como o preço padrão desejado. Você pode substituir o preço posteriormente em qualquer loja que criar.
5. Selecione **Save and publish** para concluir suas alterações.
6. Observe seu item na lista **Items**.
7. Por fim, crie uma nova Loja do Economy Catalog (V2).
8. Edite o **Title** e adicione uma **Description** - por exemplo, `Villager Store`, `A humble store run by a humble villager.`.
9. Dê a ela uma **Friendly ID** para facilitar a recuperação, por exemplo, `villagerstore`.
10. Adicione à loja o item que você criou na etapa anterior. Você pode adicionar vários itens a uma loja e substituir quaisquer preços padrão, se necessário.
11. Selecione **Save and publish** para concluir suas alterações.
12. Observe sua loja na lista **Stores**.

### API REST

***

Concluímos a configuração do seu título do PlayFab.

## Testes

Para fins de teste, baixe o aplicativo usando a versão Alpha/Beta.

* Use uma conta de teste e um dispositivo Android real.
* Ao iniciar o aplicativo, você deverá ver o IAP inicializado e *um botão* representando seu item.
* Selecione esse botão.

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-test-app-iap.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=0570ae5b0f89411e4b2fe56fe1164bab" alt="Aplicativo de teste - botão Comprar 100 diamantes" width="1082" height="468" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-test-app-iap.png" />

A compra por IAP é iniciada. Siga as instruções do Google Play até o ponto em que a compra seja bem-sucedida.

<img src="https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy-v2/tutorials/unity-android-test-app-google-play-payment-successful.png?fit=max&auto=format&n=Oa_DP1q6U1lat7c2&q=85&s=281c211a7ceb93300685c9c9e593cc8e" alt="Aplicativo de teste - Google Play - pagamento bem-sucedido" width="428" height="290" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-test-app-google-play-payment-successful.png" />

Por fim, navegue até o seu título no painel do **Game Manager** do PlayFab e localize **New Events**.

Verifique se a compra foi fornecida, validada e encaminhada para o ecossistema do PlayFab.

Você integrou com êxito o UnityIAP e a Android Billing API ao seu aplicativo do PlayFab!

## Próximas etapas

1. Crie uma interface do Unity UI Toolkit para compras para substituir a exibição IMGUI de demonstração.
2. Crie um Unity Logger personalizado para tratar erros do PlayFab e exibi-los ao usuário.
3. Adicione imagens de ícone ao campo Images dos seus itens do PlayFab para exibição na interface do Unity.


## Related topics

- [Introdução ao PlayFab Economy Legacy, Unity IAP e Android](/pt-BR/services/playfab/economy-monetization/economy/tutorials/getting-started-with-unity-iap-android.md)
- [Resgate com o Google Marketplace](/pt-BR/services/playfab/economy-monetization/economy-v2/marketplace/marketplace-redemption/google.md)
- [Introdução ao Android](/pt-BR/services/playfab/multiplayer/networking/android-specific-requirements.md)
- [Documentação do PlayFab Economy v2](/pt-BR/services/playfab/economy-monetization/index.md)
- [Início rápido do Economy (Legado)](/pt-BR/services/playfab/economy-monetization/economy/quickstart.md)
