廣告識別碼變更:如何在 Android 13+ 中取得 Google GAID?

opoinstall
2026-08-24
5 min read

什麼是 GAID 以及如何透過程式碼取得?Google 廣告識別碼 (GAID) 是由 Google Play 服務提供、可由使用者重設的軟體識別碼,用於廣告成效衡量。當確保合併後的應用程式資訊清單包含必要的 AD_ID 權限後,即可透過 AdvertisingIdClient API 在主執行緒之外以程式碼取得。

Google 廣告識別碼 (GAID) 也稱為 Android 廣告識別碼 (AAID),是由 Google Play 服務提供的一個可重設、具唯一性的字串,用於 Android 裝置上的廣告歸因、個人化廣告指定與分析。針對 Android 13 (API 級別 33) 或更高版本的應用程式,在存取 Google Play 服務廣告識別碼時,必須確保合併後的資訊清單包含 com.google.android.gms.permission.AD_ID 權限;否則 API 將會回傳全為零的數值。

術語 定義
GAID 由 Google Play 服務提供,用於廣告成效衡量的 Google 廣告識別碼。
AdvertisingIdClient 用於查詢廣告識別碼後設資料的 Google Play 服務 API。
AD_ID 權限 當目標 API 級別為 33+ 的應用程式存取 Google Play 服務廣告識別碼時,所需的 Android 資訊清單權限。
歸零識別碼 當廣告識別碼無法使用或被拒絕授權時所回傳的全零哨兵值 (00000000-0000-0000-0000-000000000000)。

什麼是 GAID 以及 Google 廣告識別碼的運作方式

廣告識別碼的技術解析

Google 廣告識別碼 (GAID) 是由 Google Play 服務回傳的隱含識別碼字串,通常格式化為 128 位元的半形小寫十六進位 UUID (例如 38400000-8cf0-11bd-b23e-10b96e4ef00d)。應用程式應將回傳的字串視為隱含識別碼,而不應從其格式推導商業邏輯。

與硬體層級的識別碼不同,GAID 具有明確的隱私權控制設計:

  • 使用者可重設:使用者隨時可以透過裝置設定產生新的隨機識別碼。
  • 使用者可刪除:從 Android 12 開始,使用者可以刪除其廣告識別碼,指示 Google Play 服務對所有應用程式隱藏廣告識別碼。
  • 每個設定檔的裝置範圍:廣告識別碼通常適用於同一裝置使用者設定檔中的所有應用程式,但同一實體裝置上的不同 Android 使用者或訪客設定檔會收到不同的廣告識別碼。

Google Play 服務在管理識別碼狀態中的角色

GAID 並非核心開源 Android 架構的一部分。它是一項由專有 Google Play 服務用戶端函式庫 (com.google.android.gms:play-services-ads-identifier) 動態管理與提供的應用程式層級服務。

當應用程式呼叫 Google Play 服務時,用戶端會與 Google Play 服務進行封鎖式通訊,以擷取目前的廣告識別碼與使用者限制廣告追蹤偏好設定。

為什麼 GAID 會取代硬體識別碼

在早期 Android 版本中,廣告聯播網與開發者使用無法重設的硬體識別碼來追蹤轉換事件:

  • 國際行動裝置設備識別碼 (IMEI):與裝置的行動通訊硬體繫結。
  • 媒體存取控制 (MAC) 位址:與網路介面硬體繫結。
  • 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 服務將回傳一串零 (00000000-0000-0000-0000-000000000000)。
  • 目標 SDK 32 及以下:資訊清單中不需要 AD_ID 權限。然而,由於使用者的廣告識別碼隱私權設定(包含限制廣告追蹤或刪除狀態),廣告識別碼仍然可能無法使用或歸零。
  • Play 商店政策宣告:提交針對 API 級別 33+ 的更新時,開發者必須在 Google Play Console 中完成目前的廣告識別碼宣告,準確回報應用程式是否以及如何使用該識別碼。

Android 13 GAID 擷取與歸零識別碼流程

