광고 식별자 변경: Android 13 이상에서 Google GAID를 가져오는 방법

opoinstall
2026-08-24
5 min read

GAID란 무엇이며 프로그래밍 방식으로 어떻게 가져올 수 있나요? GAID(Google Advertising ID)는 광고 측정 및 분석을 위해 Google Play 서비스에서 제공하는 사용자가 재설정할 수 있는 소프트웨어 식별자입니다. 병합된 앱 매니페스트에 필요한 AD_ID 권한이 포함되어 있는지 확인한 후, AdvertisingIdClient API를 사용하여 메인 스레드가 아닌 백그라운드에서 프로그래밍 방식으로 가져옵니다.

AAID(Android Advertising ID)라고도 하는 GAID(Google Advertising ID)는 Android 기기에서의 광고 어트리뷰션, 맞춤형 광고 타겟팅 및 분석을 위해 Google Play 서비스에서 제공하는 사용자가 재설정할 수 있는 고유한 문자열입니다. Android 13(API 수준 33) 이상을 타겟팅하는 앱은 Google Play 서비스 광고 식별자에 액세스할 때 병합된 매니페스트에 com.google.android.gms.permission.AD_ID 권한이 포함되어 있는지 확인해야 합니다. 그렇지 않으면 API가 모두 0으로 채워진 값을 반환합니다.

용어 정의
GAID 광고 측정을 위해 Google Play 서비스에서 제공하는 Google 광고 식별자입니다.
AdvertisingIdClient 광고 식별자 메타데이터를 쿼리하는 데 사용되는 Google Play 서비스 API입니다.
AD_ID 권한 Google Play 서비스 광고 식별자에 액세스할 때 API 수준 33 이상을 타겟팅하는 앱에 필요한 Android 매니페스트 권한입니다.
0값 식별자 광고 식별자를 사용할 수 없거나 거부되었을 때 반환되는 모두 0으로 채워진 센티넬 값(00000000-0000-0000-0000-000000000000)입니다.

GAID란 무엇이며 Google 광고 식별자는 어떻게 작동하는가

광고 식별자의 기술적 구조

GAID는 Google Play 서비스가 불투명한 식별자 문자열로 반환하며, 일반적으로 128비트 소문자 16진수 UUID 형식(예: 38400000-8cf0-11bd-b23e-10b96e4ef00d)으로 표현됩니다. 애플리케이션은 반환된 문자열의 형식을 기반으로 비즈니스 로직을 유추하기보다 불투명한 식별자로 처리해야 합니다.

하드웨어 수준의 식별자와 달리, GAID는 명시적인 프라이버시 제어 기능을 갖추고 설계되었습니다.

  • 사용자 재설정 가능: 사용자는 기기 설정을 통해 언제든지 새로운 무작위 식별자를 생성할 수 있습니다.
  • 사용자 삭제 가능: Android 12부터 사용자는 광고 ID를 삭제하여 Google Play 서비스가 모든 앱에 광고 식별자를 제공하지 않도록 차단할 수 있습니다.
  • 프로필별 기기 범위: 광고 식별자는 일반적으로 동일한 기기 사용자 프로필 내의 앱 간에 공유되지만, 동일한 물리적 기기 내의 다른 Android 사용자 또는 게스트 프로필에는 서로 다른 광고 식별자가 할당됩니다.

식별자 상태 관리에 있어 Google Play 서비스의 역할

GAID는 오픈소스 Android 프레임워크의 핵심 구성 요소가 아닙니다. 독점적인 Google Play 서비스 클라이언트 라이브러리(com.google.android.gms:play-services-ads-identifier)를 통해 동적으로 관리되고 제공되는 애플리케이션 수준의 서비스입니다.

애플리케이션이 Google Play 서비스를 호출하면 클라이언트는 Google Play 서비스와의 동기 통신을 수행하여 현재 광고 식별자와 사용자 맞춤형 광고 제한(Limit Ad Tracking) 설정을 가져옵니다.

GAID가 하드웨어 식별자를 대체한 이유

