Version: 2021.1
Recibos de Compra
Extensiones de la Store (tienda)

Validación de Recibo

La validación de recibo le ayuda a usted prevenir a los usuarios que accedan contenido que no hayan comprado.

Punto de validación

Es mejor práctica validar el recibo en el punto donde se distribuye el contenido de su aplicación.

  • Local validation: (Validación local) Para el contenido del lado del cliente, en el que todo el contenido está contenido en la aplicación y se habilita una vez comprado, la validación debe realizarse en el dispositivo destino, sin necesidad de conectarse a un servidor remoto. Unity IAP está diseñado para admitir la validación local dentro de su aplicación. Consulte Local validation para más información.
  • Remote validation: (Validación remota) Para el contenido del lado del servidor, donde se descarga el contenido una vez se adquirió, la validación debe realizarse en el servidor antes de que se publique el contenido. Unity no ofrece soporte para la validación del servidor; Sin embargo, hay solución de terceros disponibles, como el proyecto IAP de Nobuyori Takahashi (https://github.com/voltrue2/in-app-purchase).

Validación local

Si el contenido que el usuario está comprando ya existe en el dispositivo, la aplicación simplemente tiene que tomar una decisión sobre si desbloquearlo.

Unity IAP proporciona herramientas para ayudarle a ocultar contenido y validar y parse recibos a través de las tiendas de Google Play y Apple.

La Ofuscación de claves de cifrado

La validación de recibo es realizada utilizando unas claves de cifrado; para su aplicación, esta es una llave pública cifrada de Google Play, y/o el certificado raíz de Apple.

Si un usuario puede remplazar estas, entonces pueden ganarle a sus revisiones de validación de recibo, por lo que es importante hacerlas difícil para el usuario para que fácilmente encuentre y modifique estás llaves.

Unity IAP proporciona una herramienta que le pueda a ayudar a ofuscar sus llaves de cifrado dentro de su Aplicación. Esto confunde o desordena las llaves para que sea más difícil para un usuario accederlas. En la barra del menú de Unity, ir a Window_ > Unity IAP > IAP Receipt Validation Obfuscator.

La ventana obfuscator
La ventana obfuscator

Esta ventana codifica tanto el certificado raíz de Apple (que se incluye con Unity IAP) como la llave pública de Google Play (desde la página Google Play Developer Console’s Services & APIs de la aplicación) en dos archivos C# files: AppleTangle y GooglePlayTangle. Estos se agregan a su proyecto para su uso en la siguiente sección.

Tenga en cuenta que no tiene que proporcionar una llave pública de Google Play si solo tiene como objetivo las tiendas de Apple y viceversa.

Validando recibos

Utilice la clase CrossPlatformValidator para la validación a través de las tiendas de Google Play y Apple.

Debe proporcionar esta clase con su llave pública de Google Play o con el certificado raíz de Apple o ambos si desea validar en ambas plataformas.

El CrossPlatformValidator realiza dos comprobaciones:

  • La autenticidad del recibo se verifica mediante la validación de la firma.
  • El identificador del bundle de la aplicación en el recibo se compara al de su aplicación. Una excepción InvalidBundleId se lanza si no coinciden.

Tenga en cuenta que el validador sólo valida los recibos generados en las plataformas Google Play y Apple. Los recibos generados en cualquier otra plataforma, incluidas las falsas generadas en el Editor, lanzan una IAPSecurityException.

Si intenta validar un recibo para una plataforma que no ha proporcionado una llave secreta, se lanzará MissingStoreSecretException.

public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
    bool validPurchase = true; // Presume valid for platforms with no R.V.

    // Unity IAP's validation logic is only included on these platforms.
#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
    // Prepare the validator with the secrets we prepared in the Editor
    // obfuscation window.
    var validator = new CrossPlatformValidator(GooglePlayTangle.Data(),
        AppleTangle.Data(), Application.bundleIdentifier);

    try {
        // On Google Play, result has a single product ID.
        // On Apple stores, receipts contain multiple products.
        var result = validator.Validate(e.purchasedProduct.receipt);
        // For informational purposes, we list the receipt(s)
        Debug.Log("Receipt is valid. Contents:");
        foreach (IPurchaseReceipt productReceipt in result) {
            Debug.Log(productReceipt.productID);
            Debug.Log(productReceipt.purchaseDate);
            Debug.Log(productReceipt.transactionID);
        }
    } catch (IAPSecurityException) {
        Debug.Log("Invalid receipt, not unlocking content");
        validPurchase = false;
    }
#endif

    if (validPurchase) {
        // Unlock the appropriate content here.
    }

    return PurchaseProcessingResult.Complete;
}

Es importante que compruebe no sólo que el recibo es válido, sino también qué información contiene. Una técnica común de los usuarios que intentan acceder a contenido sin comprar es suministrar recibos de otros productos o aplicaciones. Estos recibos son genuinos y pasan la validación, por lo que debe tomar decisiones basadas en los ID de producto analizados por CrossPlatformValidator.

Detalles específicos de tiendas

Las diferentes tiendas tienen diferentes campos en sus recibos de compra. Para acceder a los campos específicos de la tienda, IPurchaseReceipt puede reducirse a dos subtipos diferentes:` GooglePlayReceipt y AppleInAppPurchaseReceipt.

var result = validator.Validate(e.purchasedProduct.receipt);
Debug.Log("Receipt is valid. Contents:");
foreach (IPurchaseReceipt productReceipt in result) {
    Debug.Log(productReceipt.productID);
    Debug.Log(productReceipt.purchaseDate);
    Debug.Log(productReceipt.transactionID);

    GooglePlayReceipt google = productReceipt as GooglePlayReceipt;
    if (null != google) {
        // This is Google's Order ID.
        // Note that it is null when testing in the sandbox
        // because Google's sandbox does not provide Order IDs.
        Debug.Log(google.transactionID);
        Debug.Log(google.purchaseState);
        Debug.Log(google.purchaseToken);
    }

    AppleInAppPurchaseReceipt apple = productReceipt as AppleInAppPurchaseReceipt;
    if (null != apple) {
        Debug.Log(apple.originalTransactionIdentifier);
        Debug.Log(apple.subscriptionExpirationDate);
        Debug.Log(apple.cancellationDate);
        Debug.Log(apple.quantity);
    }
}

Parsing recibos Apple raw (crudos)

Utilice la clase AppleValidator para extraer información detallada sobre un recibo de Apple. Tenga en cuenta que esta clase sólo funciona con los recibos de la aplicación de iOS desde la versión 7.0 en adelante, no los recibos de transacciones obsoletos de Apple.

#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// Get a reference to IAppleConfiguration during IAP initialization.
var appleConfig = builder.Configure<IAppleConfiguration>();
var receiptData = System.Convert.FromBase64String(appleConfig.appReceipt);
AppleReceipt receipt = new AppleValidator(AppleTangle.Data()).Validate(receiptData);

Debug.Log(receipt.bundleID);
Debug.Log(receipt.receiptCreationDate);
foreach (AppleInAppPurchaseReceipt productReceipt in receipt.inAppPurchaseReceipts) {
    Debug.Log(productReceipt.transactionIdentifier);
    Debug.Log(productReceipt.productIdentifier);
}
#endif

The AppleReceipt type models Apple’s ASN1 receipt format. See Apple’s documentation for an explanation of its fields.

Recibos de Compra
Extensiones de la Store (tienda)