Servidor a servidor - Guía de implantación de SKAdNetwork 3

Documento

SKAdNetwork 4 Disponible: Para conocer la última versión de SKAdNetwork, consulte la Guía de implementación de SKAdNetwork 4.

Guía de implementación de SKAdNetwork 3.0 S2S

Implemente el marco SKAdNetwork 3.0 de Apple para la atribución de iOS conforme a la privacidad mediante la integración de servidor a servidor para medir el rendimiento de la campaña de instalación de aplicaciones sin comprometer los identificadores de usuario.


Visión general

¿Qué es SKAdNetwork?

SKAdNetwork es el marco de atribución de Apple que preserva la privacidad y permite medir las tasas de conversión de las campañas publicitarias de instalación de aplicaciones en iOS sin necesidad de identificadores a nivel de usuario.

El marco procesa la atribución a través de los servidores de App Store, desconectando la información de atribución de los identificadores de usuario y los datos temporales antes de enviarla a las redes publicitarias.

Documentación de Apple: Referencia del marco SKAdNetwork


Cómo funciona SKAdNetwork

El proceso de atribución se realiza íntegramente a través de la infraestructura de Apple, lo que garantiza la privacidad del usuario al tiempo que permite medir el rendimiento de la campaña.

SKAdNetwork Attribution Flow

Flujo de atribución:

  1. Clic en el anuncio: El usuario hace clic en un anuncio que contiene la firma de SKAdNetwork con el ID de la red, del editor y de la campaña.
  2. Apertura de la App Store: El dispositivo almacena los datos de atribución y abre la App Store para la instalación.
  3. Lanzamiento de la aplicación: El usuario instala e inicia la aplicación por primera vez.
  4. Registro: La aplicación se registra en el marco de SKAdNetwork para indicar que la instalación se ha realizado correctamente.
  5. Valor de conversión: La aplicación actualiza opcionalmente el valor de conversión (0-63) que representa la actividad posterior a la instalación.
  6. Ventana de temporizador: El dispositivo espera más de 24 horas tras el primer lanzamiento o la última actualización del valor de conversión.
  7. Postback: App Store envía la atribución a la red publicitaria con el ID de la campaña, el valor de conversión y la firma criptográfica.

Privacidad por diseño:

  • El postback no contiene identificadores de dispositivo ni de usuario
  • El retraso mínimo de 24 horas evita la correlación temporal
  • La aplicación nunca sabe en qué anuncio ha hecho clic el usuario
  • La red nunca sabe qué usuario específico instaló el anuncio

Capacidades y limitaciones

SKAdNetwork ofrece:

  • Atribución de último clic: Funciona sin el consentimiento del usuario o ATT opt-in
  • Desglose de campañas: Granularidad de fuente, campaña y editor
  • Valores de conversión: 64 valores discretos (0-63) para la medición posterior a la instalación
  • Prevención del fraude: Las firmas criptográficas validan la autenticidad de la atribución

Limitaciones actuales:

  • Sin datos a nivel de usuario: No se puede realizar un seguimiento de los recorridos individuales de los usuarios
  • No View-Through: Sólo atribución basada en clics
  • Valores de conversión limitados: Un único valor de 6 bits (0-63) por instalación
  • Granularidad limitada: Máximo 100 ID de campaña, sin desglose por grupo de anuncios o creatividad
  • Sin cohortes largas: Marco temporal limitado para la medición de conversiones
  • Exposición al fraude: El valor de conversión en sí no está firmado, los postbacks pueden duplicarse

Recursos de Singular

Singular proporciona recursos completos para la implementación y optimización de SKAdNetwork.


Solución Singular SKAdNetwork

La solución SKAdNetwork de Singular proporciona una gestión de la atribución de extremo a extremo, desde la implementación en el lado del cliente hasta el procesamiento postback y la optimización de la campaña.

Componentes de la solución

Características de la plataforma

Soporte completo de SKAdNetwork en todo el flujo de trabajo de atribución y análisis.