設定 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">

    <!-- 在 API 33+ 上存取非零 GAID 所需 -->
    <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 服務 Ads Identifier 函式庫
    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 或 Android App Bundle (AAB) 時,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 實作展示了具備執行緒安全的 AdvertisingIdManager,它能在主執行緒外執行擷取、處理 Google Play 服務可用性例外狀況,並驗證識別碼完整性:

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 廣告識別碼。
     * 自動處理例外狀況、歸零狀態與使用者退出設定。
     */
    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, "廣告識別碼無法使用或已歸零。")
                GaidResult(
                    gaid = null,
                    isLimitAdTrackingEnabled = isLAT,
                    isZeroed = true,
                    isAvailable = false
                )
            } else {
                Log.d(TAG, "成功擷取廣告識別碼。已啟用 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, "擷取廣告識別碼時發生無效狀態。", e)
            GaidResult(gaid = null, isLimitAdTrackingEnabled = true, isZeroed = false, isAvailable = false)
        } catch (e: Exception) {
            Log.e(TAG, "擷取 Google 廣告識別碼時發生未預期的錯誤。", e)
            GaidResult(gaid = null, isLimitAdTrackingEnabled = true, isZeroed = false, isAvailable = false)
        }
    }
}

解析 AdvertisingIdClient.Info 與處理限制廣告追蹤

AdvertisingIdClient.getAdvertisingIdInfo() 方法會回傳一個包含兩個關鍵屬性的 AdvertisingIdClient.Info 物件:

  • getId() (String):代表廣告識別碼的英數字串。
  • isLimitAdTrackingEnabled() (Boolean):當啟用限制廣告追蹤時,Google Play 政策禁止使用廣告識別碼資料來建立廣告設定檔或指定個人化廣告。政策仍然允許情境式廣告、頻率上限控制、轉換追蹤、報表與安全性/詐欺偵測等活動;然而,在目前的 Google Play 服務中,當啟用此設定時,廣告識別碼本身會被歸零,因此應用程式不應假設可用的 GAID 仍然存在。

處理歸零識別碼與使用者主動刪除狀態

00000000-0000-0000-0000-000000000000 字串:何時以及為何會出現

在正式環境中,當發生以下情況時,AdvertisingIdClient.Info.getId() 會回傳 00000000-0000-0000-0000-000000000000

  1. 使用者已刪除廣告識別碼:使用者前往裝置設定並刪除了他們的廣告識別碼。
  2. 已啟用限制廣告追蹤:使用者在支援的作業系統版本上啟用了限制廣告追蹤。
  3. 缺少資訊清單權限:應用程式以 Android 13+ (API 級別 33+) 為目標,且未在其合併的資訊清單中宣告 com.google.android.gms.permission.AD_ID

GAID 歸零識別碼與隱私權狀態處理

使用者設定工作流程:刪除廣告識別碼

現行 Android 版本的使用者可以透過導覽至下列路徑來移除其識別碼:

設定 > 隱私權 > 廣告 > 刪除廣告識別碼(確切標籤可能因裝置 OEM 而異)。

刪除後,Google Play 服務會清除底層數值。所有已安裝應用程式後續的 API 呼叫都會回傳歸零字串。

重設與刪除狀態的 Google Play 政策需求

根據 Google Play 關於廣告識別碼的開發者政策,開發者必須根據明確規則處理使用者隱私權動作:

  • 重設需求:當使用者重設其廣告識別碼時,未經使用者明確同意,開發者不得將新的廣告識別碼與先前的廣告識別碼或衍生自該識別碼的資料進行橋接或連結。
  • 刪除需求:當使用者刪除其廣告識別碼時,開發者不得將該裝置與其先前廣告識別碼所連結或衍生出的資料進行連結。

在下游擷取管線中清理識別碼輸入

後端歸因引擎必須實作驗證過濾器,以防止歸零字串污染歸因資料庫:

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

如果偵測到歸零識別碼,下游系統切勿將其視為可用的 GAID 或識別碼配對金鑰;任何歸因或分析處理都應僅依賴其他獨立允許的訊號。

Google Play 家庭政策與應用程式類別限制

