12 KiB
12 KiB
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 获取(同步方式)✅
- 追踪限制状态检测 ✅
- 综合标识符获取 ✅
- 完整的中文注释 ✅
- 详细的使用文档 ✅
- 隐私合规建议 ✅