초기 Android 버전에서는 광고 네트워크와 개발자가 재설정할 수 없는 하드웨어 식별자를 사용하여 전환 이벤트를 추적했습니다.

  • IMEI(International Mobile Equipment Identity): 기기의 셀룰러 하드웨어에 고정되어 있습니다.
  • MAC(Media Access Control) 주소: 네트워크 인터페이스 하드웨어에 고정되어 있습니다.
  • ANDROID_ID(SSAID): 최신 Android 8.0 이상 버전에서는 범용 크로스 앱 광고 키로 작동하는 대신 앱 서명 키, 사용자, 기기의 조합에 따라 범위가 지정됩니다.

Google Play의 광고 관련 유의 사항에 대해 개발자는 다른 지속적인 기기 식별자를 사용하는 대신 사용 가능한 경우 광고 식별자를 사용해야 합니다.

참고 항목: GAID ──> 모바일 어트리뷰션 아키텍처

Android 13 권한 요구 사항: AD_ID 매니페스트 선언

API 수준 33 강제 적용 모델

Android 13(API 수준 33)부터 Google은 com.google.android.gms.permission.AD_ID 권한을 도입했습니다.

  • SDK 33 이상 타겟팅: Android 13 이상을 타겟팅하는 애플리케이션은 매니페스트에 AD_ID 권한을 선언해야 합니다. 권한이 누락된 경우 Google Play 서비스는 0으로 채워진 문자열(00000000-0000-0000-0000-000000000000)을 반환합니다.
  • SDK 32 이하 타겟팅: 매니페스트에 AD_ID 권한이 필수가 아닙니다. 그러나 맞춤형 광고 제한 또는 삭제 상태를 포함한 사용자의 광고 ID 프라이버시 설정으로 인해 여전히 광고 ID를 사용하지 못하거나 0값으로 처리될 수 있습니다.
  • Play 스토어 정책 선언: API 수준 33 이상을 타겟팅하는 업데이트를 제출할 때 개발자는 Google Play 콘솔에서 현재 광고 ID 선언을 완료하고 앱이 식별자를 사용하는지 여부와 방식을 정확하게 보고해야 합니다.

Android 13 GAID 검색 및 0값 식별자 흐름

AndroidManifest.xml 및 Gradle 종속성 구성

권한을 선언하려면 AndroidManifest.xml 내부에 <uses-permission> 태그를 포함합니다. 앱 모듈의 build.gradle 파일에 공식 play-services-ads-identifier 종속성을 추가합니다.

아래의 설정은 매니페스트 권한 구문과 Gradle 종속성 구성을 보여줍니다.

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">

    <!-- 0이 아닌 GAID에 액세스하려면 API 33 이상에서 필요함 -->
    <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>

    <application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:theme="@style/Theme.MyApp">
        <!-- 애플리케이션 구성 요소 -->
    </application>
</manifest>
// 위치: app/build.gradle
// 참고: 예시 종속성 버전입니다. 프로덕션 환경에서 사용하기 전에 공식 저장소에서 최신 안정 버전을 확인하세요.

dependencies {
    // 공식 Google Play 서비스 광고 식별자 라이브러리
    implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'

    // 메인 스레드 외 비동기 실행을 위한 Kotlin 코루틴
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
}

매니페스트 병합 이해: 전이적 SDK 주입

Android APK 또는 AAB(Android App Bundle)를 빌드할 때 Gradle 빌드 시스템은 가져온 모든 타사 라이브러리의 매니페스트를 단일 최종 AndroidManifest.xml로 병합합니다.

가져온 광고 네트워크 SDK, 분석 도구 또는 어트리뷰션 라이브러리가 내부 매니페스트에 com.google.android.gms.permission.AD_ID를 선언하면 해당 권한이 최종 빌드에 자동으로 병합됩니다. 개발자는 app/build/outputs/logs/manifest-merger-release-report.txt를 검사하여 어떤 종속성이 해당 권한을 추가했는지 확인할 수 있습니다.

프로그래밍 방식 가져오기: Kotlin에서 AdvertisingIdClient를 통해 GAID 검색

