Guía de obtención de datos del dispositivo
Guía completa para obtener los identificadores y parámetros del dispositivo específicos de la plataforma necesarios para una atribución precisa con la API S2S y la medición de campañas.
Identificadores del dispositivo obligatorios: Singular requiere identificadores del dispositivo específicos en todas las solicitudes de la API para una atribución precisa.
Plataformas móviles:
- Android (Google Play): Google Advertising ID (GAID/AIFA) y App Set ID (ASID)
- Android (Amazon): Amazon Advertising ID (AMID) para dispositivos Fire
- Android (OEM chinos): Open Advertising ID (OAID) para dispositivos sin Google Play Services
- Android (alternativa): Android ID (ANDI) solo cuando no hay otros identificadores disponibles
- iOS: Identifier for Vendors (IDFV) e Identifier for Advertisers (IDFA) cuando esté disponible
Parámetros del dispositivo: Configuración regional (locale), marca del dispositivo, modelo del dispositivo y versión de compilación (build) obligatorios para las plataformas móviles
Los ejemplos de código a continuación muestran los métodos de obtención para cada plataforma y tipo de identificador.
Aplicaciones de ejemplo
Implementaciones de referencia
Ejemplos completos y funcionales para iOS y Android que muestran los patrones de obtención de datos del dispositivo.
Singular Device ID (SDID)
Si tu app incluye un SDK de Singular (una integración híbrida), obtén el Singular Device ID (SDID) del SDK y envíalo como el parámetro
sdid
en lugar de recopilar identificadores específicos de la plataforma. El SDK genera y resuelve el SDID automáticamente. Para saber cómo obtener el SDID en cada SDK, consulta la guía de integración del SDK:
- SDK de iOS
- SDK de Android
- SDK de Unity
- SDK de Flutter
- SDK de React Native
- SDK de Cordova
- SDK de Unreal Engine
Para integraciones server-to-server puras sin SDK en el dispositivo, genera un UUIDv4 del lado del cliente para usarlo como SDID, o sigue usando los identificadores específicos de la plataforma documentados a continuación.
Identificadores del dispositivo iOS
Los dispositivos iOS requieren el IDFV (siempre) y el IDFA (cuando el usuario concede el permiso de seguimiento), además del estado de autorización de ATT, para una atribución precisa.
Identificadores obligatorios de iOS
Requisitos de los identificadores:
- IDFV: Obligatorio en todas las solicitudes S2S, independientemente del permiso de seguimiento
- IDFA: Debe proporcionarse si el usuario concedió el consentimiento de App Tracking Transparency
- Estado de ATT: Código de estado de autorización obligatorio en todas las solicitudes (0-3)
Guía de implementación
Identifier for Advertisers (IDFA)
El Identifier for Advertisers (IDFA) permite a los anunciantes rastrear y atribuir las acciones de los usuarios (clics en anuncios, instalaciones de apps) a campañas específicas para una segmentación y optimización precisas.
A partir de iOS 14.5, los usuarios deben dar su consentimiento a través del framework App Tracking Transparency (ATT) antes de que las apps accedan al IDFA. Sin el consentimiento del usuario, el IDFA devuelve solo ceros, lo que limita las funciones de seguimiento.
Identifier for Vendors (IDFV)
El Identifier for Vendors (IDFV) es un identificador único asignado por Apple al dispositivo, específico para cada proveedor/desarrollador. Se mantiene constante en todas las apps del mismo proveedor en el dispositivo, lo que permite el seguimiento del comportamiento entre apps sin identificación personal.
Pasos de implementación:
- Asegúrate de que la solicitud de ATT se muestre y se gestione antes de intentar acceder al IDFA
- Captura el IDFA (si está autorizado) y envíalo al servidor para las solicitudes de la API
- Captura el IDFV y envíalo al servidor para las solicitudes de la API (siempre obligatorio)
- Incluye el estado de autorización de ATT en todas las solicitudes
Ejemplos de código
Solicitar la autorización de ATT y obtener el IDFA/IDFV
#import <AdSupport/AdSupport.h>
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import <UIKit/UIKit.h>
- (void)retrieveIdentifiers {
// Request ATT authorization (iOS 14.5+)
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
dispatch_async(dispatch_get_main_queue(), ^{
switch (status) {
case ATTrackingManagerAuthorizationStatusAuthorized: {
// ATT authorized, retrieve IDFA
NSUUID *idfa = [[ASIdentifierManager sharedManager] advertisingIdentifier];
NSLog(@"IDFA: %@", [idfa UUIDString]);
NSLog(@"ATT Status: %ld", (long)status); // Status = 3
break;
}
case ATTrackingManagerAuthorizationStatusDenied:
NSLog(@"ATT Status: Denied (%ld)", (long)status); // Status = 2
break;
case ATTrackingManagerAuthorizationStatusRestricted:
NSLog(@"ATT Status: Restricted (%ld)", (long)status); // Status = 1
break;
case ATTrackingManagerAuthorizationStatusNotDetermined:
NSLog(@"ATT Status: Not Determined (%ld)", (long)status); // Status = 0
break;
default:
NSLog(@"Unknown ATT status.");
break;
}
// Retrieve IDFV (always available)
NSUUID *idfv = [[UIDevice currentDevice] identifierForVendor];
if (idfv != nil) {
NSLog(@"IDFV: %@", [idfv UUIDString]);
} else {
NSLog(@"Unable to retrieve IDFV.");
}
});
}];
}
// Call the method to retrieve identifiers
[self retrieveIdentifiers];
import AdSupport
import AppTrackingTransparency
import UIKit
func retrieveIdentifiers() {
// Request ATT authorization (iOS 14.5+)
ATTrackingManager.requestTrackingAuthorization { status in
DispatchQueue.main.async {
switch status {
case .authorized:
// ATT authorized, retrieve IDFA
let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
print("IDFA: \(idfa)")
print("ATT Status: \(status.rawValue)") // Status = 3
case .denied:
print("ATT Status: Denied (\(status.rawValue))") // Status = 2
case .restricted:
print("ATT Status: Restricted (\(status.rawValue))") // Status = 1
case .notDetermined:
print("ATT Status: Not Determined (\(status.rawValue))") // Status = 0
@unknown default:
print("Unknown ATT status.")
}
// Retrieve IDFV (always available)
if let idfv = UIDevice.current.identifierForVendor?.uuidString {
print("IDFV: \(idfv)")
} else {
print("Unable to retrieve IDFV.")
}
}
}
}
// Call the function to retrieve identifiers
retrieveIdentifiers()
Disponibilidad de los identificadores:
- IDFA: Requiere la autorización de ATT a partir de iOS 14.5. Sin consentimiento, devuelve solo ceros
- IDFV: Siempre disponible; inclúyelo en todas las solicitudes de la API de Singular
- Valores de estado de ATT: 0=Sin determinar, 1=Restringido, 2=Denegado, 3=Autorizado
Identificadores del dispositivo Android (Google Play)
Los dispositivos Android con Google Play Services requieren el App Set ID (ASID) en todas las solicitudes, junto con el Google Advertising ID (GAID/AIFA) cuando esté disponible.
Identificadores obligatorios de Google Play
Requisitos de los identificadores:
- ASID: Obligatorio en todas las solicitudes S2S para dispositivos con Google Play
- AIFA/GAID: Debe proporcionarse cuando esté disponible (si el usuario no lo ha desactivado)
Guía de implementación
Google Advertising Identifier (GAID)
El Google Advertising Identifier (GAID), también conocido como AIFA o Android Advertising ID (AAID), es un identificador único que el usuario puede restablecer y que se asigna a los dispositivos Android. Permite a los anunciantes y desarrolladores rastrear y atribuir las acciones de los usuarios entre apps para la segmentación y optimización de campañas, manteniendo la privacidad.
Dependencias
Agrega la dependencia necesaria en tu
build.gradle
:
dependencies {
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
}
Permisos
Si tu objetivo es Android 12/nivel de API 31 o superior, agrega el permiso
en
AndroidManifest.xml
:
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
Uso
AdIdUtils.getGoogleAdId(getApplicationContext());
Implementación
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
public class AdIdUtils {
public static void getGoogleAdId(Context context) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
try {
Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context);
String adId = adInfo.getId();
boolean isLimitAdTrackingEnabled = adInfo.isLimitAdTrackingEnabled();
Log.d("GoogleAdID", "Advertising ID: " + adId);
Log.d("GoogleAdID", "Limit Ad Tracking: " + isLimitAdTrackingEnabled);
} catch (Exception e) {
Log.e("GoogleAdID", "Error retrieving GAID", e);
}
}
});
}
}
Dependencias
dependencies {
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
}
Permisos
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
Uso
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
lifecycleScope.launch {
val googleAdId = AdIdUtils.getGoogleAdId(applicationContext)
Log.d("MainActivity", "Retrieved Google Ad ID: $googleAdId")
}
}
}
Implementación
import android.content.Context
import android.util.Log
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
object AdIdUtils {
suspend fun getGoogleAdId(context: Context): String? {
return withContext(Dispatchers.IO) {
try {
val adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context)
val adId = adInfo.id
val isLimitAdTrackingEnabled = adInfo.isLimitAdTrackingEnabled
Log.d("GoogleAdID", "Advertising ID: $adId")
Log.d("GoogleAdID", "Limit Ad Tracking: $isLimitAdTrackingEnabled")
adId
} catch (e: Exception) {
Log.e("GoogleAdID", "Error retrieving GAID", e)
null
}
}
}
}
App Set ID (ASID)
El App Set ID de Android proporciona un seguimiento entre apps respetuoso con la privacidad para el mismo desarrollador. Es útil para el análisis y la prevención de fraude, pero no puede usarse para publicidad personalizada.
Dependencias
dependencies {
implementation 'com.google.android.gms:play-services-appset:16.1.0'
}
Uso
AppSetIdUtils.getAppSetId(getApplicationContext());
Implementación
import android.content.Context;
import android.util.Log;
import com.google.android.gms.appset.AppSet;
import com.google.android.gms.appset.AppSetIdClient;
import com.google.android.gms.appset.AppSetIdInfo;
import com.google.android.gms.tasks.Task;
public class AppSetIdUtils {
public static void getAppSetId(Context context) {
AppSetIdClient client = AppSet.getClient(context);
Task task = client.getAppSetIdInfo();
task.addOnSuccessListener(info - {
String appSetId = info.getId();
int scope = info.getScope();
Log.d("AppSetID", "App Set ID: " + appSetId);
Log.d("AppSetID", "Scope: " + (scope == AppSetIdInfo.SCOPE_DEVELOPER ? "Developer" : "App"));
}).addOnFailureListener(e - {
Log.e("AppSetID", "Failed to retrieve App Set ID", e);
});
}
}
Dependencias
dependencies {
implementation 'com.google.android.gms:play-services-appset:16.1.0'
}
Uso
AppSetIdUtils.getAppSetId(applicationContext)
Implementación
import android.content.Context
import android.util.Log
import com.google.android.gms.appset.AppSet
import com.google.android.gms.appset.AppSetIdClient
import com.google.android.gms.appset.AppSetIdInfo
object AppSetIdUtils {
fun getAppSetId(context: Context) {
val client: AppSetIdClient = AppSet.getClient(context)
val task = client.appSetIdInfo
task.addOnSuccessListener { info -
val appSetId: String = info.id
val scope: Int = info.scope
Log.d("AppSetID", "App Set ID: $appSetId")
Log.d("AppSetID", "Scope: ${if (scope == AppSetIdInfo.SCOPE_DEVELOPER) "Developer" else "App"}")
}.addOnFailureListener { exception -
Log.e("AppSetID", "Failed to retrieve App Set ID", exception)
}
}
}
Identificadores del dispositivo Android (sin Google Play)
Los dispositivos Android sin Google Play Services requieren identificadores alternativos según el fabricante del dispositivo y el método de distribución.
Identificador de dispositivos Amazon
AMID: El Amazon Advertising ID debe proporcionarse para dispositivos Amazon Fire sin Google Play Services.
Amazon ID (AMID)
Amazon Advertising Identifier permite el seguimiento publicitario que el usuario puede restablecer en dispositivos Amazon Fire sin Google Play Services, manteniendo la privacidad del usuario y habilitando la atribución.
Requisitos:
- Funciona en dispositivos Amazon Fire con Fire OS 5.1 o superior
- Respeta la preferencia de Limit Ad Tracking del usuario
- Es posible que no esté disponible en dispositivos que no sean Fire OS
Uso
AdvertisingIdHelper.getAmazonAdvertisingId(getContentResolver());
Implementación
import android.content.ContentResolver;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
public class AdvertisingIdHelper {
public static void getAmazonAdvertisingId(ContentResolver contentResolver) {
String advertisingID = "";
boolean limitAdTracking = false;
try {
limitAdTracking = Settings.Secure.getInt(contentResolver, "limit_ad_tracking") != 0;
advertisingID = Settings.Secure.getString(contentResolver, "advertising_id");
Log.d("AdvertisingID", "Amazon Advertising ID: " + advertisingID);
Log.d("LimitAdTracking", "Limit Ad Tracking: " + limitAdTracking);
} catch (SettingNotFoundException e) {
Log.e("AdvertisingID", "Advertising ID not supported on this device", e);
}
}
}
Uso
AdvertisingIdHelper.getAmazonAdvertisingId(contentResolver)
Implementación
import android.content.ContentResolver
import android.provider.Settings
import android.util.Log
object AdvertisingIdHelper {
fun getAmazonAdvertisingId(contentResolver: ContentResolver) {
try {
val limitAdTracking = Settings.Secure.getInt(contentResolver, "limit_ad_tracking") != 0
val advertisingID = Settings.Secure.getString(contentResolver, "advertising_id")
Log.d("AdvertisingID", "Amazon Advertising ID: $advertisingID")
Log.d("LimitAdTracking", "Limit Ad Tracking: $limitAdTracking")
} catch (e: Settings.SettingNotFoundException) {
Log.e("AdvertisingID", "Advertising ID not supported on this device", e)
}
}
}
Identificador de OEM chinos
OAID: El Open Advertising Identifier debe proporcionarse para dispositivos fabricados en China sin Google Play Services.
Open Advertising ID (OAID)
El Open Advertising Identifier (OAID) es un identificador único y anónimo para publicidad en dispositivos Android fabricados en China. Introducido por la Mobile Security Alliance (MSA) como alternativa al GAID para dispositivos donde Google Play Services no está disponible.
Dispositivos compatibles: Huawei, Xiaomi, OPPO, Vivo y otros dispositivos Android fabricados en China
Accede a través del MSA SDK o de Huawei Mobile Services (HMS).
Dependencias
dependencies {
implementation 'com.bun.msa.sdk:msa:1.0.26'
}
Implementación
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import com.bun.msa.sdk.DeviceId;
import com.bun.msa.sdk.DeviceIdSupplier;
import com.bun.msa.sdk.IIdentifierListener;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "OAIDExample";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getOAID();
}
private void getOAID() {
try {
DeviceId deviceId = new DeviceId(this);
deviceId.getDeviceIds(new IIdentifierListener() {
@Override
public void onSupport(boolean isSupport, DeviceIdSupplier supplier) {
if (isSupport && supplier != null) {
String oaid = supplier.getOAID();
Log.d(TAG, "OAID: " + oaid);
} else {
Log.e(TAG, "OAID not supported on this device");
}
}
});
} catch (Exception e) {
Log.e(TAG, "Error retrieving OAID", e);
}
}
}
Dependencias
dependencies {
implementation 'com.bun.msa.sdk:msa:1.0.26'
}
Implementación
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.bun.msa.sdk.DeviceId
import com.bun.msa.sdk.DeviceIdSupplier
import com.bun.msa.sdk.IIdentifierListener
class MainActivity : AppCompatActivity() {
companion object {
private const val TAG = "OAIDExample"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
getOAID()
}
private fun getOAID() {
try {
val deviceId = DeviceId(this)
deviceId.getDeviceIds(object : IIdentifierListener {
override fun onSupport(isSupport: Boolean, supplier: DeviceIdSupplier?) {
if (isSupport && supplier != null) {
val oaid = supplier.oAID
Log.d(TAG, "OAID: $oaid")
} else {
Log.e(TAG, "OAID not supported on this device")
}
}
})
} catch (e: Exception) {
Log.e(TAG, "Error retrieving OAID", e)
}
}
}
Alternativa de Android ID
Restricciones de ANDI: El Android ID solo puede proporcionarse si no hay otros identificadores disponibles Y la app no se distribuye a través de Google Play Store. Está prohibido para apps de Google Play.
Android ID (ANDI)
El Android ID es un identificador único de 64 bits que se genera cuando el dispositivo se configura por primera vez. A partir de Android 8.0 (Oreo), tiene un alcance por app y por usuario: diferentes apps reciben diferentes Android ID a menos que compartan la misma clave de firma.
Persistencia: Se mantiene constante a menos que se restablezca el dispositivo a los valores de fábrica o se desinstale/reinstale la app después de una actualización OTA.
import android.provider.Settings;
import android.content.Context;
String androidId = Settings.Secure.getString(
context.getContentResolver(),
Settings.Secure.ANDROID_ID
);
import android.provider.Settings
val androidId: String = Settings.Secure.getString(
contentResolver,
Settings.Secure.ANDROID_ID
)
Identificadores web y multiplataforma
Las aplicaciones web y las implementaciones multiplataforma requieren el Singular Device ID (SDID) para un seguimiento de atribución preciso.
Identificador web obligatorio
SDID: El Singular Device ID es obligatorio en todas las solicitudes S2S para las plataformas web, PC, consola y CTV.
ID de dispositivo del Singular Web SDK
El Singular Device ID (SDID) proporciona un seguimiento coherente entre sesiones para aplicaciones web y plataformas no móviles.
Requisitos previos: El Singular Web SDK debe estar implementado e inicializado antes de obtener el SDID.
Uso
// Retrieve SDID after Singular SDK initialization
const sdid = window.singularSdk.getSingularDeviceId();
console.log("Singular Device ID:", sdid);
Nota de implementación:
Llama a
getSingularDeviceId()
solo después de que el SDK de Singular se haya inicializado correctamente; intentar obtenerlo
antes de la
inicialización devuelve null.
Parámetros del dispositivo móvil
Los parámetros del dispositivo obligatorios proporcionan el contexto esencial para la atribución y el análisis en plataformas móviles.
Parámetros obligatorios
Plataformas móviles: La configuración regional (locale), la marca del dispositivo, el modelo del dispositivo y la compilación (build) son obligatorios en todas las solicitudes S2S para iOS y Android.
Obtención de parámetros
Recopila la información de configuración regional, fabricante, modelo y compilación para un perfil completo del dispositivo.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <sys/sysctl.h>
// Retrieve Locale
NSString *retrieveLocale() {
NSString *locale = [[NSLocale currentLocale] localeIdentifier];
NSLog(@"Locale: %@", locale);
return locale;
}
// Retrieve Manufacturer (always Apple for iOS)
NSString *retrieveManufacturer() {
return @"Apple";
}
// Retrieve Device Model
NSString *deviceModel() {
size_t bufferSize = 64;
char model[bufferSize];
int status = sysctlbyname("hw.machine", model, &bufferSize, NULL, 0);
if (status == 0) {
NSString *deviceModel = [NSString stringWithCString:model encoding:NSUTF8StringEncoding];
NSLog(@"Device Model: %@", deviceModel);
return deviceModel;
} else {
NSLog(@"Unable to retrieve device model.");
return nil;
}
}
// Retrieve Build Version
NSString *buildVersion() {
size_t bufferSize = 64;
char build[bufferSize];
int status = sysctlbyname("kern.osversion", build, &bufferSize, NULL, 0);
if (status == 0) {
NSString *buildVersion = [NSString stringWithCString:build encoding:NSUTF8StringEncoding];
NSLog(@"Build Version: %@", buildVersion);
return buildVersion;
} else {
NSLog(@"Unable to retrieve build version.");
return nil;
}
}
import Foundation
import UIKit
// Retrieve Locale
func retrieveLocale() - String {
let locale = Locale.current.identifier
print("Locale: \(locale)")
return locale
}
// Retrieve Manufacturer (always Apple for iOS)
func retrieveManufacturer() - String {
return "Apple"
}
// Retrieve Device Model
func deviceModel() - String? {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
print("Device Model: \(identifier)")
return identifier
}
// Retrieve Build Version
func buildVersion() - String? {
var size: Int = 0
sysctlbyname("kern.osversion", nil, &size, nil, 0)
var build = [CChar](repeating: 0, count: size)
sysctlbyname("kern.osversion", &build, &size, nil, 0)
let buildVersion = String(cString: build)
print("Build Version: \(buildVersion)")
return buildVersion
}
import android.os.Build;
import java.util.Locale;
// Locale (lc parameter)
String locale = Locale.getDefault().toString();
// Device Make (ma parameter)
String deviceMake = Build.MANUFACTURER;
// Device Model (mo parameter)
String deviceModel = Build.MODEL;
// Build (bd parameter)
String build = "Build/" + Build.ID;
import android.os.Build
import java.util.Locale
// Locale (lc parameter)
val locale: String = Locale.getDefault().toString()
// Device Make (ma parameter)
val deviceMake: String = Build.MANUFACTURER
// Device Model (mo parameter)
val deviceModel: String = Build.MODEL
// Build (bd parameter)
val build: String = "Build/" + Build.ID
Asignación de parámetros:
- Configuración regional (lc): Código de idioma y región (por ejemplo, en_US, zh_CN)
- Marca (ma): Fabricante del dispositivo (Apple, Samsung, Xiaomi)
- Modelo (mo): Modelo específico del dispositivo (iPhone14,2, SM-G991B)
- Compilación (bd): Versión de compilación del SO precedida por "Build/"
Parámetros de marca de tiempo
Los parámetros opcionales de marca de tiempo describen el estado de instalación y actualización del dispositivo. Estos son valores informados por el SO, recopilados en el dispositivo y enviados en la solicitud SESSION.
Obtención de install_time
install_time
es la marca de tiempo Unix (en segundos) informada por el SO de cuándo se instaló
físicamente la app en el dispositivo. En Android, lee
PackageInfo.firstInstallTime
(en milisegundos) y divídelo entre 1000. iOS no expone ninguna API de hora de instalación, así que
usa la fecha de creación del directorio Documents de la app como
aproximación estándar.
#import <Foundation/Foundation.h>
// install_time: creation date of the Documents directory (proxy)
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *docs = [[fm URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] firstObject];
NSDictionary *attrs = [fm attributesOfItemAtPath:docs.path error:nil];
NSDate *created = attrs[NSFileCreationDate];
long installTime = (long)[created timeIntervalSince1970];
NSLog(@"install_time: %ld", installTime);
import Foundation
// install_time: creation date of the Documents directory (proxy)
let docs = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask).first!
let attrs = try? FileManager.default.attributesOfItem(atPath: docs.path)
let created = attrs?[.creationDate] as? Date
let installTime = created.map { Int($0.timeIntervalSince1970) }
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
// install_time: PackageInfo.firstInstallTime is in milliseconds
long installTime = 0L;
try {
PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0);
installTime = info.firstInstallTime / 1000L; // seconds
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
import android.content.pm.PackageManager
// install_time: PackageInfo.firstInstallTime is in milliseconds
val installMillis = packageManager
.getPackageInfo(packageName, 0)
.firstInstallTime
val installTime = installMillis / 1000 // seconds
Esta es la hora de instalación del dispositivo, no la hora de instalación de la atribución
de Singular. La atribución usa la marca de tiempo de la sesión (
utime
) de la primera sesión (
install=true
).
Obtención de update_time
update_time
es la marca de tiempo Unix (en segundos) informada por el SO de cuándo se actualizó
por última vez la app en el dispositivo. En Android, lee
PackageInfo.lastUpdateTime
(en milisegundos) y divídelo entre 1000. iOS no expone ninguna API de hora de actualización, así que
usa la fecha de creación del ejecutable del paquete (bundle) de la app, que se
reescribe en cada actualización, como aproximación estándar.
#import <Foundation/Foundation.h>
// update_time: creation date of the app bundle executable (proxy)
NSString *execPath = [[NSBundle mainBundle] executablePath];
NSDictionary *attrs = [[NSFileManager defaultManager]
attributesOfItemAtPath:execPath error:nil];
NSDate *updated = attrs[NSFileCreationDate];
long updateTime = (long)[updated timeIntervalSince1970];
NSLog(@"update_time: %ld", updateTime);
import Foundation
// update_time: creation date of the app bundle executable (proxy)
let execPath = Bundle.main.executablePath!
let attrs = try? FileManager.default.attributesOfItem(atPath: execPath)
let updated = attrs?[.creationDate] as? Date
let updateTime = updated.map { Int($0.timeIntervalSince1970) }
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
// update_time: PackageInfo.lastUpdateTime is in milliseconds
long updateTime = 0L;
try {
PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0);
updateTime = info.lastUpdateTime / 1000L; // seconds
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
import android.content.pm.PackageManager
// update_time: PackageInfo.lastUpdateTime is in milliseconds
val updateMillis = packageManager
.getPackageInfo(packageName, 0)
.lastUpdateTime
val updateTime = updateMillis / 1000 // seconds
En un dispositivo donde la app nunca se ha actualizado, esto es igual a
install_time
. Refleja las actualizaciones de la app, no la actividad de atribución.