DevCheck-lib/设备信息收集和上传使用指南.md
2025-12-24 15:32:35 +08:00

14 KiB
Raw Blame History

设备信息收集和上传使用指南

概述

本功能提供了完整的设备信息收集、序列化、加密和上传功能。所有信息收集都是异步并发执行,性能优化且不会阻塞主线程。

功能特性

1. 信息收集模块

自动收集以下 24 类设备信息:

  • CPU 信息
  • GPU 信息
  • 屏幕信息
  • 内存信息
  • 磁盘信息
  • 网络信息
  • 电池信息
  • 设备信息
  • 应用信息
  • 系统信息
  • 定位信息
  • 相机信息
  • 传感器信息
  • 系统属性
  • 蓝牙信息
  • WiFi 信息
  • NFC 信息
  • USB 信息
  • 构建信息
  • DRM 信息
  • 输入设备信息
  • Device ID
  • GAID

2. 数据处理流程

  1. 异步收集 - 并发收集所有信息,提高性能
  2. JSON 序列化 - 将所有信息转换为 JSON 格式
  3. AES 加密 - 使用 AES 加密保护数据
  4. HTTP POST - 发送加密数据到服务器
  5. 响应处理 - 解析服务器响应

使用方法

1. 基本使用

import androidx.lifecycle.lifecycleScope
import com.xyzshell.andinfo.AndInfo
import com.xyzshell.andinfo.collector.DeviceInfoCollector
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 初始化 AndInfo
        AndInfo.init(applicationContext)
        
        // 收集并上传设备信息
        uploadDeviceInfo()
    }
    
    private fun uploadDeviceInfo() {
        lifecycleScope.launch {
            val collector = DeviceInfoCollector(applicationContext)
            
            collector.collectAndUpload { message, error ->
                if (error != null) {
                    // 上传失败
                    runOnUiThread {
                        Toast.makeText(
                            this@MainActivity,
                            "上传失败: ${error.message}",
                            Toast.LENGTH_LONG
                        ).show()
                    }
                } else {
                    // 上传成功
                    runOnUiThread {
                        Toast.makeText(
                            this@MainActivity,
                            "上传成功: $message",
                            Toast.LENGTH_SHORT
                        ).show()
                    }
                }
            }
        }
    }
}

2. 仅收集信息(不上传)

lifecycleScope.launch {
    val collector = DeviceInfoCollector(applicationContext)
    
    // 仅收集信息,不上传
    val deviceInfo = collector.collectAllInfo()
    
    // 转换为 JSON 查看
    val json = collector.gson.toJson(deviceInfo)
    println("设备信息: $json")
}

3. 在 ViewModel 中使用

class DeviceInfoViewModel : ViewModel() {
    private val _uploadStatus = MutableLiveData<UploadStatus>()
    val uploadStatus: LiveData<UploadStatus> = _uploadStatus
    
    fun uploadDeviceInfo(context: Context) {
        viewModelScope.launch {
            _uploadStatus.value = UploadStatus.Loading
            
            val collector = DeviceInfoCollector(context)
            
            collector.collectAndUpload { message, error ->
                if (error != null) {
                    _uploadStatus.postValue(UploadStatus.Error(error.message ?: "上传失败"))
                } else {
                    _uploadStatus.postValue(UploadStatus.Success(message ?: "上传成功"))
                }
            }
        }
    }
}

sealed class UploadStatus {
    object Loading : UploadStatus()
    data class Success(val message: String) : UploadStatus()
    data class Error(val message: String) : UploadStatus()
}

4. 带进度显示的上传

class UploadActivity : AppCompatActivity() {
    private lateinit var progressDialog: ProgressDialog
    
    private fun uploadWithProgress() {
        // 显示进度对话框
        progressDialog = ProgressDialog(this).apply {
            setMessage("正在收集设备信息...")
            setCancelable(false)
            show()
        }
        
        lifecycleScope.launch {
            val collector = DeviceInfoCollector(applicationContext)
            
            // 更新进度
            progressDialog.setMessage("正在上传...")
            
            collector.collectAndUpload { message, error ->
                runOnUiThread {
                    progressDialog.dismiss()
                    
                    if (error != null) {
                        AlertDialog.Builder(this@UploadActivity)
                            .setTitle("上传失败")
                            .setMessage(error.message)
                            .setPositiveButton("确定", null)
                            .show()
                    } else {
                        AlertDialog.Builder(this@UploadActivity)
                            .setTitle("上传成功")
                            .setMessage(message)
                            .setPositiveButton("确定", null)
                            .show()
                    }
                }
            }
        }
    }
}