필수 백그라운드 스레드 실행 규칙

AdvertisingIdClient.getAdvertisingIdInfo(context)를 호출하면 Google Play 서비스에 대한 동기 호출이 시작됩니다. Google은 메인(UI) 스레드에서 이 메서드를 실행하는 것을 엄격히 금지합니다.

메인 스레드에서 getAdvertisingIdInfo()를 호출하면 즉시 IllegalStateException이 발생합니다.

java.lang.IllegalStateException: Calling this from your main thread can lead to deadlock

앱 ANR(응답 없음) 오류 및 런타임 충돌을 방지하기 위해 개발자는 Dispatchers.IO를 사용하는 백그라운드 작업자 또는 Kotlin 코루틴 내에서 추출 호출을 디스패치해야 합니다.

메인 스레드가 아닌 곳에서 AdvertisingIdClient GAID 검색

Kotlin 코루틴을 사용한 백그라운드 작업자 구현

아래의 Kotlin 구현은 메인 스레드 외부에 추출을 실행하고, Google Play 서비스 가용성 예외를 처리하며, 식별자 무결성을 검증하는 스레드 안전한 AdvertisingIdManager를 보여줍니다.

package com.example.myapp.analytics

import android.content.Context
import android.util.Log
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.google.android.gms.common.GooglePlayServicesNotAvailableException
import com.google.android.gms.common.GooglePlayServicesRepairableException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.IOException

data class GaidResult(
    val gaid: String?,
    val isLimitAdTrackingEnabled: Boolean,
    val isZeroed: Boolean,
    val isAvailable: Boolean
)

object AdvertisingIdManager {

    private const val TAG = "AdvertisingIdManager"
    private const val ZEROED_GAID = "00000000-0000-0000-0000-000000000000"

    /**
     * 메인 실행 스레드 외부에서 Google 광고 식별자를 프로그래밍 방식으로 가져옵니다.
     * 예외, 0값 상태 및 사용자 수신 거부를 자동으로 처리합니다.
     */
    suspend fun fetchGaid(context: Context): GaidResult = withContext(Dispatchers.IO) {
        try {
            // IO 코루틴 디스패치에서 블로킹 방식의 Google Play 서비스 IPC 호출
            val adInfo: AdvertisingIdClient.Info = AdvertisingIdClient.getAdvertisingIdInfo(context)
            
            val rawId = adInfo.id
            val isLAT = adInfo.isLimitAdTrackingEnabled
            val isZeroed = rawId == null || rawId.equals(ZEROED_GAID, ignoreCase = true)

            if (isZeroed) {
                Log.w(TAG, "광고 ID를 사용할 수 없거나 0값으로 설정되어 있습니다.")
                GaidResult(
                    gaid = null,
                    isLimitAdTrackingEnabled = isLAT,
                    isZeroed = true,
                    isAvailable = false
                )
            } else {
                Log.d(TAG, "광고 ID를 성공적으로 가져왔습니다. LAT 활성화 여부: $isLAT")
                GaidResult(
                    gaid = rawId,
                    isLimitAdTrackingEnabled = isLAT,
                    isZeroed = false,
                    isAvailable = true
                )
            }
        } catch (e: GooglePlayServicesNotAvailableException) {
            Log.e(TAG, "이 기기에 Google Play 서비스가 설치되어 있지 않거나 사용할 수 없습니다.", e)
            GaidResult(gaid = null, isLimitAdTrackingEnabled = true, isZeroed = false, isAvailable = false)
        } catch (e: GooglePlayServicesRepairableException) {
            Log.w(TAG, "Google Play 서비스에 업데이트 또는 사용자 복구가 필요합니다.", e)
            GaidResult(gaid = null, isLimitAdTrackingEnabled = true, isZeroed = false, isAvailable = false)
        } catch (e: IOException) {
            Log.e(TAG, "Google Play 서비스 연결 중 통신 오류가 발생했습니다.", e)
            GaidResult(gaid = null, isLimitAdTrackingEnabled = true, isZeroed = false, isAvailable = false)
        } catch (e: IllegalStateException) {
            Log.e(TAG, "광고 ID를 검색하는 동안 잘못된 상태가 되었습니다.", e)
            GaidResult(gaid = null, isLimitAdTrackingEnabled = true, isZeroed = false, isAvailable = false)
        } catch (e: Exception) {
            Log.e(TAG, "Google 광고 ID를 검색하는 중 예기치 않은 오류가 발생했습니다.", e)
            GaidResult(gaid = null, isLimitAdTrackingEnabled = true, isZeroed = false, isAvailable = false)
        }
    }
}

