Visão geral da SKAdNetwork
A SKAdNetwork é uma estrutura fornecida pela Apple para permitir a mensuração de campanhas publicitárias de instalação de aplicativos com privacidade no iOS(saiba mais). A estrutura ajuda a mensurar as taxas de conversão de campanhas de instalação de aplicativos sem comprometer os identificadores dos usuários.
Como funciona a SKAdNetwork?
Na SKAdNetwork, o processo de atribuição é conduzido pela App Store por meio dos servidores da Apple. As informações de atribuição são então desconectadas dos identificadores de usuários e das informações temporais e enviadas para a rede.
Quando um anúncio é clicado e a loja é aberta, o aplicativo de publicação e a rede fornecem algumas informações básicas, como rede, editor e ID da campanha. Se o aplicativo do anunciante tiver sido iniciado e registrado na SKAdNetwork, o dispositivo enviará uma notificação de conversão bem-sucedida para a rede. Ele informará os valores anexados juntamente com um valor de conversão que pode ser informado pelo aplicativo anunciado.
Essa notificação será enviada pelo menos 24 horas após o primeiro lançamento e será desprovida de qualquer informação de identificação do dispositivo ou do usuário.
Além disso, a App Store conduz o processo para que o aplicativo anunciado não tenha conhecimento do anúncio e do editor originais. Dessa forma, a rede é notificada sobre uma instalação sem saber nada sobre o usuário que a instalou.
O que esperar ao usar a SKAdNetwork?
A SKAdNetwork tem algumas vantagens importantes. Ela fornece a você todas as informações a seguir:
- Atribuição do último clique que funciona sem consentimento
- Detalhamento de fontes, campanhas e editores
- Valores de conversão pós-instalação (até 64 valores discretos)
- Assinaturas criptográficas para validar instalações
No entanto, em sua forma atual, a SKAdNetwork é básica e requer implementação e coordenação cuidadosas entre várias entidades para garantir seu funcionamento.
Aqui estão algumas das limitações atuais da SKAdNetwork:
- Não há dados no nível do usuário
- Não há atribuição de visualização
- Faixa limitada de valores de conversão:
- Um único evento de conversão por instalação/reinstalação
- Até 64 valores de conversão (6 bits)
- Granularidade limitada:
- Até 100 valores de campanha
- Nenhuma representação para o grupo de anúncios e o nível criativo
- Sem LTV / coortes longas
- Exposição a fraudes:
- O valor da conversão em si não é assinado (pode ser manipulado)
- Os postbacks podem ser duplicados.
Para superar alguns desses problemas, a Singular lançou um padrão público para a implementação da SKAdNetwork, bem como várias postagens de blog que podem ajudá-lo a navegar pela SKAdNEtwork:
- SKAN: um padrão prático para a implementação da SKAdNetwork
- SKAdNetwork 101 - O que é isso? O que isso significa para você?
- Código da SKAdNetwork: A Singular lança um repositório no Github com código para redes de anúncios, editores e anunciantes
- Como testar a SKAdNetwork: instruções passo a passo
- Singular anuncia o primeiro suporte ao mercado para substituir o IDFA
- Medição avançada usando SKAdNetwork: Desbloqueando o ROAS
- Segurança de SKAdNetwork 2.0: Uma configuração perfeita para estabelecer confiança
Implementação da SKAdNetwork S2S
A solução SKAdNetwork Singular consiste nos seguintes componentes:
- Código do lado do cliente para implementar a SKAdNetwork
- Validação e agregação de postback de todas as redes
- Proteção contra fraudes:
- Validação de assinatura e redução de ID de transação.
- Configuração segura com redes para verificar parâmetros que não são assinados (valor de conversão e geodados).
- Gerenciamento do valor de conversão: oferece a capacidade de configurar dinamicamente no painel da Singular qual atividade pós-instalação deve ser codificada no valor de conversão da SKAdNetwork.
- Relatórios: Traduzir o ID limitado da campanha SKAdNetwork e enriquecer os dados com mais parâmetros e granularidades de marketing.
- Postbacks de parceiros: Fornece o envio de postbacks de SKAdNetwork com um valor de conversão decodificado em eventos e receita, o que é fundamental para sua otimização.
Para clientes que usam uma integração Singular de servidor para servidor, a implementação da SKAdNetwork consiste em duas partes principais:
- Implementação da SKAdNetwork no lado do cliente: Essa parte é fundamental para registrar seus aplicativos na SKAdNetwork e gerenciar o valor de conversão da SKAdNetwork de forma inteligente. Isso significa que, ao implementá-la, você poderá otimizar suas campanhas com base nas atribuições de SKAdNetwork e nas atividades pós-instalação associadas.
- Atualização da integração S2S (opcional): Essa parte é importante para validar e solucionar problemas da implementação no lado do cliente. Ao enriquecer eventos e sessões enviados para o Singular hoje por meio da sessão S2S do Singular e endpoints de eventos com dados da SKAdNetwork (valores de conversão e carimbos de data/hora de atualização), o Singular pode validar se a implementação foi feita corretamente no lado do seu aplicativo.
Implementação do lado do cliente da SKAdNetwork
A Singular fornece exemplos de código que suportam o registro para SKAdNetwork e o gerenciamento do valor de conversão. Esses exemplos de código são responsáveis pelas seguintes partes:
- Suporte e registro da SKAdNetwork
- Gerenciamento do valor de conversão:
- O código se comunica de forma síncrona com um endpoint da Singular para receber o próximo valor de conversão com base no modelo de conversão configurado. Ele relata eventos/sessões/receita e, em resposta, obtém o próximo valor de conversão, que é um número codificado que representa a atividade pós-instalação que foi configurada para medição no painel do Singular.
- O código também coleta metadados da SKAdnetwork que são usados para validação e cálculo do valor da próxima conversão:
- O registro de data e hora da primeira chamada para a estrutura SKAdNetwork subjacente
- O registro de data e hora da última chamada para a estrutura SKAdNetwork subjacente
- O último valor de conversão atualizado
Atualização da integração S2S
Obrigatório
Quando você tiver um modelo de conversão ativo, nossos pontos de extremidade S2S começarão a retornar um novo campo int chamado "conversion_value", que conterá o próximo valor a ser atualizado no código do lado do cliente.
Opcional
Para validar a integração e solucionar possíveis problemas de implementação, recomendamos usar nossos exemplos de código para estender sua integração S2S atual. Os pontos de extremidade de sessão e evento S2S da Singular já suportam a obtenção de parâmetros SKAdNetwork adicionais, como:
- Valor de conversão mais recente
- Último registro de data e hora de uma chamada para a estrutura SKAdNetwork subjacente
- Primeiro registro de data e hora de uma chamada para a estrutura SKAdNetwork subjacente
Fluxo de integração
O diagrama acima ilustra o fluxo da SKAdNetwork para um cliente S2S:
- Primeiro, o código no aplicativo se comunica com um servidor Singular (por meio de um endpoint dedicado para SKAdNetwork) para obter o valor de conversão mais recente de forma síncrona com base em eventos/sessões/receitas que ocorrem no aplicativo e atualizar a estrutura de SKAdNetwork com esse valor.
- Em segundo lugar, o aplicativo enriquece os eventos e sessões existentes com dados da SKAdNetwork, que serão usados posteriormente para validações.
- Quando o aplicativo terminar de atualizar a estrutura de SKAdNetwork com novos valores de conversão e o cronômetro de SKAdNetwork expirar, o postback de SKAdNetwork será enviado para a rede.
- A rede o encaminhará para a Singular (por meio da configuração segura ou da configuração normal).
- A Singular processará o postback da seguinte forma
- Validando sua assinatura
- Decodificação do valor de conversão com base no modelo de conversão configurado
- Enriquecer o postback com mais parâmetros de marketing voltados para o exterior com base na integração com parceiros e no ID de campanha interna da SKAdNetwork
- Envio dos postbacks decodificados ao BI e aos parceiros
Uma observação importante é que as informações da SKAdNetwork, incluindo instalações e eventos decodificados, poderão ser acessadas por meio de um conjunto diferente de relatórios/APIs/tabelas ETL e postbacks para evitar misturá-las com seus conjuntos de dados existentes. Isso é especialmente importante durante as próximas semanas para permitir que você meça e teste a SKAdNetwork lado a lado com sua campanha existente.
Amostras de código iOS nativo de SKAdNetwork
Interface de SKAdNetwork
Essa interface inclui os seguintes componentes de SKAdNetwork:
Registro na SKAdNetwork:
- Esse método é responsável pelo registro do seu aplicativo na SKAdNetwork. O método subjacente da API da Apple gera uma notificação se o dispositivo tiver dados de atribuição para esse aplicativo e inicia um cronômetro de 24 horas.
- O dispositivo envia a notificação de instalação para o endpoint de postback da rede de anúncios dentro de 0 a 24 horas após a expiração do cronômetro.
- Observe que, se você atualizar o valor de conversão com um valor maior do que o anterior, ele redefinirá o primeiro cronômetro para um novo intervalo de 24 horas(leia mais aqui).
Gerenciamento e atualizações do valor de conversão:
- O valor de conversão é calculado com base na atividade pós-instalação de um dispositivo que é capturado pelos métodos abaixo e em um modelo de conversão selecionado que pode ser configurado dinamicamente pelo usuário.
- Os métodos nesta seção são responsáveis por extrair o próximo valor de conversão do endpoint da Singular de acordo com o modelo de conversão selecionado e a atividade pós-instalação relatada (consulte a documentação acima).
- Os métodos abaixo atualizam o valor de conversão com base nas seguintes atividades pós-instalação:
- Sessão: essencial para a medição da retenção de um usuário com SKAdNetwork
- Conversion Event (Evento de conversão): essencial para a medição do evento de conversão pós-instalação com SKAdNetwork
- Evento de receita: Crítico para a medição de receita com SKAdNetwork
// SKANSnippet.h
#import <Foundation/Foundation.h>
@interface
SKANSnippet : NSObject
// Registre-se para atribuição SkAdNetwork. Você deve chamar esse método o mais rápido possível assim que o aplicativo for iniciado.
+ (void)registerAppForAdNetworkAttribution;
/* Para rastrear retenção e coortes, você precisa chamar esse método após cada sessão. Ele relata os detalhes da sessão e atualiza o valor de conversão devido a esta sessão, se necessário. O valor de conversão será atualizado somente se o novo valor for maior que o valor anterior. O retorno de chamada passado para o método é opcional, você pode usá-lo para executar o código assim que o valor de conversão for atualizado. */
+ (void)updateConversionValueAsync:(void(^)(int, NSError*))handler;
/* Para rastrear eventos de conversão com SKAdNetwork você precisa chamar esse método após cada evento. Ele relata os detalhes do evento e atualiza o valor da conversão devido a esse evento, se necessário. O retorno de chamada passado para o método é opcional, você pode usá-lo para executar o código assim que o valor de conversão for atualizado.*/
+ (void)updateConversionValueAsync:(NSString*)eventName
withCompletionHandler:(void(^)(int, NSError*))handler;
/* Para acompanhar a receita com SKAdNetwork você precisa chamar esse método antes de cada evento de receita. Ele atualizará a receita total, portanto, quando você chamar 'updateConversionValueAsync', o novo valor de conversão será determinado de acordo com o valor total da receita.
Observação:
1. Chame esse método antes de chamar 'updateConversionValueAsync' para garantir que a receita seja atualizada.
2. No caso de tentar novamente um evento, evite chamar este método para que a mesma receita não seja contabilizada duas vezes.*/
+ (void)updateRevenue:(double)amount andCurrency:(NSString*)currency;
// Obtém o valor de conversão atual (nulo se nenhum)
+ (NSNumber *)getConversionValue;
@end
Implementação da interface SKAdNetwork
// 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"
// Chaves para armazenamento UserDefaults
#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
@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 = @"";
components.queryItems = @[
[NSURLQueryItem queryItemWithName:@"a" value:@""],
[NSURLQueryItem queryItemWithName:@"i" value:bundleIdentifier],
[NSURLQueryItem queryItemWithName:@"app_v" value:@""],
[NSURLQueryItem queryItemWithName:@"n" value:eventName],
[NSURLQueryItem queryItemWithName:@"p" value:@"iOS"],
[NSURLQueryItem queryItemWithName:@"idfv" value:@""],
[NSURLQueryItem queryItemWithName:@"idfa" value:@""],
[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;
}
Metadados e métodos de utilitários da SKAdNetwork
Esta seção é responsável pela implementação de utilitários que estão sendo usados na implementação acima. Observe que esses utilitários são essenciais para manter e armazenar os metadados necessários para calcular os próximos valores de conversão.
Os seguintes utilitários são implementados:
Salvar valores em UserDefaults (e recuperá-los):
- Registro de data e hora da primeira chamada para a API SKAdNetwork subjacente
- Registro de data e hora da última chamada para a API SKAdNetwork subjacente
- Receita total por moeda
Conversão de valores entre diferentes representações:
- Dicionário para string JSON
- JSON para dicionário
+ (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
Atualização da integração S2S - Implementação (opcional)
Atualize sua integração S2S com os seguintes metadados da SKAdNetwork (esses metadados devem ser encaminhados em todas as sessões e eventos relatados à Singular para validação da implementação da SKAdNetwork):
- skan_conversion_value - O valor de conversão mais recente
- skan_first_call_timestamp - Registro de data e hora Unix da primeira chamada à API SkAdNetwork subjacente
- skan_last_call_timestamp - Carimbo de data/hora Unix da última chamada à API SkAdNetwork subjacente
O trecho de código a seguir mostra como extrair esses valores:
NSDictionary *values = @{
@"skan_conversion_value":
[[SKANSnippet getConversionValue] stringValue]],
@"skan_first_call_timestamp":
[NSString stringWithFormat:@"%ld", [SKANSnippet getFirstSkanCallTimestamp]],
@"skan_last_call_timestamp":
[NSString stringWithFormat:@"%ld", [SKANSnippet getLastSkanCallTimestamp]]
};
Agora, depois de enviar esses parâmetros para o seu servidor, você pode encaminhá-los por meio de nossos endpoints de API de servidor para servidor. Para saber mais, pesquise esses parâmetros em nossa referência de API server-to-server.
Exemplo de fluxo do ciclo de vida do aplicativo
// No lançamento do aplicativo
[SKANSnippet registerAppForAdNetworkAttribution];
// Após cada sessão ser tratada
[SKANSnippet updateConversionValueAsync:handler];
// Depois de lidar com eventos sem fins lucrativos
[SKANSnippet updateConversionValueAsync:@"event_name"
withCompletionHandler:handler];
// Depois de lidar com eventos de receita
[SKANSnippet updateRevenue:15.53 andCurrency:@"KRW"];
[SKANSnippet updateConversionValueAsync:@"revenue_event_name" withCompletionHandler:handler];
Registro de alterações de código
- 1 de outubro de 2020
- Correção [IMPORTANTE]:o mecanismo de bloqueio em `getConversionValueFromServer`não foi inicializado corretamente
- Aprimoramento: retorno do motivo de falha da resposta do nosso servidor
- 23 de setembro de 2020
- Correção [IMPORTANTE]:`setConversionValue` agora chama `updateConversionValue`
- Aprimorado: tratamento de erros ao recuperar o valor de conversão mais recente do servidor
- 15 de setembro de 2020
- Alterado [IMPORTANTE]: Se o valor de conversão não for definido, o valor padrão retornado por `getConversionValue` será 0 em vez de nulo
- Aprimorado: Relatório e tratamento de receita
- Aprimorado: Recuperação do próximo valor de conversão de forma assíncrona
Teste de sua implementação
Gerenciamento de conversões
Para simular o fluxo do seu aplicativo e testar sua implementação, substitua o endpoint de produção do gerenciamento de conversões(SINGULAR_API_URL) pelo seguinte endpoint de teste -
-
- https://skadnetwork-testing.singular.net/api/v1/conversion_value
- Nenhuma chave de API é necessária
Um fluxo de teste sugerido:
- Gere 3 eventos diferentes em seu aplicativo.
-
- Se tudo estiver implementado corretamente
- Após cada evento, updateConversionValueAsync deve ser chamado (certifique-se de que o valor de conversão padrão seja inicializado em 0).
- O ponto de extremidade de teste recebe o valor de conversão atual do aplicativo e retorna o próximo valor.
- Se tudo estiver implementado corretamente
- Registre o valor de conversão retornado para verificar se tudo está funcionando conforme o esperado.
- O ponto de extremidade de teste é implementado para retornar valores entre 0 e 2.
- Portanto, após a terceira chamada, ele retornará uma cadeia de caracteres vazia, e o último valor será usado como o valor final de conversão da SKAdNetwork.
-