Componente Funcionalidad
Código cliente Muestras de código nativo iOS para el registro del marco SKAdNetwork y la gestión del valor de conversión.
Procesamiento de postbacks Validación y agregación de postbacks de todas las redes publicitarias con informes unificados
Protección contra el fraude Validación de firmas criptográficas, deduplicación de ID de transacciones y verificación segura de parámetros
Gestión de conversiones Configuración dinámica del panel de control para codificar las actividades posteriores a la instalación en valores de conversión
Informes Traducción de ID de campaña y enriquecimiento con parámetros de marketing para un análisis granular
Postbacks de socios Valores de conversión descodificados enviados como eventos e ingresos para la optimización de socios

Arquitectura de integración S2S

Componentes de implementación

La integración de servidor a servidor de SKAdNetwork consta de dos áreas principales de implementación.

1.1. Implementación del lado del cliente (obligatoria):

  • Registro del marco SKAdNetwork en el lanzamiento de la aplicación
  • Gestión inteligente del valor de conversión basada en la actividad posterior a la instalación
  • Esencial para la optimización de campañas utilizando la atribución SKAdNetwork

2. Actualización de integración S2S (Opcional):

  • Enriquece los eventos y sesiones de Singular S2S con metadatos de SKAdNetwork
  • Permite la validación de la implementación y la resolución de problemas
  • Proporciona marcas de tiempo de valores de conversión para depuración

Implementación del lado del cliente

Implemente el registro del marco SKAdNetwork y la gestión del valor de conversión utilizando las muestras de código nativo iOS de Singular para una medición óptima de la campaña.

Responsabilidades de implementación

Funciones principales

El código del lado del cliente gestiona dos funciones críticas para la medición de SKAdNetwork.

  1. Registro SKAdNetwork: Registra la aplicación con el framework inmediatamente después del lanzamiento para permitir la atribución.
  2. Gestión del valor de conversión:
    • Se comunica de forma sincrónica con el punto final de Singular para recibir el siguiente valor de conversión.
    • Informa de sesiones, eventos e ingresos a Singular.
    • Recibe un valor de conversión codificado que representa la actividad posterior a la instalación configurada.
    • Recoge metadatos de SKAdNetwork (marca de tiempo de la primera llamada, marca de tiempo de la última llamada, valor actual).

Interfaz SKAdNetwork

Definición de métodos

La interfaz incluye métodos para el registro de marcos, el seguimiento de sesiones, el seguimiento de eventos y la medición de ingresos.

SKANSnippet.h
//  SKANSnippet.h

#import <Foundation/Foundation.h>

@interface SKANSnippet : NSObject

// Register for SKAdNetwork attribution.
// Call this method as soon as possible once app is launched
+ (void)registerAppForAdNetworkAttribution;

// Track retention and cohorts by calling after each session.
// Reports session details and updates conversion value if needed.
// Conversion value updates only if new value greater than previous.
// Optional callback runs once conversion value updated.
+ (void)updateConversionValueAsync:(void(^)(int, NSError*))handler;

// Track conversion events by calling after each event.
// Reports event details and updates conversion value if needed.
// Optional callback runs once conversion value updated.
+ (void)updateConversionValueAsync:(NSString*)eventName
               withCompletionHandler:(void(^)(int, NSError*))handler;

// Track revenue by calling before each revenue event.
// Updates total revenue for next conversion value calculation.
// Note:
// 1. Call before 'updateConversionValueAsync' to ensure revenue included
// 2. Avoid calling on event retries to prevent double-counting
+ (void)updateRevenue:(double)amount andCurrency:(NSString*)currency;

// Gets current conversion value (nil if none set)
+ (NSNumber *)getConversionValue;

@end

Método de registro

registerAppForAdNetworkAttribution registra la aplicación en el marco SKAdNetwork, iniciando el temporizador de atribución de 24 horas.

Comportamiento del temporizador:

  • El dispositivo envía una notificación de instalación 0-24 horas después de que expire el temporizador.
  • La actualización del valor de conversión con un valor superior reinicia el temporizador para el nuevo intervalo de 24 horas.
  • Referencia Apple: updateConversionValue Documentación

Métodos de valor de conversión

Los métodos calculan y actualizan los valores de conversión en función de la actividad posterior a la instalación y del modelo de conversión configurado.

Actividades admitidas:

  • Sesiones: Crítico para la medición de la retención
  • Eventos de conversión: Crítico para la medición de eventos post-instalación
  • Eventos de ingresos: Críticos para la medición de ingresos

Implementación de la interfaz

