서버 간 - 디바이스 데이터 검색 가이드

디바이스 데이터 조회 가이드

정확한 S2S API 어트리뷰션 및 캠페인 측정에 필요한 플랫폼별 디바이스 식별자와 파라미터를 조회하기 위한 종합 가이드입니다.

필수 디바이스 식별자: Singular는 정확한 어트리뷰션을 위해 모든 API 요청에 특정 디바이스 식별자를 요구합니다.

모바일 플랫폼:

  • Android (Google Play): Google Advertising ID (GAID/AIFA) 및 App Set ID (ASID)
  • Android (Amazon): Fire 디바이스용 Amazon Advertising ID (AMID)
  • Android (중국 OEM): Google Play 서비스가 없는 디바이스용 Open Advertising ID (OAID)
  • Android (대체): 다른 식별자를 사용할 수 없는 경우에만 사용하는 Android ID (ANDI)
  • iOS: Identifier for Vendors (IDFV) 및 사용 가능한 경우 Identifier for Advertisers (IDFA)

디바이스 파라미터: 모바일 플랫폼에 필요한 로케일, 디바이스 제조사, 디바이스 모델, 빌드 버전

아래 코드 예시는 각 플랫폼과 식별자 유형별 조회 방법을 보여줍니다.


샘플 애플리케이션

참조 구현

디바이스 데이터 조회 패턴을 보여주는 iOS 및 Android용 완전한 작동 예제입니다.


Singular Device ID (SDID)

앱에 Singular SDK가 포함되어 있는 경우(하이브리드 연동), 플랫폼별 식별자를 수집하는 대신 SDK에서 Singular Device ID (SDID)를 가져와 sdid 파라미터로 전송하세요. SDK가 SDID를 자동으로 생성하고 확인합니다. 각 SDK에서 SDID를 가져오는 방법은 SDK 연동 가이드를 참조하세요:

디바이스에 SDK가 없는 순수 서버 간(server-to-server) 연동의 경우, 클라이언트 측에서 UUIDv4를 생성하여 SDID로 사용하거나 아래에 설명된 플랫폼별 식별자를 계속 사용하세요.


iOS 디바이스 식별자

iOS 디바이스는 정확한 어트리뷰션을 위해 IDFV(항상)와 IDFA(사용자가 추적 권한을 부여한 경우) 및 ATT 승인 상태가 필요합니다.

필수 iOS 식별자

식별자 요구사항:

  • IDFV: 추적 권한과 관계없이 모든 S2S 요청에 필수
  • IDFA: 사용자가 App Tracking Transparency 동의를 부여한 경우 제공해야 함
  • ATT 상태: 모든 요청에 필요한 권한 상태 코드(0-3)

구현 가이드

iOS 디바이스 데이터를 조회하는 방법

Identifier for Advertisers (IDFA)

Identifier for Advertisers (IDFA)는 광고주가 정확한 타겟팅과 최적화를 위해 사용자 행동(광고 클릭, 앱 설치)을 추적하고 특정 캠페인에 어트리뷰션할 수 있도록 합니다.

iOS 14.5부터는 앱이 IDFA에 접근하기 전에 사용자가 App Tracking Transparency (ATT) 프레임워크를 통해 옵트인해야 합니다. 사용자 동의가 없으면 IDFA는 모두 0을 반환하여 추적 기능이 제한됩니다.


Identifier for Vendors (IDFV)

Identifier for Vendors (IDFV)는 Apple이 디바이스에 할당하는 고유 식별자로, 벤더/개발자별로 지정됩니다. 디바이스에서 동일 벤더의 모든 앱에 걸쳐 일관되게 유지되어 개인 식별 없이 앱 간 행동 추적을 가능하게 합니다.

구현 단계:

  • IDFA 접근을 시도하기 전에 ATT 프롬프트가 표시되고 처리되었는지 확인하세요
  • IDFA(권한이 부여된 경우)를 캡처하여 API 요청을 위해 서버로 전달하세요
  • IDFV를 캡처하여 API 요청을 위해 서버로 전달하세요(항상 필수)
  • 모든 요청에 ATT 승인 상태를 포함하세요

코드 예제

ATT 승인 요청 및 IDFA/IDFV 가져오기

OBJECTIVE-C SWIFT
#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];

식별자 사용 가능 여부:

  • IDFA: iOS 14.5 이상에서 ATT 승인이 필요합니다. 동의가 없으면 모두 0을 반환합니다
  • IDFV: 항상 사용 가능—모든 Singular API 요청에 포함하세요
  • ATT 상태 값: 0=미결정, 1=제한됨, 2=거부됨, 3=승인됨