家庭應用程式中的資料實務

Google Play 針對參與家庭計畫或以兒童為目標的應用程式強制執行嚴格的資料保護規則:

  • 禁止傳輸 AAID:專門以兒童為目標的應用程式不得傳輸廣告識別碼 (AAID)。對於以 API 級別 33 或更高版本為目標的應用程式,Google 建議省略或停用 AD_ID 權限作為簡單直接的合規機制。
  • 混合受眾處理:同時以兒童和較年長受眾為目標的應用程式,不得傳輸來自兒童或未知年齡使用者的 AAID。根據預設,應用程式與 SDK 應避免傳輸 AAID,直到年齡驗證確認使用者並非兒童為止。

在資訊清單中使用 tools:node=“remove”

如果您的應用程式以兒童為目標,但匯入的第三方 SDK 透過資訊清單合併自動注入了 AD_ID 權限,請在您的主 AndroidManifest.xml 中加入 tools: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 歸零、被刪除或受政策限制時,工程團隊會根據其功能目標部署特定使用情境的替代方案:

  • 行銷活動歸因:使用 Google Play 安裝推薦連結 API 來擷取透過 Play 商店網址 (referrer=...) 傳遞的商店中介行銷活動參數。獨立於 GAID 刪除運作。
  • 新手引導與使用者意圖:使用第一方情境參數路由來還原從網頁到達網頁傳遞的推薦代碼、優惠券代碼與深層連結目的地。
  • 開發者範圍分析與詐欺防範:使用應用程式集識別碼 (AppSetIdClient) 在發布於相同開發者帳戶下的應用程式之間產生共用識別碼,而無需進行跨應用程式廣告追蹤。
                    GAID 無法使用或已歸零
                                 │
         ┌───────────────────────┼───────────────────────┐
         │                       │                       │
         ▼                       ▼                       ▼
     付費行銷活動             新手引導與              開發者擁有的
       歸因                  推薦意圖              分析與詐欺防範
         │                       │                       │
         ▼                       ▼                       ▼
    Google Play             第一方                  應用程式集識別碼
    安裝推薦連結             情境式                  (開發者或
     (商店網址)              路由                  應用程式範圍)

用於歸因、新手引導與分析的 GAID 替代方案

比較矩陣:GAID 與安裝推薦連結與應用程式集識別碼

維度 Google 廣告識別碼 (GAID) Google Play 安裝推薦連結 應用程式集識別碼 (AppSet)
識別碼類型 可重設的跨應用程式廣告 UUID 商店中介的行銷活動參數字串 開發者或應用程式範圍的識別碼,取決於安裝與 Play 服務內容
資訊清單權限 com.google.android.gms.permission.AD_ID
使用者刪除影響 回傳一串零 獨立於 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 家庭政策,請將 `<uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/>` 加入您的主 `AndroidManifest.xml` 檔案中。

總結與決策框架

Google 廣告識別碼對於 Android 廣告與使用者分析使用情境而言,依然是重要的可重設識別碼,但在 Android 13+ 上運作時,需要遵守資訊清單權限政策、背景執行標準,以及對歸零識別碼狀態的妥善處理。當 GAID 無法使用時,工程團隊應根據特定的使用情境選擇衡量基礎元件——例如,針對 Play 商店行銷活動歸因選擇安裝推薦連結、針對新手引導狀態選擇第一方情境參數,或針對開發者擁有的分析與防弊情境選擇應用程式集識別碼。

若要探索 Android 歸因與深層連結管線的實作模式,請查閱 OpoInstall 文件

相關資料

  • 概念:廣告識別碼生命週期、AD_ID 資訊清單權限、背景執行緒擷取、歸零識別碼處理

  • 技術:Google Play 服務、AdvertisingIdClient API、Google Play 安裝推薦連結 API、OpoInstall Android SDK

  • 標準:Google Play 開發者政策、Android 13 行為變更、IETF RFC 4122 UUID 標準

  • API 與類別AdvertisingIdClientAdvertisingIdClient.InfoAppSetIdClient、OpoInstall Context API

官方文件

Share this article