Código de implementación completa

La implementación completa gestiona el registro, la gestión de conversiones y la comunicación Singular API.

SKANSnippet.m
//  SKANSnippet.m

#import "SKANSnippet.h"
#import <StoreKit/SKAdNetwork.h>

#define SESSION_EVENT_NAME @"__SESSION__" 
#define SINGULAR_API_URL @"https://sdk-api-v1.singular.net/api/v1/conversion_value"

// Keys for UserDefaults storage
#define CONVERSION_VALUE_KEY @"skan_conversion_value"
#define FIRST_SKAN_CALL_TIMESTAMP @"skan_first_call_to_skadnetwork_timestamp"
#define LAST_SKAN_CALL_TIMESTAMP @"skan_last_call_to_skadnetwork_timestamp"
#define TOTAL_REVENUE_BY_CURRENCY_KEY @"skan_total_revenue_by_currency"
#define SECONDS_PER_DAY 86400

static NSLock *lockObject;

@implementation SKANSnippet

+ (void)registerAppForAdNetworkAttribution {
    if ([SKANSnippet getFirstSkanCallTimestamp] != 0) {
        return;
    }

    if (@available(iOS 11.3, *)) {
        [SKAdNetwork registerAppForAdNetworkAttribution];
        [SKANSnippet setFirstSkanCallTimestamp];
        [SKANSnippet setLastSkanCallTimestamp];
    }
}

+ (void)updateConversionValueAsync:(void(^)(int, NSError*))handler {
    [SKANSnippet updateConversionValueAsync:SESSION_EVENT_NAME withCompletionHandler:handler];
}

+ (void)updateConversionValueAsync:(NSString*)eventName withCompletionHandler:(void(^)(int, NSError*))handler {
    if (@available(iOS 14, *)) {
        if ([SKANSnippet isSkanUpdateWindowOver]) {
            return;
        }
        
        [SKANSnippet getConversionValueFromServer:eventName withCompletionHandler:handler];
    }
}

+ (void)updateRevenue:(double)amount andCurrency:(NSString*)currency {
    if (@available(iOS 14, *)) {
        
        // Update total revenues
        if (amount != 0 && currency) {
            NSMutableDictionary* revenues = [[SKANSnippet getTotalRevenue] mutableCopy];
            NSNumber* currentRevenue = @(0);
            
            if ([revenues objectForKey:currency]) {
                currentRevenue = [revenues objectForKey:currency];
            }
            
            currentRevenue = @([currentRevenue floatValue] + amount);
            [revenues setObject:currentRevenue forKey:currency];
            
            [SKANSnippet setTotalRevenue:revenues];
        }
    }
}

+ (NSNumber *)getConversionValue {
    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
    if (![userDefaults objectForKey:CONVERSION_VALUE_KEY]) {
        return nil;
    }
    return @([userDefaults integerForKey:CONVERSION_VALUE_KEY]);
}