5. 定时自动上传

class AutoUploadService : Service() {
    private val uploadInterval = 24 * 60 * 60 * 1000L // 24小时
    private val handler = Handler(Looper.getMainLooper())
    
    private val uploadRunnable = object : Runnable {
        override fun run() {
            uploadDeviceInfo()
            handler.postDelayed(this, uploadInterval)
        }
    }
    
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        handler.post(uploadRunnable)
        return START_STICKY
    }
    
    private fun uploadDeviceInfo() {
        CoroutineScope(Dispatchers.IO).launch {
            val collector = DeviceInfoCollector(applicationContext)
            
            collector.collectAndUpload { message, error ->
                if (error != null) {
                    Log.e("AutoUpload", "上传失败: ${error.message}")
                } else {
                    Log.i("AutoUpload", "上传成功: $message")
                }
            }
        }
    }
    
    override fun onDestroy() {
        handler.removeCallbacks(uploadRunnable)
        super.onDestroy()
    }
    
    override fun onBind(intent: Intent?): IBinder? = null
}

API 接口说明

请求格式

URL: https://api.xyzshell.com/api/mobile/checker/save

Method: POST

Content-Type: application/json

请求体:

{
  "encrypted": "AES加密后的Base64字符串"
}

加密前的数据格式:

{
  "cpuInfo": "{\"processorName\":\"ARM\",\"cores\":8}",
  "gpuInfo": "{\"vendor\":\"Qualcomm\",\"renderer\":\"Adreno 650\"}",
  "screenInfo": "{\"width\":1080,\"height\":2400}",
  "memoryInfo": "{\"totalMem\":8589934592}",
  "diskInfo": "{\"totalSpace\":128000000000}",
  "networkInfo": "{}",
  "batteryInfo": "{\"level\":85,\"status\":3}",
  "deviceInfo": "{\"brand\":\"Samsung\",\"model\":\"SM-G998B\"}",
  "appInfo": "{}",
  "systemInfo": "{\"androidVersion\":\"13\",\"sdkInt\":33}",
  "locationInfo": "{\"gpsSupported\":true}",
  "cameraInfo": "{\"cameraCount\":4}",
  "sensorInfo": "{\"sensorCount\":20}",
  "propsInfo": "{}",
  "bluetoothInfo": "{\"supported\":true,\"enabled\":true}",
  "wifiInfo": "{}",
  "nfcInfo": "{\"supported\":true}",
  "usbInfo": "{\"hostSupported\":true}",
  "buildInfo": "{\"trebleEnabled\":true}",
  "deviceId": "9774d56d682e549c",
  "deviceName": "Samsung SM-G998B",
  "drmInfo": "{\"supportedSchemes\":2}",
  "inputInfo": "{\"deviceCount\":3}",
  "gaid": "38400000-8cf0-11bd-b23e-10b96e40000d"
}

响应格式

成功响应:

{
  "data": null,
  "message": "设备信息保存成功",
  "status": "Success"
}

失败响应:

{
  "data": null,
  "message": "错误详情信息",
  "status": "Fail"
}

数据模型

DeviceInfoRequest

data class DeviceInfoRequest(
    val cpuInfo: String,           // CPU信息JSON
    val gpuInfo: String,           // GPU信息JSON
    val screenInfo: String,        // 屏幕信息JSON
    val memoryInfo: String,        // 内存信息JSON
    val diskInfo: String,          // 磁盘信息JSON
    val networkInfo: String,       // 网络信息JSON
    val batteryInfo: String,       // 电池信息JSON
    val deviceInfo: String,        // 设备信息JSON
    val appInfo: String,           // 应用信息JSON
    val systemInfo: String,        // 系统信息JSON
    val locationInfo: String,      // 定位信息JSON
    val cameraInfo: String,        // 相机信息JSON
    val sensorInfo: String,        // 传感器信息JSON
    val propsInfo: String,         // 系统属性JSON
    val bluetoothInfo: String,     // 蓝牙信息JSON
    val wifiInfo: String,          // WiFi信息JSON
    val nfcInfo: String,           // NFC信息JSON
    val usbInfo: String,           // USB信息JSON
    val buildInfo: String,         // 构建信息JSON
    val deviceId: String,          // 设备ID
    val deviceName: String,        // 设备名称
    val drmInfo: String,           // DRM信息JSON
    val inputInfo: String,         // 输入信息JSON
    val gaid: String               // Google广告ID
)