Android 디바이스 식별자 (Google Play)

Google Play 서비스가 있는 Android 디바이스는 모든 요청에 App Set ID (ASID)가 필요하며, 사용 가능한 경우 Google Advertising ID (GAID/AIFA)가 필요합니다.

필수 Google Play 식별자

식별자 요구사항:

  • ASID: Google Play 디바이스에 대한 모든 S2S 요청에 필수
  • AIFA/GAID: 사용 가능한 경우(옵트아웃하지 않은 경우) 제공해야 함

구현 가이드

Android 디바이스 데이터를 조회하는 방법 (Google Play)

Google Advertising Identifier (GAID)

AIFA 또는 Android Advertising ID (AAID)라고도 하는 Google Advertising Identifier (GAID)는 Android 디바이스에 할당된 고유하고 사용자가 재설정할 수 있는 식별자입니다. 광고주와 개발자가 프라이버시를 유지하면서 캠페인 타겟팅과 최적화를 위해 앱 전반에 걸쳐 사용자 행동을 추적하고 어트리뷰션할 수 있도록 합니다.

JAVA KOTLIN

종속성

다음 필수 종속성을 build.gradle 에 추가하세요:

dependencies {
    implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
}

권한

Android 12/API 레벨 31 이상을 타겟팅하는 경우, AndroidManifest.xml 에 권한을 추가하세요:

<uses-permission android:name="com.google.android.gms.permission.AD_ID" />

사용법

AdIdUtils.getGoogleAdId(getApplicationContext());

구현

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);
                }
            }
        });
    }
}

App Set ID (ASID)

Android App Set ID는 동일 개발자를 위한 프라이버시를 고려한 앱 간 추적을 제공합니다. 분석 및 부정행위 방지에는 유용하지만 개인화된 광고에는 사용할 수 없습니다.

JAVA KOTLIN

종속성

dependencies {
    implementation 'com.google.android.gms:play-services-appset:16.1.0'
}

사용법

AppSetIdUtils.getAppSetId(getApplicationContext());

구현

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);
        });
    }
}

Android 디바이스 식별자 (Google Play 미지원)

Google Play 서비스가 없는 Android 디바이스는 디바이스 제조사와 배포 방식에 따라 대체 식별자가 필요합니다.

Amazon 디바이스 식별자

AMID: Google Play 서비스가 없는 Amazon Fire 디바이스의 경우 Amazon Advertising ID를 제공해야 합니다.

Amazon Advertising ID (AMID)를 조회하는 방법

Amazon ID (AMID)

Amazon Advertising Identifier 는 Google Play 서비스가 없는 Amazon Fire 디바이스에서 사용자가 재설정할 수 있는 광고 추적을 가능하게 하여, 사용자 프라이버시를 유지하면서 어트리뷰션을 활성화합니다.

요구사항:

  • Fire OS 5.1 이상을 실행하는 Amazon Fire 디바이스에서 작동합니다
  • 사용자의 광고 추적 제한 설정을 준수합니다
  • Fire OS가 아닌 디바이스에서는 사용할 수 없을 수 있습니다
JAVA KOTLIN

사용법

AdvertisingIdHelper.getAmazonAdvertisingId(getContentResolver());

구현

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);
        }
    }
}

중국 OEM 식별자

OAID: Google Play 서비스가 없는 중국산 디바이스의 경우 Open Advertising Identifier를 제공해야 합니다.

Open Advertising ID (OAID)를 조회하는 방법

Open Advertising ID (OAID)

Open Advertising Identifier (OAID)는 중국에서 제조된 Android 디바이스에서 광고를 위한 고유하고 익명의 식별자입니다. Google Play 서비스를 사용할 수 없는 디바이스를 위한 GAID의 대안으로 Mobile Security Alliance (MSA)에서 도입했습니다.

지원 디바이스: Huawei, Xiaomi, OPPO, Vivo 및 기타 중국산 Android 디바이스

MSA SDK 또는 Huawei Mobile Services (HMS)를 통해 접근합니다.

JAVA KOTLIN

종속성

dependencies {
    implementation 'com.bun.msa.sdk:msa:1.0.26'
}

구현

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);
        }
    }
}

Android ID 폴백

ANDI 제한사항: Android ID는 다른 식별자를 사용할 수 없고 앱이 Google Play Store를 통해 배포되지 않는 경우에만 제공할 수 있습니다. Google Play 앱에는 금지됩니다.

Android ID (ANDI)를 조회하는 방법

Android ID (ANDI)