AdvertisingIdClient.Info 파싱 및 맞춤형 광고 제한 처리

AdvertisingIdClient.getAdvertisingIdInfo() 메서드는 다음 두 가지 핵심 속성을 포함하는 AdvertisingIdClient.Info 객체를 반환합니다.

  • getId() (String): 광고 식별자를 나타내는 영숫자 문자열입니다.
  • isLimitAdTrackingEnabled() (Boolean): 맞춤형 광고 제한이 활성화된 경우 Google Play 정책에 따라 광고 식별자 데이터를 사용하여 광고 프로필을 생성하거나 맞춤형 광고를 타겟팅하는 것이 금지됩니다. 컨텍스트 광고, 빈도 제한, 전환 추적, 리포팅, 보안 및 사기 감지 등의 활동은 여전히 정책상 허용됩니다. 다만 현재 Google Play 서비스에서는 이 설정이 활성화되면 광고 식별자 자체가 0값으로 처리되므로 애플리케이션은 사용 가능한 GAID가 계속 유지된다고 가정해서는 안 됩니다.

0값 식별자 및 사용자에 의한 삭제 상태 처리

00000000-0000-0000-0000-000000000000 문자열: 표시 시기와 이유

프로덕션 환경에서 AdvertisingIdClient.Info.getId()는 다음과 같은 경우 00000000-0000-0000-0000-000000000000을 반환합니다.

  1. 사용자가 광고 ID를 삭제한 경우: 사용자가 기기 설정으로 이동하여 광고 ID를 삭제했습니다.
  2. 맞춤형 광고 제한이 활성화된 경우: 사용자가 지원되는 OS 버전에서 맞춤형 광고 제한을 활성화했습니다.
  3. 매니페스트 권한 누락: 애플리케이션이 Android 13+(API 수준 33+)를 타겟팅하면서 병합된 매니페스트에 com.google.android.gms.permission.AD_ID를 선언하지 않았습니다.

GAID 0값 식별자 및 프라이버시 상태 처리

사용자 설정 워크플로: 광고 ID 삭제

최신 Android 버전의 사용자는 다음 경로로 이동하여 식별자를 제거할 수 있습니다.

설정 > 개인 정보 보호 > 광고 > 광고 ID 삭제 (정확한 메뉴 이름은 기기 제조사에 따라 다를 수 있습니다).

삭제되면 Google Play 서비스는 기본 값을 삭제합니다. 이후 설치된 모든 앱에서의 API 호출은 0으로 채워진 문자열을 반환합니다.

재설정 및 삭제 상태에 대한 Google Play 정책 요구 사항

광고 ID에 관한 Google Play 개발자 정책에 따라 개발자는 명시적 규칙에 맞춰 사용자 프라이버시 조치를 처리해야 합니다.

  • 재설정 요구 사항: 사용자가 광고 ID를 재설정할 때, 개발자는 명시적인 사용자 동의 없이 새로운 광고 ID를 이전 광고 ID 또는 그로부터 파생된 데이터에 연결하거나 결합해서는 안 됩니다.
  • 삭제 요구 사항: 사용자가 광고 ID를 삭제할 때, 개발자는 해당 기기를 이전 광고 ID에 연결되었거나 그로부터 파생된 데이터에 연결해서는 안 됩니다.

다운스트림 수집 파이프라인에서 식별자 입력값 정제

