> ## 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.

# Bien démarrer avec Economy v2, Unity IAP et Android

> Connectez Unity IAP et l'API Android Billing aux bundles PlayFab Economy v2 pour que les joueurs puissent acheter des articles avec de l'argent réel et les échanger dans leur inventaire.

# Bien démarrer avec Economy v2, Unity et Android

<Info>
  Economy v2 est désormais en disponibilité générale. Pour obtenir de l'aide et donner votre avis, rendez-vous sur le [forum PlayFab](https://community.playfab.com).
</Info>

Ce tutoriel vous montre comment configurer les achats intégrés à l'application (IAP) à l'aide de PlayFab, du service Unity + IAP et de l'API Android Billing.

## Avant de commencer

L'API Android Billing et PlayFab fonctionnent ensemble pour offrir une expérience IAP à votre client :

<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 - Chronologie d'échange" width="855" height="390" data-path="images/playfab/economy-monetization/economy-v2/playfab-economyv2-redemption-timeline.png" />

Commencez par configurer vos **ID de produit** et vos **prix** via PlayMarket. Au départ, tous les produits sont *anonymes* : il s'agit d'entités numériques que votre joueur peut acheter, mais qui n'ont aucune signification pour les joueurs PlayFab.

Pour rendre ces entités utiles, nous devons les refléter dans les catalogues d'articles PlayFab. PlayFab transforme les entités anonymes en bundles, en conteneurs et en articles individuels.

Chacun possède sa propre identité, avec :

* **Titres**
* **Descriptions**
* **Balises**
* **Types**
* **Images**
* **Comportements**

Tous les articles sont liés aux produits de la place de marché par le partage d'ID.

