Pré-requisitos
Conclua as etapas em Integrando um SDK do Singular: Planejamento e Pré-requisitos antes de prosseguir com esta integração.
Importante: Estas etapas de pré-requisito são obrigatórias para qualquer integração do SDK do Singular.
Configuração específica do iOS
Antes de inicializar o SDK, confirme se os itens a seguir estão configurados no seu projeto Xcode. A falta de qualquer um destes itens é uma causa comum de falhas silenciosas do SDK.
Entradas no Info.plist:
-
NSUserTrackingUsageDescription— Uma string voltada ao usuário explicando por que seu app solicita rastreamento. Exigida pela Apple se você exibir o prompt de App Tracking Transparency (ATT) ou ler o IDFA. O SDK do Singular respeita o ATT automaticamente; sem esta chave o SDK continua funcionando, mas não consegue acessar o IDFA no iOS 14.5+. -
URL Types e
CFBundleURLSchemes— Obrigatórios se sua estratégia de deep link usar esquemas de URI personalizados (ex.:myapp://). Não são necessários para Universal Links / Singular Links via HTTPS.
Entitlements (Signing & Capabilities):
-
Associated Domains
— Adicione uma entrada por domínio com a marca Singular no formato
applinks:yourcompany.sng.link. Obrigatório para atribuição via Universal Link / Singular Link. Este domínio hospedado pela Singular irá hospedar um arquivo JSONapple-app-site-association(AASA) que a Apple baixa no momento da instalação. O arquivo AASA é gerado e atualizado quando links são criados para o app na Plataforma Singular. - Push Notifications — Obrigatórias para rastreamento de desinstalação e re-engajamento atribuído por push. Consulte os artigos sobre Suporte a Push Notifications e Rastreamento de Desinstalação.
Frameworks do sistema obrigatórios (somente para integração manual — CocoaPods e SwiftPM os vinculam automaticamente):
-
StoreKit.framework— IAP e SKAdNetwork. -
AdServices.framework— Token de atribuição do Apple Search Ads (iOS 14.3+). -
AppTrackingTransparency.framework— Prompt do ATT e status de autorização (iOS 14.5+). -
UserNotifications.framework— Push notifications. -
WebKit.framework— Obrigatório somente se você usar a ponte JS WKWebView do Singular.
Instalação
Escolha seu método de instalação preferido. Recomendamos o CocoaPods para a maioria dos projetos.
Decisão rápida:
- Já usa CocoaPods? Use o Método 1
- Projeto somente SPM? Use o Método 2
- Sem gerenciador de pacotes? Use o Método 3
Métodos de instalação
Método 1: CocoaPods (Recomendado)
Requisitos:
- CocoaPods instalado ( guia de instalação )
- Acesso ao Terminal no diretório do seu projeto
Etapas de instalação:
-
Inicialize o Podfile (pule se já tiver um):
cd /path/to/your/project pod init -
Adicione o SDK do Singular ao seu Podfile:
platform :ios, '12.0' target 'YourAppName' do use_frameworks! # Singular SDK pod 'Singular-SDK' end -
Instale as dependências:
pod install -
Abra o workspace:
A partir de agora, abra
.xcworkspaceem vez de.xcodeproj - Somente para projetos Swift: Crie o bridging header (veja abaixo)
Método 2: Swift Package Manager
Etapas de instalação:
- No Xcode: File → Add Packages
-
Informe a URL do repositório:
https://github.com/singular-labs/Singular-iOS-SDK - Selecione a versão e clique em Add Package
-
Adicione os frameworks obrigatórios:
Vá em Build Phases → Link Binary with Libraries e adicione:-
Vincule as bibliotecas obrigatórias:
Vá em Build Phases → Link Binary With Libraries e adicione:- Libsqlite3.0.tbd
- SystemConfiguration.framework
- Security.framework
- Libz.tbd
- AdSupport.framework
- WebKit.framework
- StoreKit.framework
- AdServices.framework (marque como Optional)
-
Vincule as bibliotecas obrigatórias:
- Somente para projetos Swift: Crie o bridging header (veja abaixo)
Método 3: Instalação manual do framework
Quando usar: Use este método apenas se não for possível usar CocoaPods ou SPM.
Baixar o framework:
- Xcode 12+: Baixar .xcframework
- Xcode 11 e anteriores: Baixar .framework
Etapas de instalação:
- Descompacte o framework baixado
- No Xcode: Clique com o botão direito no projeto → Add Files To [Project]
- Selecione Create Groups e adicione a pasta do framework
-
Vincule as bibliotecas obrigatórias:
Vá em Build Phases → Link Binary With Libraries e adicione:- Libsqlite3.0.tbd
- SystemConfiguration.framework
- Security.framework
- Libz.tbd
- AdSupport.framework
- WebKit.framework
- StoreKit.framework
- AdServices.framework (marque como Optional)
-
Incorpore o framework:
Vá em General → Frameworks, Libraries, and Embedded Content
Defina o framework Singular como Embed & Sign
Bridging Header do Swift
Importante: Obrigatório para projetos Swift que usam CocoaPods ou SPM.
-
Crie o arquivo de header:
Xcode → File → New → File → Header File
Nomeie comoYourProjectName-Bridging-Header.h -
Adicione o import:
#import <Singular/Singular.h> -
Vincule nas configurações de build:
Build Settings → Objective-C Bridging Header
Defina como:YourProjectName/YourProjectName-Bridging-Header.h
Configurar e inicializar o SDK
Crie um objeto de configuração e inicialize o SDK nos pontos de entrada do seu app.
Criar o objeto de configuração
Configuração básica
Crie um objeto
SingularConfig
com suas credenciais do SDK e recursos opcionais. Esta configuração é universal para todas as arquiteturas de app.
Obtenha suas credenciais: Encontre sua SDK Key e SDK Secret na plataforma Singular em Developer Tools → SDK Integration .
// MARK: - Singular Configuration
private func getConfig() -> SingularConfig? {
// Create config with your credentials
guard let config = SingularConfig(
apiKey: "YOUR_SDK_KEY",
andSecret: "YOUR_SDK_SECRET"
) else {
return nil
}
// OPTIONAL: Wait for ATT consent (if showing ATT prompt)
// Remove this line if NOT using App Tracking Transparency
config.waitForTrackingAuthorizationWithTimeoutInterval = 300
// OPTIONAL: Support custom ESP domains for deep links
config.espDomains = ["links.your-domain.com"]
// OPTIONAL: Handle deep links
config.singularLinksHandler = { params in
if let params = params {
self.handleDeeplink(params)
}
}
return config
}
// MARK: - OPTIONAL: Deep link handler implementation
private func handleDeeplink(_ params: SingularLinkParams) {
// Guard clause: Exit if no deep link provided
guard let deeplink = params.getDeepLink() else {
return
}
// Extract deep link parameters
let passthrough = params.getPassthrough()
let isDeferred = params.isDeferred()
let urlParams = params.getUrlParameters()
#if DEBUG
// Debug logging only - stripped from production builds
print("Singular Links Handler")
print("Singular deeplink received:", deeplink)
print("Singular passthrough received:", passthrough ?? "none")
print("Singular isDeferred received:", isDeferred ? "YES" : "NO")
print("Singular URL Params received:", urlParams ?? [:])
#endif
// TODO: Navigate to appropriate screen based on deep link
// Add deep link handling code here. Navigate to appropriate screen.
}
#pragma mark - Singular Configuration
- (SingularConfig *)getConfig {
// Create config with your credentials
SingularConfig *config = [[SingularConfig alloc]
initWithApiKey:@"YOUR_SDK_KEY"
andSecret:@"YOUR_SDK_SECRET"];
// OPTIONAL: Wait for ATT consent (if showing ATT prompt)
// Remove this line if NOT using App Tracking Transparency
config.waitForTrackingAuthorizationWithTimeoutInterval = 300;
// OPTIONAL: Support custom ESP domains for deep links
config.espDomains = @[@"links.your-domain.com"];
// OPTIONAL: Handle deep links
config.singularLinksHandler = ^(SingularLinkParams *params) {
[self handleDeeplink:params];
};
return config;
}
#pragma mark - OPTIONAL: Deep link handler implementation
- (void)handleDeeplink:(SingularLinkParams *)params {
// Guard clause: Exit if params is nil
if (!params) {
return;
}
// Guard clause: Exit if no deep link provided
NSString *deeplink = [params getDeepLink];
if (!deeplink) {
return;
}
// Extract deep link parameters
NSString *passthrough = [params getPassthrough];
BOOL isDeferred = [params isDeferred];
NSDictionary *urlParams = [params getUrlParameters];
#ifdef DEBUG
// Debug logging only - stripped from production builds
NSLog(@"Singular Links Handler");
NSLog(@"Singular deeplink received: %@", deeplink);
NSLog(@"Singular passthrough received: %@", passthrough);
NSLog(@"Singular isDeferred received: %@", isDeferred ? @"YES" : @"NO");
NSLog(@"Singular URL Params received: %@", urlParams);
#endif
// TODO: Navigate to appropriate screen based on deep link
// Add deep link handling code here. Navigate to appropriate screen.
}
SKAdNetwork ativado automaticamente: A partir da versão 12.0.6 do SDK, o SKAdNetwork é ativado por padrão. Nenhuma configuração adicional é necessária.
Inicializar o SDK
Escolha a arquitetura do seu app
Inicialize o SDK em todos os pontos de entrada do app. O padrão de inicialização depende da arquitetura do seu app.
Qual arquitetura eu tenho?
-
SceneDelegate:
Verifique se seu projeto tem
SceneDelegate.swiftouSceneDelegate.m -
SwiftUI:
Seu app começa com
@main struct YourApp: App - Somente AppDelegate: Apps pré-iOS 13 ou apps sem SceneDelegate
iOS moderno: SceneDelegate (iOS 13+)
Onde adicionar o código:
SceneDelegate.swift
ou
SceneDelegate.m
Pontos de entrada para inicializar:
-
willConnectTo session- Inicialização do app -
continue userActivity- Universal Links -
openURLContexts- Esquemas de deep link
import Singular
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// 1️⃣ App launch
func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
// ANTI-SWIZZLING: Capture deep link parameters IMMEDIATELY before any
// other code runs. This prevents third-party SDKs from intercepting
// or modifying these values.
let userActivity = connectionOptions.userActivities.first
let urlContext = connectionOptions.urlContexts.first
let openUrl = urlContext?.url
#if DEBUG
// Log captured values to detect swizzling interference
print("[SWIZZLE CHECK] UserActivity captured:", userActivity?.webpageURL?.absoluteString ?? "none")
print("[SWIZZLE CHECK] URL Context captured:", openUrl?.absoluteString ?? "none")
print("IDFV:", UIDevice.current.identifierForVendor?.uuidString ?? "N/A")
#endif
// Create window from windowScene
guard let windowScene = scene as? UIWindowScene else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = UIViewController() // Replace with your root VC
window?.makeKeyAndVisible()
// Singular initialization - uses captured values to avoid swizzling conflicts
guard let config = getConfig() else { return }
// Pass Universal Link if available
if let userActivity = userActivity {
config.userActivity = userActivity
}
// Pass URL scheme if available
// CRITICAL for custom URL scheme attribution
if let openUrl = openUrl {
config.openUrl = openUrl
}
// Initialize Singular SDK
Singular.start(config)
}
// 2️⃣ Universal Links
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard let config = getConfig() else { return }
config.userActivity = userActivity
// Initialize Singular SDK
Singular.start(config)
}
// 3️⃣ Deep link schemes
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let config = getConfig() else { return }
if let url = URLContexts.first?.url {
config.openUrl = url
}
// Initialize Singular SDK
Singular.start(config)
}
}
#import <Singular/Singular.h>
@implementation SceneDelegate
// 1️⃣ App launch
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session
options:(UISceneConnectionOptions *)connectionOptions {
// ANTI-SWIZZLING: Capture deep link parameters IMMEDIATELY before any
// other code runs. This prevents third-party SDKs from intercepting
// or modifying these values.
NSUserActivity *userActivity =
[[[connectionOptions userActivities]
allObjects] firstObject];
UIOpenURLContext *urlContext =
[[connectionOptions URLContexts]
allObjects].firstObject;
NSURL *openUrl = urlContext.URL;
#ifdef DEBUG
// Log captured values to detect swizzling interference
NSLog(@"[SWIZZLE CHECK] "
"UserActivity captured: %@",
userActivity.webpageURL);
NSLog(@"[SWIZZLE CHECK] "
"URL Context captured: %@",
openUrl);
#endif
// Create window from windowScene
UIWindowScene *windowScene = (UIWindowScene *)scene;
self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
self.window.rootViewController = [[UIViewController alloc] init];
[self.window makeKeyAndVisible];
#ifdef DEBUG
// Print IDFV for testing in SDK Console
NSLog(@"IDFV: %@", [[[UIDevice currentDevice] identifierForVendor] UUIDString]);
#endif
// Singular initialization - uses captured values to avoid swizzling
SingularConfig *config = [self getConfig];
// Pass Universal Link if available
if (userActivity) {
config.userActivity = userActivity;
}
// Pass URL scheme if available
// CRITICAL for custom URL scheme
if (openUrl) {
config.openUrl = openUrl;
}
// Initialize Singular SDK
[Singular start:config];
}
// 2️⃣ Universal Links
- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity {
// ANTI-SWIZZLING: Capture userActivity immediately at method entry. Called
// when Universal Link is opened while app is running or backgrounded.
NSUserActivity *capturedActivity = userActivity;
#ifdef DEBUG
NSLog(@"[SWIZZLE CHECK] "
"continueUserActivity captured: %@",
capturedActivity.webpageURL);
#endif
SingularConfig *config = [self getConfig];
config.userActivity = capturedActivity;
// Initialize Singular SDK
[Singular start:config];
}
// 3️⃣ Deep link schemes
- (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts {
// ANTI-SWIZZLING: Capture URL immediately at method entry. Called
// when URL scheme is opened while app is running or backgrounded.
NSURL *capturedUrl =
[[URLContexts allObjects]
firstObject].URL;
#ifdef DEBUG
NSLog(@"[SWIZZLE CHECK] "
"openURLContexts captured: %@",
capturedUrl);
#endif
SingularConfig *config = [self getConfig];
if (capturedUrl) {
config.openUrl = capturedUrl;
}
// Initialize Singular SDK
[Singular start:config];
}
@end
iOS moderno: App SwiftUI (iOS 14+)
Onde adicionar o código:
Seu arquivo struct
App
principal
Pontos de entrada para inicializar:
-
.onOpenURL(of: scenePhase)- Tratar esquemas de URL personalizados -
.onContinueUserActivity(of: scenePhase)- Tratar Universal Links (Singular Deep Links) -
.onChange.active- Tratar a inicialização na primeira execução se nenhum deep link tiver ocorrido. Trata Deferred Deeplinks.
import SwiftUI
import Singular
@main
struct simpleSwiftUIApp: App {
@Environment(\.scenePhase) var scenePhase
@State private var hasInitialized = false
var body: some Scene {
WindowGroup {
ContentView()
// 1️⃣ Handle custom URL schemes (e.g., myapp://path)
.onOpenURL { url in
#if DEBUG
print("[Singular] URL Scheme:", url.absoluteString)
#endif
guard let config = getConfig() else { return }
config.openUrl = url
Singular.start(config)
hasInitialized = true
}
// 2️⃣ Handle Universal Links (e.g., https://links.your-domain.com)
.onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { userActivity in
#if DEBUG
print("[Singular] Universal Link:", userActivity.webpageURL?.absoluteString ?? "none")
#endif
guard let config = getConfig() else { return }
config.userActivity = userActivity
Singular.start(config)
hasInitialized = true
}
}
.onChange(of: scenePhase) { oldPhase, newPhase in
switch newPhase {
case .active:
// 3️⃣ Initialize ONLY on first launch if no deep link occurred
guard !hasInitialized else {
#if DEBUG
print("[Singular] Already initialized, skipping")
#endif
return
}
#if DEBUG
if let idfv = UIDevice.current.identifierForVendor?.uuidString {
print("[Singular] IDFV:", idfv)
}
#endif
guard let config = getConfig() else { return }
Singular.start(config)
hasInitialized = true
case .background:
#if DEBUG
print("[Singular] App backgrounded")
#endif
case .inactive:
#if DEBUG
print("[Singular] App inactive")
#endif
@unknown default:
break
}
}
}
// Add your getConfig() function here
// MARK: - Singular Configuration
private func getConfig() -> SingularConfig? {
// ... (same as above)
}
// Add your handleDeeplink() function here
// MARK: - Deep Link Handler
private func handleDeeplink(_ params: SingularLinkParams) {
// ... (same as above)
}
}
iOS legado: AppDelegate (Pré-iOS 13)
Onde adicionar o código:
AppDelegate.swift
ou
AppDelegate.m
Pontos de entrada para inicializar:
-
didFinishLaunchingWithOptions- Inicialização do app -
continue userActivity- Universal Links -
open url- Esquemas de deep link
import Singular
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
// 1️⃣ App launch
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// ANTI-SWIZZLING: Capture deep link parameters IMMEDIATELY before any
// other code runs. This prevents third-party SDKs from intercepting
// or modifying these values.
let launchUrl = launchOptions?[.url] as? URL
let userActivityDictionary = launchOptions?[.userActivityDictionary] as? [String: Any]
let userActivity = userActivityDictionary?["UIApplicationLaunchOptionsUserActivityKey"] as? NSUserActivity
#if DEBUG
// Log captured values to detect swizzling interference
print("[SWIZZLE CHECK] Launch URL captured:", launchUrl?.absoluteString ?? "none")
print("[SWIZZLE CHECK] UserActivity captured:", userActivity?.webpageURL?.absoluteString ?? "none")
print("IDFV:", UIDevice.current.identifierForVendor?.uuidString ?? "N/A")
#endif
// Singular initialization - uses captured values to avoid swizzling conflicts
guard let config = getConfig() else { return true }
// Pass the entire launchOptions dictionary for Singular's internal processing
config.launchOptions = launchOptions
// Explicitly pass Universal Link if available
// CRITICAL for universal link attribution
if let userActivity = userActivity {
config.userActivity = userActivity
}
// Explicitly pass URL scheme if available
// CRITICAL for custom URL scheme attribution
if let launchUrl = launchUrl {
config.openUrl = launchUrl
}
// Initialize Singular SDK
Singular.start(config)
return true
}
// 2️⃣ Universal Links
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {
#if DEBUG
print("[SWIZZLE CHECK] Universal Link handler called:", userActivity.webpageURL?.absoluteString ?? "none")
#endif
guard let config = getConfig() else { return true }
config.userActivity = userActivity
Singular.start(config)
return true
}
// 3️⃣ Deep link schemes
func application(_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
#if DEBUG
print("[SWIZZLE CHECK] URL Scheme handler called:", url.absoluteString)
#endif
guard let config = getConfig() else { return true }
config.openUrl = url
Singular.start(config)
return true
}
// Add your getConfig() function here
// MARK: - Singular Configuration
private func getConfig() -> SingularConfig? {
// ... (same as above)
}
// Add your handleDeeplink() function here
// MARK: - Deep Link Handler
private func handleDeeplink(_ params: SingularLinkParams) {
// ... (same as above)
}
}
#import "AppDelegate.h"
#import <Singular/Singular.h>
@implementation AppDelegate
// 1️⃣ App launch
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ANTI-SWIZZLING: Capture deep link parameters IMMEDIATELY before any
// other code runs. This prevents third-party SDKs from intercepting
// or modifying these values.
NSURL *launchUrl = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
NSDictionary *userActivityDictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsUserActivityDictionaryKey];
NSUserActivity *userActivity = [userActivityDictionary objectForKey:@"UIApplicationLaunchOptionsUserActivityKey"];
#if DEBUG
// Log captured values to detect swizzling interference
NSLog(@"[SWIZZLE CHECK] Launch URL captured: %@", launchUrl.absoluteString ?: @"none");
NSLog(@"[SWIZZLE CHECK] UserActivity captured: %@", userActivity.webpageURL.absoluteString ?: @"none");
NSLog(@"IDFV: %@", [UIDevice currentDevice].identifierForVendor.UUIDString ?: @"N/A");
#endif
// Singular initialization - uses captured values to avoid swizzling conflicts
SingularConfig *config = [self getConfig];
if (!config) {
return YES;
}
// Pass the entire launchOptions dictionary for Singular's internal processing
config.launchOptions = launchOptions;
// Explicitly pass Universal Link if available
// CRITICAL for universal link attribution
if (userActivity) {
config.userActivity = userActivity;
}
// Explicitly pass URL scheme if available
// CRITICAL for custom URL scheme attribution
if (launchUrl) {
config.openUrl = launchUrl;
}
// Initialize Singular SDK
[Singular start:config];
return YES;
}
// 2️⃣ Universal Links
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
#if DEBUG
NSLog(@"[SWIZZLE CHECK] Universal Link handler called: %@", userActivity.webpageURL.absoluteString ?: @"none");
#endif
SingularConfig *config = [self getConfig];
if (!config) {
return YES;
}
config.userActivity = userActivity;
[Singular start:config];
return YES;
}
// 3️⃣ Deep link schemes
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
#if DEBUG
NSLog(@"[SWIZZLE CHECK] URL Scheme handler called: %@", url.absoluteString);
#endif
SingularConfig *config = [self getConfig];
if (!config) {
return YES;
}
config.openUrl = url;
[Singular start:config];
return YES;
}
#pragma mark - Singular Configuration
- (SingularConfig *)getConfig {
}
#pragma mark - OPTIONAL: Deep link handler implementation
- (void)handleDeeplink:(SingularLinkParams *)params {
}
@end
Verificar a instalação
Checklist pré-execução
Confirme estes itens antes de compilar e testar sua integração.
- SDK instalado via CocoaPods, SPM ou framework manual
- Bridging header do Swift criado (se estiver usando Swift)
-
Função
getConfig()implementada -
Singular.start(config)chamado em todos os pontos de entrada - SDK Key e SDK Secret adicionados à configuração
- Timeout do ATT configurado (somente se exibir o prompt do ATT)
- Handler de deep link configurado (somente se estiver usando deep links)
- O app compila sem erros
Próximas etapas:
- Compile e execute seu app
- Verifique no console o print do IDFV
- Teste no Singular SDK Console usando seu IDFV
- Verifique se as sessões aparecem no SDK Console em 1 a 2 minutos
Opcional: App Tracking Transparency (ATT)
Configure o ATT para solicitar permissão do usuário para acessar o IDFA e melhorar a precisão da atribuição.
Pule esta seção se: Você não estiver exibindo um prompt do ATT no seu app.
Por que solicitar o consentimento do ATT?
Benefícios do IDFA
A partir do iOS 14.5, os apps precisam solicitar permissão do usuário para acessar o IDFA (Identifier for Advertisers) do dispositivo.
Atribuição com vs. sem IDFA:
- Com IDFA: Atribuição precisa em nível de dispositivo e correspondência de instalações com precisão
- Sem IDFA: Atribuição probabilística usando IP, user agent e fingerprinting de dispositivo
Recomendação: Solicite o consentimento do ATT para obter melhor precisão de atribuição. A Singular consegue atribuir sem o IDFA, mas a precisão diminui.
Configurar o atraso do ATT
Atrasar a inicialização do SDK
Adicione um timeout para aguardar a resposta do ATT do usuário antes de enviar a primeira sessão para a Singular.
Crítico: O SDK precisa aguardar o consentimento do ATT antes de enviar a primeira sessão. Caso contrário, o evento inicial de atribuição não incluirá o IDFA.
func getSingularConfig() -> SingularConfig? {
guard let config = SingularConfig(
apiKey: "YOUR_SDK_KEY",
andSecret: "YOUR_SDK_SECRET"
) else {
return nil
}
// Wait up to 300 seconds for ATT response
config.waitForTrackingAuthorizationWithTimeoutInterval = 300
return config
}
- (SingularConfig *)getSingularConfig {
SingularConfig *config = [[SingularConfig alloc]
initWithApiKey:@"YOUR_SDK_KEY"
andSecret:@"YOUR_SDK_SECRET"];
// Wait up to 300 seconds for ATT response
config.waitForTrackingAuthorizationWithTimeoutInterval = 300;
return config;
}
Linha do tempo do fluxo ATT
Veja o que acontece quando você configura um atraso para o ATT:
- Inicialização do app: O SDK começa a registrar eventos, mas ainda não os envia
- Prompt do ATT: Seu app exibe a caixa de diálogo de consentimento do ATT
- Resposta do usuário: O usuário concede ou nega a permissão
- O SDK envia os dados: O SDK envia imediatamente os eventos enfileirados com o IDFA (se concedido)
- Fallback de timeout: Se 300 segundos se passarem sem resposta, o SDK envia os dados mesmo assim
Melhor prática: Exiba o prompt do ATT o mais cedo possível (idealmente na primeira inicialização do app) para maximizar a disponibilidade do IDFA para atribuição.