백엔드 어트리뷰션 엔진은 0값 문자열이 어트리뷰션 데이터베이스를 오염시키지 않도록 유효성 검사 필터를 구현해야 합니다.

fun isGaidValid(gaid: String?): Boolean {
    if (gaid.isNullOrBlank()) return false
    val zeroedGaid = "00000000-0000-0000-0000-000000000000"
    return !gaid.equals(zeroedGaid, ignoreCase = true)
}

0값 식별자가 감지된 경우 다운스트림 시스템은 이를 사용 가능한 GAID나 식별자 매칭 키로 처리해서는 안 됩니다. 모든 어트리뷰션 또는 분석 처리는 독립적으로 허용된 다른 신호에만 의존해야 합니다.

Google Play 패밀리 정책 및 앱 카테고리 제한

패밀리 앱에서의 데이터 관행

Google Play는 패밀리 프로그램에 참여하거나 아동을 타겟팅하는 애플리케이션에 대해 엄격한 데이터 보호 규칙을 시행합니다.

  • AAID 전송 금지: 아동만을 타겟팅하는 애플리케이션은 AAID(광고 ID)를 전송해서는 안 됩니다. API 수준 33 이상을 타겟팅하는 앱의 경우, Google은 간단한 규정 준수 메커니즘으로 AD_ID 권한을 생략하거나 비활성화할 것을 권장합니다.
  • 혼합 대상층 처리: 아동과 고연령층 모두를 타겟팅하는 애플리케이션은 아동이나 연령을 알 수 없는 사용자의 AAID를 전송해서는 안 됩니다. 기본적으로 앱과 SDK는 연령 확인을 통해 사용자가 아동이 아님을 확인하기 전까지 AAID 전송을 피해야 합니다.

매니페스트에서 tools:node=“remove” 사용

애플리케이션이 아동을 타겟팅하지만 가져온 타사 SDK가 매니페스트 병합을 통해 AD_ID 권한을 자동으로 주입하는 경우, 메인 AndroidManifest.xmltools:node="remove" 속성을 추가하세요.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.familyapp">

    <!-- 전이적 종속성에 의해 주입된 AD_ID를 명시적으로 제거 -->
    <uses-permission 
        android:name="com.google.android.gms.permission.AD_ID" 
        tools:node="remove"/>

</manifest>

GAID를 사용할 수 없을 때 활용할 수 있는 유익한 측정 대안

GAID가 0값으로 처리되거나, 삭제되었거나, 정책에 의해 제한된 경우 엔지니어링 팀은 기능적 목적에 따라 유익한 대안을 배포합니다.

  • 캠페인 어트리뷰션: Google Play Install Referrer API를 사용하여 Play 스토어 URL(referrer=...)을 통해 전달된 스토어 중계 캠페인 파라미터를 가져옵니다. GAID 삭제와 무관하게 작동합니다.
  • 온보딩 및 사용자 의도: 웹 랜딩 페이지에서 전달된 리퍼럴 토큰, 프로모션 코드 및 딥 링크 목적지를 복원하기 위해 자사(First-party) 컨텍스트 파라미터 라우팅을 사용합니다.
  • 개발자 범위 분석 및 사기 방지: 크로스 앱 광고 추적 없이 동일한 개발자 계정으로 게시된 앱 간에 공유 식별자를 생성하기 위해 App Set ID(AppSetIdClient)를 사용합니다.
                    GAID를 사용할 수 없거나 0값인 경우
                                 │
         ┌───────────────────────┼───────────────────────┐
         │                       │                       │
         ▼                       ▼                       ▼
     유료 캠페인             온보딩 및             개발자 소유
      어트리뷰션             리퍼럴 의도           분석 및 사기 방지
         │                       │                       │
         ▼                       ▼                       ▼
    Google Play             자사 컨텍스트               App Set ID
   Install Referrer           라우팅              (개발자 또는
     (스토어 URL)                                   앱 범위 지정)

어트리뷰션 온보딩 및 분석을 위한 GAID 대안

비교 매트릭스: GAID 대 Install Referrer 대 App Set ID

