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

# Prise en main d'Economy v2, d'Unity IAP et d'Android

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

# Prise en main d'Economy v2, d'Unity et d'Android

<Info>
  Economy v2 est maintenant en disponibilité générale. Pour obtenir du soutien et donner vos commentaires, rendez-vous sur le [forum PlayFab](https://community.playfab.com).
</Info>

Ce tutoriel vous montre comment configurer les achats intégrés (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 de l'é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** au moyen de PlayMarket. Au départ, tous les produits sont *sans visage* : des 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 sans visage en lots, en conteneurs et en articles individuels.

Chacun possède son propre visage unique, avec :

* **Titres**
* **Descriptions**
* **Étiquettes**
* **Types**
* **Images**
* **Comportements**

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

La meilleure façon d'accéder aux articles en argent réel offerts à l'achat est d'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-CA/services/playfab/sdks/unity3d) importé et configuré pour fonctionner avec votre titre.
* Un éditeur comme [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 votre 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. Assurez-vous d'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 plugiciels 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 plugiciels" width="444" height="525" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-import-plugins.png" />

Poursuivez l'installation d'Unity et la procédure d'importation jusqu'à ce que tous les plugiciels aient été importés.

1. Vérifiez que les plugiciels 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` contenant le code suivant (consultez les commentaires du code pour obtenir 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époser, ou autrement).
3. Assurez-vous d'**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>
  Assurez-vous de 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 d'obtenir 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 la portée de ce tutoriel. Nous supposons que vous *avez* déjà une application et qu'elle est 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" />

Notes utiles :

* Pour arriver à ce point, vous devez avoir téléversé un APK. Utilisez l'APK que nous avons créé dans la section précédente.
* Téléversez l'APK en tant qu'application *Alpha* ou *Bêta* pour activer le bac à sable 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 comme testeur pour votre version Alpha/Bêta.

1. Publiez la version de l'application.
2. Sélectionnez **In-app products** dans le menu.
   * Si on vous demande un **compte marchand**, 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. Dans l'écran du nouveau produit, sélectionnez **Managed Product**.
5. Donnez-lui un *ID de produit* descriptif, comme `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 du produit" width="639" height="482" data-path="images/playfab/economy-monetization/economy-v2/tutorials/unity-android-playmarket-add-product-id.png" />
7. PlayMarket exige que vous remplissiez 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 plus bas 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, comme « \$0.99 » (remarquez que le prix est converti indépendamment pour chaque pays ou 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, remontez en haut de l'écran et changez l'état de l'article à **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 - Rendre le produit actif" 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. Repérez 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 bac à sable soit automatiquement activé pour les versions Alpha et Bêta, nous devons configurer les comptes autorisés à tester l'application :

1. Accédez à **Home**.
2. Repérez et sélectionnez **Account details** dans le menu de gauche.
3. Repérez 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 à **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" />

Le volet Play Market de l'intégration devrait maintenant être configuré.

## Configuration d'un titre PlayFab

Notre dernière étape consiste à configurer un titre PlayFab pour refléter nos produits et l'intégrer à 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. Remplissez votre **Package ID**.
2. Remplissez 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 prochaine étape consiste à refléter notre lot de 100 diamants dans PlayFab :

### Game Manager

1. Créez une nouvelle monnaie dans le catalogue Economy (V2).
2. Modifiez le **titre** et ajoutez une **description**, par exemple `Diamonds`, `Our in-game currency of choice.`.
3. Ajoutez un **Friendly ID** pour trouver plus facilement votre monnaie, `diamonds`.
4. Sélectionnez **Save and publish** pour terminer vos modifications.
5. Observez votre monnaie dans la liste **Currency**.
6. Ensuite, créez un nouveau lot dans le catalogue Economy (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 lots, 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 lot. Sélectionnez Currencies dans le filtre et choisissez la monnaie que vous avez créée à l'étape précédente. Définissez la quantité en fonction du montant de monnaie que vous souhaitez vendre dans ce lot.
4. Ajoutez une nouvelle plateforme pour la marketplace « GooglePlay ». Si vous n'avez pas encore la marketplace GooglePlay, vous pouvez la créer dans la page Economy Settings. Définissez le **Marketplace ID** pour qu'il corresponde à l'ID de produit de la Google Play Console que vous avez créé dans la section précédente.
5. Sélectionnez **Save and publish** pour terminer vos modifications.
6. Observez votre lot dans la liste **Bundles**.

### API REST

***

Ensuite, nous pouvons configurer des achats en jeu permettant aux joueurs de dépenser leur monnaie, avec une boutique PlayFab représentant un marchand PNJ en jeu :

### Game Manager

1. Créez un nouvel article dans le catalogue Economy (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 la boutique. Ajoutez des étiquettes et un type de contenu pour vous aider à organiser vos articles en vue de leur récupération ultérieure au moyen de l'API. Utilisez les propriétés d'affichage pour stocker des données de jeu, comme 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 au prix que vous souhaitez par défaut. Vous pourrez remplacer le prix plus tard dans n'importe quelle boutique que vous créerez.
5. Sélectionnez **Save and publish** pour terminer vos modifications.
6. Observez votre article dans la liste **Items**.
7. Enfin, créez une nouvelle boutique dans le catalogue Economy (V2).
8. Modifiez le **titre** et ajoutez une **description**, par exemple `Villager Store`, `A humble store run by a humble villager.`.
9. Donnez-lui un **Friendly ID** pour faciliter la récupération, par exemple `villagerstore`.
10. Ajoutez à la boutique l'article que vous avez créé à l'étape précédente. Vous pouvez ajouter plusieurs articles à une boutique et remplacer les prix par défaut au besoin.
11. Sélectionnez **Save and publish** pour terminer vos modifications.
12. Observez votre boutique dans la liste **Stores**.

### API REST

***

Nous avons terminé la configuration de votre titre PlayFab.

## Tests

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

* Assurez-vous d'utiliser un compte de test et un véritable appareil Android.
* Une fois l'application démarrée, vous devriez 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 repérez **New Events**.

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

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

## Étapes suivantes

1. Créez une interface d'achat avec Unity UI Toolkit pour 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)
- [Introducción a PlayFab Economy heredado, Unity IAP y Android](/es/services/playfab/economy-monetization/economy/tutorials/getting-started-with-unity-iap-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)