EncryptedRequest

data class EncryptedRequest(
    val encrypted: String  // AES加密后的Base64字符串
)

ApiResponse

data class ApiResponse(
    val data: Any?,       // 响应数据
    val message: String,  // 响应消息
    val status: String    // 状态: "Success" 或 "Fail"
)

加密说明

AES 加密

  • 算法: AES/ECB/PKCS5Padding
  • 密钥: "e67cbcee5e573d1b" (16字节)
  • 编码: Base64 (NO_WRAP)

加密示例

val webService = WebService()
val plainText = """{"test": "data"}"""
val encrypted = webService.encrypt(plainText)
println("加密结果: $encrypted")

权限要求

根据收集的信息类型,可能需要以下权限:

<!-- 必需权限 -->
<uses-permission android:name="android.permission.INTERNET" />

<!-- 可选权限(用于获取更多信息) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

性能优化

1. 并发收集

所有信息收集都是并发执行:

// 使用协程并发收集
val cpuInfoDeferred = async { collectCpuInfo() }
val gpuInfoDeferred = async { collectGpuInfo() }
// ... 其他信息并发收集

2. 异常处理

每个收集方法都有完善的异常处理:

private suspend fun collectCpuInfo(): String = withContext(Dispatchers.Default) {
    try {
        // 收集逻辑
    } catch (e: Exception) {
        "{}"  // 返回空JSON对象
    }
}

3. 线程调度

  • 信息收集:使用 Dispatchers.DefaultDispatchers.IO
  • 加密操作:使用 Dispatchers.Default
  • 网络请求:使用 Dispatchers.IO

错误处理

常见错误及解决方案

  1. 网络错误
// 错误: java.net.UnknownHostException
// 解决: 检查网络连接和URL是否正确
  1. 加密错误
// 错误: 加密失败
// 解决: 检查密钥长度是否为16/24/32字节
  1. 序列化错误
// 错误: JSON解析失败
// 解决: 确保所有收集方法返回有效的JSON字符串

注意事项

  1. 隐私合规

    • 确保用户知情并同意收集设备信息
    • 遵守 GDPR、CCPA 等隐私法规
    • 在隐私政策中说明数据用途
  2. 网络使用

    • 建议在 WiFi 环境下上传
    • 可以添加网络类型检测
  3. 频率控制

    • 不要频繁上传
    • 建议每天或每周上传一次
  4. 错误重试

    • 失败时可以实现重试机制
    • 保存失败的数据,下次再试

完整示例

class DeviceCheckActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_device_check)
        
        // 初始化
        AndInfo.init(applicationContext)
        
        // 检查权限后上传
        if (checkPermissions()) {
            uploadDeviceInfo()
        } else {
            requestPermissions()
        }
    }
    
    private fun uploadDeviceInfo() {
        lifecycleScope.launch {
            try {
                val collector = DeviceInfoCollector(applicationContext)
                
                // 显示加载对话框
                val dialog = ProgressDialog(this@DeviceCheckActivity)
                dialog.setMessage("正在收集设备信息...")
                dialog.show()
                
                collector.collectAndUpload { message, error ->
                    runOnUiThread {
                        dialog.dismiss()
                        
                        if (error != null) {
                            showErrorDialog(error.message ?: "上传失败")
                        } else {
                            showSuccessDialog(message ?: "上传成功")
                        }
                    }
                }
            } catch (e: Exception) {
                runOnUiThread {
                    showErrorDialog("发生错误: ${e.message}")
                }
            }
        }
    }
    
    private fun showSuccessDialog(message: String) {
        AlertDialog.Builder(this)
            .setTitle("成功")
            .setMessage(message)
            .setPositiveButton("确定", null)
            .show()
    }
    
    private fun showErrorDialog(message: String) {
        AlertDialog.Builder(this)
            .setTitle("失败")
            .setMessage(message)
            .setPositiveButton("确定", null)
            .setNegativeButton("重试") { _, _ ->
                uploadDeviceInfo()
            }
            .show()
    }
    
    private fun checkPermissions(): Boolean {
        // 检查必要权限
        return true
    }
    
    private fun requestPermissions() {
        // 请求权限
    }
}

总结

本功能提供了完整的设备信息收集和上传解决方案:

  • 异步并发收集,性能优化
  • 完整的24类设备信息
  • AES 加密保护数据
  • 完善的错误处理
  • 简单易用的 API
  • 详细的中文注释