Android ID는 디바이스가 처음 설정될 때 생성되는 고유한 64비트 식별자입니다. Android 8.0 (Oreo)부터는 앱별, 사용자별로 범위가 지정되어—동일한 서명 키를 공유하지 않는 한 서로 다른 앱은 서로 다른 Android ID를 받습니다.

지속성: 디바이스를 공장 초기화하거나 OTA 업데이트 후 앱을 삭제/재설치하지 않는 한 일정하게 유지됩니다.

JAVA KOTLIN
import android.provider.Settings;
import android.content.Context;

String androidId = Settings.Secure.getString(
    context.getContentResolver(),
    Settings.Secure.ANDROID_ID
);

웹 & 크로스 플랫폼 식별자

웹 애플리케이션과 크로스 플랫폼 구현에는 정확한 어트리뷰션 추적을 위해 Singular Device ID (SDID)가 필요합니다.

필수 웹 식별자

SDID: 웹, PC, 콘솔, CTV 플랫폼에 대한 모든 S2S 요청에 필요한 Singular Device ID입니다.

Singular Device ID (SDID)를 조회하는 방법

Singular Web SDK Device ID

Singular Device ID (SDID)는 웹 애플리케이션과 비모바일 플랫폼에 대해 일관된 크로스 세션 추적을 제공합니다.

전제 조건: SDID를 조회하기 전에 Singular Web SDK가 구현되고 초기화되어야 합니다.

사용법

// Retrieve SDID after Singular SDK initialization
const sdid = window.singularSdk.getSingularDeviceId();
console.log("Singular Device ID:", sdid);

구현 참고: Singular SDK가 성공적으로 초기화된 후에만 getSingularDeviceId() 를 호출하세요—초기화 전에 조회를 시도하면 null이 반환됩니다.


모바일 디바이스 파라미터

필수 디바이스 파라미터는 모바일 플랫폼에서 어트리뷰션과 분석을 위한 필수적인 컨텍스트를 제공합니다.

필수 파라미터

모바일 플랫폼: 로케일, 디바이스 제조사, 디바이스 모델, 빌드는 iOS 및 Android에 대한 모든 S2S 요청에 필수입니다.

디바이스 파라미터를 조회하는 방법

파라미터 조회

완전한 디바이스 프로파일링을 위해 로케일, 제조사, 모델, 빌드 정보를 수집하세요.

OBJECTIVE-C SWIFT JAVA KOTLIN
#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;
    }
}

파라미터 매핑:

  • Locale (lc): 언어 및 지역 코드(예: en_US, zh_CN)
  • Make (ma): 디바이스 제조사(Apple, Samsung, Xiaomi)
  • Model (mo): 특정 디바이스 모델(iPhone14,2, SM-G991B)
  • Build (bd): "Build/" 접두사가 붙은 OS 빌드 버전

타임스탬프 파라미터

선택적 타임스탬프 파라미터는 디바이스의 설치 및 업데이트 상태를 설명합니다. 이 값들은 OS가 보고하는 값으로, 디바이스에서 수집되어 SESSION 요청 시 전송됩니다.

install_time을 조회하는 방법

install_time 조회

install_time 은 앱이 디바이스에 물리적으로 설치된 시점의 OS 보고 Unix 타임스탬프(초)입니다. Android에서는 PackageInfo.firstInstallTime (밀리초)을 읽어 1000으로 나눕니다. iOS는 설치 시간 API를 제공하지 않으므로, 표준적인 근사값으로 앱의 Documents 디렉터리 생성 날짜를 사용합니다.

OBJECTIVE-C SWIFT JAVA KOTLIN
#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);

이것은 디바이스 설치 시간이며 Singular의 어트리뷰션 설치 시간이 아닙니다. 어트리뷰션은 첫 세션( install=true )의 세션 타임스탬프( utime )를 사용합니다.

update_time을 조회하는 방법

update_time 조회

update_time 은 앱이 디바이스에서 마지막으로 업데이트된 시점의 OS 보고 Unix 타임스탬프(초)입니다. Android에서는 PackageInfo.lastUpdateTime (밀리초)을 읽어 1000으로 나눕니다. iOS는 업데이트 시간 API를 제공하지 않으므로, 표준적인 근사값으로 각 업데이트마다 다시 기록되는 앱 번들 실행 파일의 생성 날짜를 사용합니다.

OBJECTIVE-C SWIFT JAVA KOTLIN
#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);

앱이 한 번도 업데이트되지 않은 디바이스에서는 이 값이 install_time 과 같습니다. 이는 어트리뷰션 활동이 아닌 앱 업데이트를 반영합니다.