DevCheck-lib/DeviceInfo-DeviceID和GAID使用示例.md
2025-12-24 15:32:35 +08:00

12 KiB
Raw Blame History

DeviceInfo - Device ID 和 GAID 使用示例

概述

DeviceInfo 类现在提供了完整的设备标识符获取功能,包括 Android ID (Device ID) 和 Google Advertising ID (GAID)。

新增功能

1. Android ID (Device ID)

  • getAndroidId() - 获取 Android ID

2. Google Advertising ID (GAID)

  • getAdvertisingId() - 协程方式获取 GAID推荐
  • getAdvertisingIdSync() - 同步方式获取 GAID不推荐
  • getDeviceIdentifiers() - 获取所有标识符

3. 数据类

  • AdvertisingIdInfo - GAID 信息
  • DeviceIdentifiers - 设备标识符集合

使用方法

1. 初始化

import com.xyzshell.andinfo.AndInfo

// 在 Application 或 Activity 中初始化
AndInfo.init(applicationContext)

// 获取 DeviceInfo 实例
val deviceInfo = AndInfo.instance.device

2. 获取 Android ID (Device ID)

基本使用

// 获取 Android ID
val androidId = deviceInfo.getAndroidId()
println("Android ID: $androidId")
// 输出示例: "Android ID: 9774d56d682e549c"

Android ID 特点

  • 格式: 64位十六进制字符串
  • 生成时机: 设备首次启动时随机生成
  • 持久性:
    • 出厂重置后会改变
    • 清除应用数据不会改变
  • 作用域:
    • Android 8.0+ 后,每个应用和用户组合都会获得不同的 Android ID
    • Android 8.0 之前,所有应用获得相同的 Android ID
  • 权限: 不需要特殊权限

适用场景

// 1. 应用级设备标识
fun getDeviceTag(): String {
    val deviceInfo = AndInfo.instance.device
    return "device_${deviceInfo.getAndroidId()}"
}

// 2. 用户设备绑定
fun bindDeviceToUser(userId: String) {
    val deviceInfo = AndInfo.instance.device
    val androidId = deviceInfo.getAndroidId()
    // 将 androidId 与 userId 关联存储
    saveBinding(userId, androidId)
}

// 3. 设备唯一性校验
fun isNewDevice(): Boolean {
    val deviceInfo = AndInfo.instance.device
    val androidId = deviceInfo.getAndroidId()
    return !isDeviceRegistered(androidId)
}

3. 获取 GAID (Google Advertising ID)

协程方式(推荐)

import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch

// 在 Activity 或 Fragment 中
lifecycleScope.launch {
    val deviceInfo = AndInfo.instance.device
    val gaidInfo = deviceInfo.getAdvertisingId()
    
    if (gaidInfo != null) {
        println("GAID: ${gaidInfo.id}")
        println("是否限制追踪: ${gaidInfo.isLimitAdTrackingEnabled}")
        
        // 根据追踪限制状态决定是否使用
        if (!gaidInfo.isLimitAdTrackingEnabled) {
            // 用户允许广告追踪,可以使用 GAID
            sendToAnalytics(gaidInfo.id)
        } else {
            // 用户限制了广告追踪,应该尊重用户选择
            println("用户已限制广告追踪")
        }
    } else {
        // Google Play Services 不可用
        println("无法获取 GAID设备可能没有 Google Play Services")
    }
}

在 ViewModel 中使用

class MainViewModel : ViewModel() {
    fun loadAdvertisingId() {
        viewModelScope.launch {
            val deviceInfo = AndInfo.instance.device
            val gaidInfo = deviceInfo.getAdvertisingId()
            
            gaidInfo?.let { info ->
                _advertisingId.value = info.id
                _isTrackingLimited.value = info.isLimitAdTrackingEnabled
            }
        }
    }
}

同步方式(不推荐)

// ⚠️ 警告:会阻塞当前线程,不要在主线程调用
Thread {
    val deviceInfo = AndInfo.instance.device
    val gaidInfo = deviceInfo.getAdvertisingIdSync()
    
    gaidInfo?.let { info ->
        println("GAID: ${info.id}")
    }
}.start()