측면 Google 광고 식별자(GAID) Google Play Install Referrer App Set ID (AppSet)
식별자 유형 재설정 가능한 크로스 앱 광고 UUID 스토어 중계 캠페인 파라미터 문자열 설치 및 Play 서비스 컨텍스트에 따라 개발자 또는 앱 범위로 지정되는 식별자
매니페스트 권한 com.google.android.gms.permission.AD_ID 없음 없음
사용자 삭제 영향 0으로 채워진 문자열 반환 GAID 삭제와 독립적으로 작동 API 액세스 없이 13개월이 경과하거나, 세트에 포함된 마지막 앱이 제거되거나, 공장 초기화 후 재설정될 수 있음
주요 활용 사례 크로스 앱 광고 어트리뷰션 및 리타겟팅 Play 스토어 캠페인 성과 추적 사기 탐지 및 개발자 소유 분석
패밀리 정책 적합성 아동 관련 데이터에서 전송되어서는 안 됨 AAID 전송 금지 대상에 해당하지 않음. 단, 사용 시 관련 패밀리 정책을 준수해야 함 패밀리 앱 내 분석 용도로 Google에서 권장함

자주 묻는 질문(FAQ)

AdvertisingIdClient를 호출할 때 왜 IllegalStateException 충돌이 발생하나요?
AdvertisingIdClient.getAdvertisingIdInfo(context)는 Google Play 서비스와의 블로킹 통신을 수행합니다. Google은 메인 실행 스레드에서 이 메서드를 호출하는 것을 엄격히 금지합니다. 개발자는 `Dispatchers.IO`를 사용하여 백그라운드 스레드 또는 Kotlin 코루틴 내에서 이 메서드를 호출해야 합니다.
앱이 Android 13을 타겟팅하면서 AD_ID 권한을 선언하지 않으면 어떻게 되나요?
앱이 API 수준 33 이상을 타겟팅하면서 병합된 매니페스트에 `com.google.android.gms.permission.AD_ID` 권한을 선언하지 않으면, Google Play 서비스 API는 실제 광고 식별자 대신 `00000000-0000-0000-0000-000000000000`을 자동으로 반환합니다.
타사 SDK 종속성에 의해 주입된 AD_ID 권한은 어떻게 제거하나요?
타사 라이브러리가 매니페스트 병합을 통해 `AD_ID` 권한을 자동으로 주입하고 앱이 Google Play 패밀리 정책을 준수해야 하는 경우, 메인 `AndroidManifest.xml` 파일에 `<uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/>`를 추가하세요.

요약 및 결정 프레임워크

Google 광고 ID는 Android 광고 및 사용자 분석 유의 사항에서 여전히 중요한 재설정 가능 식별자이지만, Android 13 이상에서 운영하려면 매니페스트 권한 정책, 백그라운드 실행 표준 준수 및 0값 식별자 상태에 대한 유연한 처리가 필요합니다. GAID를 사용할 수 없는 경우 엔지니어링 팀은 구체적인 유의 사항에 적합한 측정 방식을 선택해야 합니다. 예를 들어 Play 스토어 캠페인 어트리뷰션에는 Install Referrer를, 온보딩 상태에는 자사 컨텍스트 파라미터를, 개발자 소유 분석 및 사기 방지 시나리오에는 App Set ID를 활용할 수 있습니다.

Android 어트리뷰션 및 딥 링크 파이프라인의 구현 패턴을 살펴보려면 OpoInstall 문서를 참조하세요.

관련 자료

  • 개념: 광고 ID 라이프사이클, AD_ID 매니페스트 권한, 백그라운드 스레드 추출, 0값 식별자 처리

  • 기술: Google Play 서비스, AdvertisingIdClient API, Google Play Install Referrer API, OpoInstall Android SDK

  • 표준: Google Play 개발자 정책, Android 13 동작 변경 사항, IETF RFC 4122 UUID 표준

  • API 및 클래스: AdvertisingIdClient, AdvertisingIdClient.Info, AppSetIdClient, OpoInstall Context API

공식 문서

Share this article