+ (void)getConversionValueFromServer:(NSString*)eventName withCompletionHandler:(void(^)(int, NSError*))handler {
    if (!lockObject) {
        lockObject = [NSLock new];
    }
    
    // Making the lock async so it will not freeze the calling thread
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
        
        [lockObject lock];
        
        NSURLComponents *components = [NSURLComponents componentsWithString:SINGULAR_API_URL];
        
        NSString* bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
        
        components.queryItems = @[
            [NSURLQueryItem queryItemWithName:@"a" value:@"YOUR_SDK_KEY"],
            [NSURLQueryItem queryItemWithName:@"i" value:bundleIdentifier],
            [NSURLQueryItem queryItemWithName:@"app_v" value:@"YOUR_APP_VERSION"],
            [NSURLQueryItem queryItemWithName:@"n" value:eventName],
            [NSURLQueryItem queryItemWithName:@"p" value:@"iOS"],
            [NSURLQueryItem queryItemWithName:@"idfv" value:@"YOUR_IDFV"],
            [NSURLQueryItem queryItemWithName:@"idfa" value:@"YOUR_IDFA"],
            [NSURLQueryItem queryItemWithName:@"conversion_value"  value:[[SKANSnippet getConversionValue] stringValue]],
            [NSURLQueryItem queryItemWithName:@"total_revenue_by_currency"  value:[SKANSnippet dictionaryToJsonString:[SKANSnippet getTotalRevenue]]],
            [NSURLQueryItem queryItemWithName:@"first_call_to_skadnetwork_timestamp"  value:[NSString stringWithFormat:@"%ld", [SKANSnippet getFirstSkanCallTimestamp]]],
            [NSURLQueryItem queryItemWithName:@"last_call_to_skadnetwork_timestamp"  value:[NSString stringWithFormat:@"%ld", [SKANSnippet getLastSkanCallTimestamp]]],
        ];
        
        [[[NSURLSession sharedSession] dataTaskWithURL:components.URL
                                     completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            if (error) {
                [lockObject unlock];
                if (handler) {
                    handler(-1, error);
                }
                return;
            }
            
            NSDictionary* parsedResponse = [SKANSnippet jsonDataToDictionary:data];
            
            if (!parsedResponse) {
                [lockObject unlock];
                if (handler) {
                    handler(-1, [NSError errorWithDomain:bundleIdentifier
                                                    code:0
                                                userInfo:@{NSLocalizedDescriptionKey:@"Failed parsing server response"}]);
                }
                return;
            }
            
            NSNumber *conversionValue = [parsedResponse objectForKey:@"conversion_value"];
            
            if (!conversionValue) {
                [lockObject unlock];
                NSString *status = [parsedResponse objectForKey:@"status"];
                
                if (!status || ![status isEqualToString:@"ok"]) {
                    if (handler) {
                    NSString *reason = [parsedResponse objectForKey:@"reason"];
                        if (!reason) {
                            reason = @"Got error from server";
                        }
                        
                        handler(-1, [NSError errorWithDomain:bundleIdentifier
                                                        code:0
                                                    userInfo:@{NSLocalizedDescriptionKey:reason}]);
                    }
                }
                return;
            }
            
            NSNumber* currentValue = [SKANSnippet getConversionValue];
            if ([conversionValue intValue] <= [currentValue intValue]) {
                [lockObject unlock];
                return;
            }
            
            [SKANSnippet setConversionValue:[conversionValue intValue]];
            [SKANSnippet setLastSkanCallTimestamp];
            
            if (![SKANSnippet getFirstSkanCallTimestamp]) {
                [SKANSnippet setFirstSkanCallTimestamp];
            }
            
            [lockObject unlock];
            
            if (handler) {
                handler([conversionValue intValue], error);
            }
        }] resume];
    });
}

+ (BOOL)isSkanUpdateWindowOver {        
    NSInteger timeDiff = [SKANSnippet getCurrentUnixTimestamp] - [SKANSnippet getLastSkanCallTimestamp];
    return SECONDS_PER_DAY <= timeDiff;
}

@end

Métodos de utilidad

Gestión de metadatos

Los métodos de utilidad gestionan el almacenamiento de metadatos de SKAdNetwork en UserDefaults, crítico para el cálculo del valor de conversión.

Implementación crítica: Estas utilidades mantienen los metadatos necesarios para el cálculo preciso del valor de conversión. No modificar a menos que sea necesario.

Utility Methods
+ (NSInteger)getFirstSkanCallTimestamp {
    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults integerForKey:FIRST_SKAN_CALL_TIMESTAMP];
}

+ (NSInteger)getLastSkanCallTimestamp {
    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults integerForKey:LAST_SKAN_CALL_TIMESTAMP];
}

+ (NSDictionary*)getTotalRevenue {
    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
    if (![userDefaults objectForKey:TOTAL_REVENUE_BY_CURRENCY_KEY]) {
        return [NSDictionary new];
    }
    return [userDefaults objectForKey:TOTAL_REVENUE_BY_CURRENCY_KEY];
}

+ (NSInteger)getCurrentUnixTimestamp {
    return [[NSDate date]timeIntervalSince1970];
}

+ (void)setConversionValue:(int)value {
    if (@available(iOS 14.0, *)) {
        if (value <= [[SKANSnippet getConversionValue] intValue]) {
            return;
        }
        
        [SKAdNetwork updateConversionValue:value];
        
        NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
        [userDefaults setInteger:value forKey:CONVERSION_VALUE_KEY];
        [userDefaults synchronize];
    }
}