GAID 特点

  • 格式: UUID 格式的字符串
  • 示例: "38400000-8cf0-11bd-b23e-10b96e40000d"
  • 依赖: 需要 Google Play Services
  • 用户控制:
    • 用户可以在设置中重置 GAID
    • 用户可以选择限制广告追踪
  • 权限: 不需要特殊权限,但需要 Google Play Services
  • 线程: 必须在后台线程调用

4. 获取所有设备标识符

// 一次性获取所有标识符
lifecycleScope.launch {
    val deviceInfo = AndInfo.instance.device
    val identifiers = deviceInfo.getDeviceIdentifiers()
    
    println("=== 设备标识符 ===")
    println("Android ID: ${identifiers.androidId}")
    
    identifiers.advertisingId?.let { gaid ->
        println("GAID: ${gaid.id}")
        println("限制追踪: ${gaid.isLimitAdTrackingEnabled}")
    } ?: run {
        println("GAID: 不可用")
    }
}

5. 完整示例:设备信息收集

class DeviceInfoActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        lifecycleScope.launch {
            collectDeviceInfo()
        }
    }
    
    private suspend fun collectDeviceInfo() {
        val deviceInfo = AndInfo.instance.device
        
        // 基本设备信息
        val brand = deviceInfo.brand
        val model = deviceInfo.model
        val manufacturer = deviceInfo.manufacturer
        
        // 设备标识符
        val androidId = deviceInfo.getAndroidId()
        val gaidInfo = deviceInfo.getAdvertisingId()
        
        // 显示信息
        val info = buildString {
            appendLine("=== 设备信息 ===")
            appendLine("品牌: $brand")
            appendLine("型号: $model")
            appendLine("制造商: $manufacturer")
            appendLine()
            appendLine("=== 设备标识符 ===")
            appendLine("Android ID: $androidId")
            
            if (gaidInfo != null) {
                appendLine("GAID: ${gaidInfo.id}")
                appendLine("限制追踪: ${if (gaidInfo.isLimitAdTrackingEnabled) "是" else "否"}")
            } else {
                appendLine("GAID: 不可用(可能没有 Google Play Services")
            }
        }
        
        println(info)
        // 或显示在 UI 上
        // textView.text = info
    }
}

数据结构

AdvertisingIdInfo

/**
 * 广告标识符信息数据类
 */
data class AdvertisingIdInfo(
    val id: String,                        // GAID
    val isLimitAdTrackingEnabled: Boolean  // 是否限制广告追踪
)

DeviceIdentifiers

/**
 * 设备标识符集合数据类
 */
data class DeviceIdentifiers(
    val androidId: String,                    // Android ID
    val advertisingId: AdvertisingIdInfo?     // GAID可能为 null
)

Android ID vs GAID 对比

特性 Android ID GAID
格式 64位十六进制 UUID
示例 9774d56d682e549c 38400000-8cf0-11bd-b23e-10b96e40000d
依赖 Google Play Services
权限 无需权限 无需权限
重置 出厂重置后改变 用户可随时重置
作用域 Android 8.0+ 按应用区分 全局统一
用户控制 不可控制 可限制追踪
适用场景 应用内标识、设备绑定 广告追踪、分析
隐私友好 中等 高(用户可控)

典型应用场景

1. 广告归因

suspend fun trackAdConversion(campaignId: String) {
    val deviceInfo = AndInfo.instance.device
    val gaidInfo = deviceInfo.getAdvertisingId()
    
    if (gaidInfo != null && !gaidInfo.isLimitAdTrackingEnabled) {
        // 用户允许追踪,上报转化数据
        analyticsService.trackConversion(
            gaid = gaidInfo.id,
            campaignId = campaignId
        )
    } else {
        // 使用匿名方式或不追踪
        analyticsService.trackAnonymousConversion(campaignId)
    }
}

2. 用户设备管理

