# 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. 初始化 ```kotlin import com.xyzshell.andinfo.AndInfo // 在 Application 或 Activity 中初始化 AndInfo.init(applicationContext) // 获取 DeviceInfo 实例 val deviceInfo = AndInfo.instance.device ``` ### 2. 获取 Android ID (Device ID) #### 基本使用 ```kotlin // 获取 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 - **权限**: 不需要特殊权限 #### 适用场景 ```kotlin // 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) #### 协程方式(推荐) ```kotlin 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 中使用 ```kotlin 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 } } } } ``` #### 同步方式(不推荐) ```kotlin // ⚠️ 警告:会阻塞当前线程,不要在主线程调用 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. 获取所有设备标识符 ```kotlin // 一次性获取所有标识符 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. 完整示例:设备信息收集 ```kotlin 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 ```kotlin /** * 广告标识符信息数据类 */ data class AdvertisingIdInfo( val id: String, // GAID val isLimitAdTrackingEnabled: Boolean // 是否限制广告追踪 ) ``` ### DeviceIdentifiers ```kotlin /** * 设备标识符集合数据类 */ 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. 广告归因 ```kotlin 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. 用户设备管理 ```kotlin 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. 防作弊检测 ```kotlin suspend fun checkDeviceFraud(): Boolean { val deviceInfo = AndInfo.instance.device val androidId = deviceInfo.getAndroidId() // 检查设备是否被标记为作弊 return fraudDetectionService.isDeviceFlagged(androidId) } ``` ### 4. A/B 测试分组 ```kotlin 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. 隐私合规检查 ```kotlin 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` 中添加依赖: ```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. 最佳实践 ```kotlin 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 获取(同步方式)✅ - 追踪限制状态检测 ✅ - 综合标识符获取 ✅ - 完整的中文注释 ✅ - 详细的使用文档 ✅ - 隐私合规建议 ✅