+ (void)setFirstSkanCallTimestamp {
    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setInteger:[SKANSnippet getCurrentUnixTimestamp] 
forKey:FIRST_SKAN_CALL_TIMESTAMP]; [userDefaults synchronize]; } + (void)setLastSkanCallTimestamp { NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setInteger:[SKANSnippet getCurrentUnixTimestamp]
forKey:LAST_SKAN_CALL_TIMESTAMP]; [userDefaults synchronize]; } + (void)setTotalRevenue:(NSDictionary *)values { NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setObject:values forKey:TOTAL_REVENUE_BY_CURRENCY_KEY]; [userDefaults synchronize]; } + (NSString*)dictionaryToJSONString:(NSDictionary*)dictionary { if (!dictionary || [dictionary count] == 0){ return @"{}"; } NSError *error; NSData *JSONData = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&error]; if (error || !JSONData) { return @"{}"; } return [[NSString alloc] initWithData:JSONData
encoding:NSUTF8StringEncoding]; } + (NSDictionary*)JSONDataToDictionary:(NSData*)JSONData { if (!JSONData) { return nil; } NSError * error; NSDictionary * parsedData = [NSJSONSerialization
JSONObjectWithData:JSONData options:kNilOptions error:&error]; if (error || !parsedData) { return nil; } return parsedData; } @end

Actualización de la integración S2S

Mejora opcional de la integración de servidor a servidor con los metadatos de SKAdNetwork para la validación de la implementación y la resolución de problemas.

Actualizaciones obligatorias

Respuesta del valor de conversión

Una vez activado el modelo de conversión, los puntos finales S2S devuelven el campo entero conversion_value que contiene el siguiente valor para la actualización del lado del cliente.

Tratamiento de la respuesta: Análisis de conversion_valuea partir de las respuestas de los puntos finales S2S y aplicación al marco SKAdNetwork mediante código del lado del cliente.


Mejoras opcionales

Parámetros de metadatos

Enriquezca las solicitudes de sesiones y eventos S2S con metadatos SKAdNetwork para validar la integración y solucionar problemas de implementación.

Parámetro Descripción
skan_conversion_value Último valor de conversión en el momento de la solicitud
skan_first_call_timestamp Fecha y hora Unix de la primera llamada a la API de SKAdNetwork
skan_last_call_timestamp Marca de tiempo Unix de la última llamada a la API de SKAdNetwork

Código de extracción de metadatos

Extraer valores de metadatos SKAdNetwork utilizando métodos de utilidad para la transmisión S2S.

Objective-C
NSDictionary *skanMetadata = @{
    @"skan_conversion_value": 
        [[SKANSnippet getConversionValue] stringValue],
    @"skan_first_call_timestamp": 
        [NSString stringWithFormat:@"%ld", [SKANSnippet getFirstSkanCallTimestamp]],
    @"skan_last_call_timestamp": 
        [NSString stringWithFormat:@"%ld", [SKANSnippet getLastSkanCallTimestamp]]
};

// Forward skanMetadata to your server for S2S API enrichment

Transmitir los parámetros al lado del servidor y añadirlos a las solicitudes de la API S2S Singular. Documentación completa de los parámetros: Referencia de la API S2S


Flujo de integración

Flujo completo de SKAdNetwork para clientes S2S, desde la gestión de la conversión en el lado del cliente hasta el procesamiento posterior.

SKAdNetwork S2S Integration Flow

Etapas del flujo

Proceso de extremo a extremo

  1. Solicitud de valor de conversión: El código de la aplicación se comunica con el punto final de Singular de forma sincrónica para obtener el último valor de conversión basado en sesiones, eventos e ingresos.
  2. Actualización del marco : la aplicación actualiza el marco SKAdNetwork con el valor de conversión recibido.
  3. Enriquecimiento de metadatos: La aplicación enriquece los eventos y sesiones S2S con metadatos SKAdNetwork para su validación.
  4. Expiración del temporizador: Transcurridas más de 24 horas desde la última actualización, SKAdNetwork envía un postback a la red publicitaria.
  5. Reenvío de postbacks: La red reenvía el postback a Singular (configuración segura o normal)
  6. Procesamiento de postbacks: Singular procesa el postback:
    • Validación de la firma criptográfica
    • Decodificación del valor de conversión utilizando el modelo configurado
    • Enriquecimiento con parámetros de marketing basados en integraciones de socios
    • Envío de los datos descodificados a BI y a los socios mediante postbacks