suspend fun registerDevice() {
    val deviceInfo = AndInfo.instance.device
    val identifiers = deviceInfo.getDeviceIdentifiers()
    
    // 注册设备信息
    val deviceProfile = DeviceProfile(
        androidId = identifiers.androidId,
        brand = deviceInfo.brand,
        model = deviceInfo.model,
        timestamp = System.currentTimeMillis()
    )
    
    saveDeviceProfile(deviceProfile)
}

3. 防作弊检测

suspend fun checkDeviceFraud(): Boolean {
    val deviceInfo = AndInfo.instance.device
    val androidId = deviceInfo.getAndroidId()
    
    // 检查设备是否被标记为作弊
    return fraudDetectionService.isDeviceFlagged(androidId)
}

4. A/B 测试分组

suspend fun getExperimentGroup(): String {
    val deviceInfo = AndInfo.instance.device
    val gaidInfo = deviceInfo.getAdvertisingId()
    
    // 使用 GAID 的哈希值进行分组
    val deviceId = gaidInfo?.id ?: deviceInfo.getAndroidId()
    val hash = deviceId.hashCode()
    
    return if (hash % 2 == 0) "GroupA" else "GroupB"
}

5. 隐私合规检查

suspend fun checkPrivacyCompliance(): PrivacyStatus {
    val deviceInfo = AndInfo.instance.device
    val gaidInfo = deviceInfo.getAdvertisingId()
    
    return PrivacyStatus(
        hasGooglePlayServices = gaidInfo != null,
        isTrackingLimited = gaidInfo?.isLimitAdTrackingEnabled ?: true,
        canUsePersonalizedAds = gaidInfo?.let { !it.isLimitAdTrackingEnabled } ?: false
    )
}

依赖配置

要使用 GAID 功能,需要在 build.gradle 中添加依赖:

dependencies {
    // Google Play Services - Advertising ID
    implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
    
    // Kotlin Coroutines如果项目中还没有
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
}

注意事项

1. Android ID

  • ⚠️ Android 8.0+ 后,每个应用获得的 Android ID 不同
  • ⚠️ 出厂重置后会改变
  • ⚠️ 不应用于跨应用追踪
  • 适合应用内设备标识

2. GAID

  • ⚠️ 需要 Google Play Services国内设备可能不可用
  • ⚠️ 必须尊重用户的"限制广告追踪"设置
  • ⚠️ 必须在后台线程调用
  • ⚠️ 用户可以随时重置
  • 适合广告归因和分析
  • 符合 Google Play 政策

3. 隐私合规

  • 📋 遵守 GDPR、CCPA 等隐私法规
  • 📋 在隐私政策中说明标识符用途
  • 📋 尊重用户的追踪限制选择
  • 📋 提供用户删除数据的选项

4. 最佳实践

suspend fun getDeviceIdentifierForAnalytics(): String? {
    val deviceInfo = AndInfo.instance.device
    
    // 1. 优先使用 GAID如果可用且用户允许
    val gaidInfo = deviceInfo.getAdvertisingId()
    if (gaidInfo != null && !gaidInfo.isLimitAdTrackingEnabled) {
        return gaidInfo.id
    }
    
    // 2. 用户限制了追踪,不应该使用任何标识符
    if (gaidInfo?.isLimitAdTrackingEnabled == true) {
        return null  // 返回 null 表示不追踪
    }
    
    // 3. GAID 不可用(可能是国内设备),使用 Android ID
    // 注意:这种情况下应该获得用户明确同意
    return if (hasUserConsent()) {
        deviceInfo.getAndroidId()
    } else {
        null
    }
}

示例输出

=== 设备信息 ===
品牌: Samsung
型号: SM-G998B
制造商: samsung

=== 设备标识符 ===
Android ID: 9774d56d682e549c
GAID: 38400000-8cf0-11bd-b23e-10b96e40000d
限制追踪: 否

完成度

100% - 所有功能都已实现

  • Android ID (Device ID) 获取
  • GAID 获取(协程方式)
  • GAID 获取(同步方式)
  • 追踪限制状态检测
  • 综合标识符获取
  • 完整的中文注释
  • 详细的使用文档
  • 隐私合规建议