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