Separación de datos: Los datos de SKAdNetwork (instalaciones y eventos descodificados) accesibles a través de informes, API, tablas ETL y postbacks separados para evitar que se mezclen con los conjuntos de datos existentes durante las pruebas y la validación.


Implementación del ciclo de vida de la aplicación

Integre los métodos de SKAdNetwork en los puntos adecuados del ciclo de vida de la aplicación para una cobertura completa de la atribución.

Ejemplo de implementación

Colocación del método

Objective-C
// On app launch (in applicationDidFinishLaunching)
[SKANSnippet registerAppForAdNetworkAttribution];

// After each session handled
[SKANSnippet updateConversionValueAsync:^(int value, NSError *error) {
    if (error) {
        NSLog(@"Conversion value update failed: %@", error);
    } else {
        NSLog(@"Conversion value updated to: %d", value);
    }
}];

// After handling non-revenue events
[SKANSnippet updateConversionValueAsync:@"event_name" 
                   withCompletionHandler:^(int value, NSError *error) {
    if (error) {
        NSLog(@"Event conversion value update failed: %@", error);
    } else {
        NSLog(@"Event conversion value updated to: %d", value);
    }
}];

// After handling revenue events
[SKANSnippet updateRevenue:15.53 andCurrency:@"USD"];
[SKANSnippet updateConversionValueAsync:@"revenue_event_name" 
                   withCompletionHandler:^(int value, NSError *error) {
    if (error) {
        NSLog(@"Revenue conversion value update failed: %@", error);
    } else {
        NSLog(@"Revenue conversion value updated to: %d", value);
    }
}];

Pruebas de implementación

Valide la implementación de SKAdNetwork utilizando el punto final de prueba de Singular antes de la implementación en producción.

Entorno de prueba

Configuración del endpoint de prueba

Sustituya el endpoint de gestión de conversión de producción por el endpoint de prueba para simular el flujo de la aplicación.

URL del endpoint de prueba:

https://skadnetwork-testing.singular.net/api/v1/conversion_value
  • No se requiere clave API para el endpoint de prueba
  • Devuelve los valores de conversión 0-2 secuencialmente
  • Devuelve una cadena vacía tras la tercera llamada

Procedimiento de prueba

Pasos de validación

  1. Actualizar punto final: Sustituir la constante SINGULAR_API_URLpor la URL del endpoint de prueba
  2. Inicializar valor de conversión: Asegurar que el valor de conversión por defecto se inicializa a 0
  3. Generar eventos: Activar 3 eventos diferentes dentro de la aplicación
  4. Verificar actualizaciones: Confirmar updateConversionValueAsync llamada después de cada evento
  5. Registrar valores: Registrar los valores de conversión devueltos para verificar la progresión correcta (0 → 1 → 2)
  6. Confirmar finalización: Después de la tercera llamada, verificar la respuesta vacía y la retención del valor final

Comportamiento esperado:

  • Primer evento: Recibe el valor de conversión 0
  • Segundo evento: Recibe valor de conversión 1
  • Tercer evento: Recibe valor de conversión 2
  • Cuarto+ eventos: Respuesta vacía, el valor 2 persiste

Registro de cambios del código

Seguimiento de las actualizaciones de muestras de código y correcciones críticas aplicadas a lo largo del tiempo.

Historial de versiones

Fecha Cambios
1 de octubre de 2020
  • Corrección [CRÍTICA]: Mecanismo de bloqueo en la inicialización de getConversionValueFromServer corregido
  • Mejorado: La razón de fallo de respuesta del servidor ahora se devuelve en la gestión de errores
23 de septiembre de 2020
  • Corrección [CRÍTICA]: setConversionValue ahora llama correctamente a updateConversionValue
  • Mejorado: Mejorada la gestión de errores al recuperar valores de conversión del servidor
15 de septiembre de 2020
  • Cambiado [IMPORTANTE]:getConversionValuevalor por defecto cambiado de null a 0 cuando no se establece
  • Mejoras: Mejoras en los informes y la gestión de los ingresos
  • Mejoras: Implementación de recuperación de valor de conversión asíncrona