La meilleure façon d'accéder aux articles en argent réel disponibles à l'achat consiste à utiliser [GetItems](https://learn.microsoft.com/en-us/rest/api/playfab/economy/catalog/get-items).

L'ID de l'article constitue le lien entre PlayFab et tout système IAP externe. Nous transmettons donc l'ID de l'article au service IAP.

À ce stade, le processus d'achat commence. Le joueur interagit avec l'interface IAP et, si l'achat réussit, vous obtenez un reçu.

PlayFab valide le reçu et enregistre l'achat, en octroyant au joueur PlayFab les articles qu'il vient d'acheter.

## Configuration d'une application cliente

Cette section vous montre comment configurer une application pour tester les IAP à l'aide de PlayFab, d'UnityIAP et de l'API Android Billing.

Prérequis :

* Un projet Unity.
* Le [SDK PlayFab pour Unity](/fr/services/playfab/sdks/unity3d) importé et configuré pour fonctionner avec votre titre.
* Un éditeur tel que [Visual Studio](https://learn.microsoft.com/en-us/visualstudio/gamedev/unity/get-started/getting-started-with-visual-studio-tools-for-unity) installé et configuré pour fonctionner avec votre projet Unity.

Notre première étape consiste à configurer UnityIAP :

1. Accédez à **Services**.
2. Assurez-vous que l'onglet **Services** est sélectionné.
3. Sélectionnez votre profil ou organisation **Unity Services**.
4. Sélectionnez le bouton **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="Configuration du service UnityIAP" width="570" height="693" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-setting-up-service.png" />

1. Ensuite, accédez au service **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="Accéder au service UnityIAP" width="500" height="862" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-navigate-to-service.png" />

1. Veillez à activer le **service** en activant le bouton bascule **Simplify cross-platform IAP**.
2. Sélectionnez ensuite le bouton **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="Activer le service UnityIAP" width="428" height="325" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-enable-service.png" />

Une page contenant une liste de plug-ins s'affiche.

1. Sélectionnez le bouton **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="Service UnityIAP - Importer les plug-ins" width="444" height="525" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-import-plugins.png" />

Poursuivez la procédure d'installation et d'importation de Unity jusqu'à ce que tous les plug-ins aient été importés.

1. Vérifiez que les plug-ins sont en place.
2. Créez ensuite un nouveau script nommé **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 - Créer un nouveau script" width="407" height="330" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-create-new-script.png" />

`AndroidIAPExample.cs` contient le code suivant (reportez-vous aux commentaires du code pour plus d'explications).

```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. Créez un nouveau **GameObject** nommé **Code**.
2. Ajoutez-y le composant `AndroidIAPExample` (par glisser-déplacer, ou).
3. Veillez à **enregistrer** la scène.

<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 - Créer l'objet de jeu d'exemple" width="1105" height="757" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-create-example-game-object.png" />

Enfin, accédez à **Build Settings**.

1. Vérifiez que votre scène a été ajoutée à la zone **Scenes In Build**.
2. Assurez-vous que la plateforme **Android** est sélectionnée.
3. Passez à la zone **Player Settings**.
4. Attribuez votre **Package Name**.

<Note>
  Veillez à choisir votre *propre* nom de package pour éviter tout conflit dans **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 - Ajouter l'objet de jeu d'exemple" width="1089" height="749" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-add-example-game-object.png" />

Enfin, générez l'application comme d'habitude et assurez-vous de disposer d'un APK.

Pour effectuer les tests, nous devons configurer PlayMarket et PlayFab.

## Configuration d'une application PlayMarket pour les IAP

Cette section décrit en détail comment activer les IAP pour votre application PlayMarket.

<Note>
  La configuration de l'application elle-même dépasse le cadre de ce tutoriel. Nous partons du principe que vous *disposez* déjà d'une application configurée pour publier au moins des versions 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="Activer l'application PlayMarket" width="608" height="157" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-enable-playmarket-application.png" />

Remarques utiles :

* Pour arriver à ce stade, vous devez avoir chargé un APK. Utilisez l'APK que nous avons généré dans la section précédente.
* Chargez l'APK en tant qu'application *Alpha* ou *Bêta* pour activer le sandbox IAP.
* La configuration de la **classification du contenu** comprend des questions sur la façon dont les IAP sont activés dans l'application.
* PlayMarket *ne permet pas* aux éditeurs d'utiliser ou de tester les IAP. Choisissez un *autre* compte Google à des fins de test et ajoutez-le en tant que testeur de votre build Alpha/Bêta.

1. Publiez le build de l'application.
2. Sélectionnez **In-app products** dans le menu.
   * Si un **compte marchand** vous est demandé, liez-en un ou créez-en un.
3. Sélectionnez le bouton **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 - Ajouter un nouveau produit" width="1151" height="640" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-new-product.png" />
4. Sur l'écran du nouveau produit, sélectionnez **Managed Product**.
5. Attribuez-lui un *ID de produit* descriptif, tel que `100diamonds`.
6. Sélectionnez **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 - Ajouter l'ID de produit" width="639" height="482" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-id.png" />
7. PlayMarket vous demande de renseigner un **titre (1)** et une **description (2)**, par exemple `100 Diamonds` et `A pack of 100 diamonds to spend in-game`. Les données de l'**article de données** proviennent exclusivement du service PlayFab, et seuls les ID doivent correspondre. <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 - Ajouter le titre et la description du produit" width="852" height="511" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-title-description.png" />
8. Faites défiler la page et sélectionnez le bouton **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 - Ajouter le prix du produit" width="850" height="378" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-price.png" />
9. Entrez un prix valide, par exemple « \$0.99 » (notez que le prix est converti indépendamment pour chaque pays/région).
10. Sélectionnez le bouton **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 - Appliquer les prix locaux du produit" width="897" height="779" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-apply-local-prices.png" />
11. Enfin, revenez en haut de l'écran et définissez l'état de l'article sur **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 - Activer le produit" width="671" height="417" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-make-product-active.png" />
12. Enregistrez la **clé de licence** pour lier PlayFab à PlayMarket.
13. Accédez à **Services & APIs** dans le menu.
14. Localisez et enregistrez ensuite la version **Base64** de la **clé**.

<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 - Enregistrer la clé de licence du produit" width="717" height="350" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-save-product-licensing-key.png" />

L'étape suivante consiste à activer les tests IAP. Bien que le sandbox soit automatiquement activé pour les builds Alpha et Bêta, nous devons configurer les comptes autorisés à tester l'application :

1. Accédez à **Home**.
2. Localisez et sélectionnez **Account details** dans le menu de gauche.
3. Localisez la zone **License Testing**.
4. Vérifiez que vos **comptes de test** figurent dans la liste.
5. Assurez-vous que **License Test Response** est défini sur **RESPOND\_NORMALLY**.

N'oubliez pas d'appliquer les paramètres !

<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 - Activer les tests IAP" width="562" height="657" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-enable-iap-testing.png" />

La partie Play Market de l'intégration doit maintenant être configurée.

## Configuration d'un titre PlayFab

Notre dernière étape consiste à configurer un titre PlayFab pour qu'il reflète nos produits et s'intègre à l'API Google Billing.

1. Sélectionnez **Add-ons**.
2. Sélectionnez ensuite le module complémentaire **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 - Ouvrir le module complémentaire Google" width="1589" height="1043" data-path="images/playfab/identity/player-identity/platform-specific-authentication/tutorials/google-html5/open-google-add-on.png" />

1. Renseignez votre **Package ID**.
2. Renseignez la **Google App License Key** que vous avez obtenue dans la section précédente.
3. Validez vos modifications en sélectionnant le bouton **Install Google**.

Notre étape suivante consiste à refléter notre bundle de 100 diamants dans PlayFab :

### Game Manager

1. Créez une nouvelle monnaie dans Economy Catalog (V2).
2. Modifiez le **titre** et ajoutez une **description**, par exemple `Diamonds`, `Our in-game currency of choice.`.
3. Ajoutez un **Friendly ID** pour faciliter la recherche de votre monnaie, `diamonds`.
4. Sélectionnez **Save and publish** pour finaliser vos modifications.
5. Observez votre monnaie dans la liste **Currency**.
6. Ensuite, créez un nouveau bundle dans Economy Catalog (V2).
7. Modifiez le **titre** et ajoutez une **description**, par exemple `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>
  Gardez à l'esprit que ces données n'ont *rien à voir* avec le **titre** et la **description de l'article Play Market** : elles en sont indépendantes.
</Note>

1. Vous pouvez utiliser le type de contenu pour organiser vos bundles, par exemple `appstorebundles`. Les types de contenu sont gérés dans ⚙️ > Title Settings > Economy (V2).
2. Suivez les prix réels en ajoutant des prix localisés aux propriétés d'affichage.
   ```json theme={null}
   {
       "prices": [
           "en-us": 0.99,
           "en-gb": 0.85,
           "de-de": 0.45
       ]
   }
   ```
3. Ajoutez un nouvel article au bundle. Sélectionnez Currencies dans le filtre et choisissez la monnaie que vous avez créée précédemment. Définissez la quantité en fonction du montant de monnaie que vous souhaitez vendre dans ce bundle.
4. Ajoutez une nouvelle plateforme pour la place de marché « GooglePlay ». Si vous ne disposez pas encore de la place de marché GooglePlay, vous pouvez la créer dans la page Economy Settings. Définissez le **Marketplace ID** pour qu'il corresponde à l'ID de produit Google Play Console que vous avez créé dans la section précédente.
5. Sélectionnez **Save and publish** pour finaliser vos modifications.
6. Observez votre bundle dans la liste **Bundles**.

### API REST

***

Ensuite, nous pouvons définir des achats en jeu sur lesquels les joueurs dépenseront leur monnaie, avec un magasin PlayFab représentant un marchand PNJ en jeu :

### Game Manager

1. Créez un nouvel article dans Economy Catalog (V2).
2. Modifiez le **titre** et ajoutez une **description**, par exemple « Golden Sword », « A sword made of gold. ».
3. Vous pouvez ajouter des mots-clés localisés pour aider les joueurs à trouver votre article dans le magasin. Ajoutez des balises et un type de contenu pour vous aider à organiser vos articles en vue de leur récupération ultérieure via l'API. Utilisez les propriétés d'affichage pour stocker des données de jeu telles que des valeurs d'armure, un chemin relatif vers des ressources graphiques ou toute autre donnée que vous devez stocker pour votre jeu.
4. Ajoutez un nouveau prix et sélectionnez la monnaie que vous avez créée à l'étape précédente. Définissez le montant sur le prix que vous souhaitez appliquer par défaut. Vous pourrez remplacer le prix ultérieurement dans n'importe quel magasin que vous créerez.
5. Sélectionnez **Save and publish** pour finaliser vos modifications.
6. Observez votre article dans la liste **Items**.
7. Enfin, créez un nouveau magasin dans Economy Catalog (V2).
8. Modifiez le **titre** et ajoutez une **description**, par exemple `Villager Store`, `A humble store run by a humble villager.`.
9. Attribuez-lui un **Friendly ID** pour faciliter sa récupération, par exemple `villagerstore`.
10. Ajoutez au magasin l'article que vous avez créé à l'étape précédente. Vous pouvez ajouter plusieurs articles à un magasin et remplacer les prix par défaut si nécessaire.
11. Sélectionnez **Save and publish** pour finaliser vos modifications.
12. Observez votre magasin dans la liste **Stores**.

### API REST

***

La configuration de votre titre PlayFab est terminée.

## Test

À des fins de test, téléchargez l'application à l'aide de la version Alpha/Bêta.

* Veillez à utiliser un compte de test et un véritable appareil Android.
* Une fois l'application démarrée, vous devez voir que les IAP sont initialisés, ainsi qu'*un bouton* représentant votre article.
* Sélectionnez ce bouton.

<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="Application de test - Bouton d'achat de 100 diamants" width="1082" height="468" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-test-app-iap.png" />

L'achat IAP est lancé. Suivez les instructions de Google Play jusqu'à ce que l'achat réussisse.

<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="Application de test - Google Play - Paiement réussi" width="428" height="290" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-test-app-google-play-payment-successful.png" />

Enfin, accédez à votre titre dans le tableau de bord **Game Manager** de PlayFab et localisez **New Events**.

Vérifiez que l'achat a été fourni, validé et transmis à l'écosystème PlayFab.

Vous avez intégré avec succès UnityIAP et l'API Android Billing dans votre application PlayFab !

## Étapes suivantes

1. Créez une interface Unity UI Toolkit pour les achats afin de remplacer l'affichage IMGUI de démonstration.
2. Créez un enregistreur Unity personnalisé pour gérer les erreurs PlayFab et les afficher à l'utilisateur.


## Related topics

- [Introducción a Economy v2, Unity IAP y Android](/es/services/playfab/economy-monetization/economy-v2/tutorials/getting-started-with-unity-and-android.md)
- [Getting started with Economy v2, Unity IAP, and Android](/services/playfab/economy-monetization/economy-v2/tutorials/getting-started-with-unity-and-android.md)
- [Economy v2, Unity IAP, Android 시작하기](/ko/services/playfab/economy-monetization/economy-v2/tutorials/getting-started-with-unity-and-android.md)
- [使用 Economy v2、Unity IAP 和 Android 快速入门](/zh-CN/services/playfab/economy-monetization/economy-v2/tutorials/getting-started-with-unity-and-android.md)
- [Economy v2、Unity IAP、Android を使い始める](/ja-jp/services/playfab/economy-monetization/economy-v2/tutorials/getting-started-with-unity-and-android.md)
