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

529 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 设备信息收集和上传使用指南
## 概述
本功能提供了完整的设备信息收集、序列化、加密和上传功能。所有信息收集都是异步并发执行,性能优化且不会阻塞主线程。
## 功能特性
### 1. 信息收集模块
自动收集以下 24 类设备信息:
- CPU 信息
- GPU 信息
- 屏幕信息
- 内存信息
- 磁盘信息
- 网络信息
- 电池信息
- 设备信息
- 应用信息
- 系统信息
- 定位信息
- 相机信息
- 传感器信息
- 系统属性
- 蓝牙信息
- WiFi 信息
- NFC 信息
- USB 信息
- 构建信息
- DRM 信息
- 输入设备信息
- Device ID
- GAID
### 2. 数据处理流程
1. **异步收集** - 并发收集所有信息,提高性能
2. **JSON 序列化** - 将所有信息转换为 JSON 格式
3. **AES 加密** - 使用 AES 加密保护数据
4. **HTTP POST** - 发送加密数据到服务器
5. **响应处理** - 解析服务器响应
## 使用方法
### 1. 基本使用
```kotlin
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. 仅收集信息(不上传)
```kotlin
lifecycleScope.launch {
val collector = DeviceInfoCollector(applicationContext)
// 仅收集信息,不上传
val deviceInfo = collector.collectAllInfo()
// 转换为 JSON 查看
val json = collector.gson.toJson(deviceInfo)
println("设备信息: $json")
}
```
### 3. 在 ViewModel 中使用
```kotlin
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. 带进度显示的上传
```kotlin
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. 定时自动上传
```kotlin
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
**请求体**:
```json
{
"encrypted": "AES加密后的Base64字符串"
}
```
**加密前的数据格式**:
```json
{
"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"
}
```
### 响应格式
**成功响应**:
```json
{
"data": null,
"message": "设备信息保存成功",
"status": "Success"
}
```
**失败响应**:
```json
{
"data": null,
"message": "错误详情信息",
"status": "Fail"
}
```
## 数据模型
### DeviceInfoRequest
```kotlin
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
```kotlin
data class EncryptedRequest(
val encrypted: String // AES加密后的Base64字符串
)
```
### ApiResponse
```kotlin
data class ApiResponse(
val data: Any?, // 响应数据
val message: String, // 响应消息
val status: String // 状态: "Success" 或 "Fail"
)
```
## 加密说明
### AES 加密
- **算法**: AES/ECB/PKCS5Padding
- **密钥**: "e67cbcee5e573d1b" (16字节)
- **编码**: Base64 (NO_WRAP)
### 加密示例
```kotlin
val webService = WebService()
val plainText = """{"test": "data"}"""
val encrypted = webService.encrypt(plainText)
println("加密结果: $encrypted")
```
## 权限要求
根据收集的信息类型,可能需要以下权限:
```xml
<!-- 必需权限 -->
<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. 并发收集
所有信息收集都是并发执行:
```kotlin
// 使用协程并发收集
val cpuInfoDeferred = async { collectCpuInfo() }
val gpuInfoDeferred = async { collectGpuInfo() }
// ... 其他信息并发收集
```
### 2. 异常处理
每个收集方法都有完善的异常处理:
```kotlin
private suspend fun collectCpuInfo(): String = withContext(Dispatchers.Default) {
try {
// 收集逻辑
} catch (e: Exception) {
"{}" // 返回空JSON对象
}
}
```
### 3. 线程调度
- 信息收集:使用 `Dispatchers.Default``Dispatchers.IO`
- 加密操作:使用 `Dispatchers.Default`
- 网络请求:使用 `Dispatchers.IO`
## 错误处理
### 常见错误及解决方案
1. **网络错误**
```kotlin
// 错误: java.net.UnknownHostException
// 解决: 检查网络连接和URL是否正确
```
2. **加密错误**
```kotlin
// 错误: 加密失败
// 解决: 检查密钥长度是否为16/24/32字节
```
3. **序列化错误**
```kotlin
// 错误: JSON解析失败
// 解决: 确保所有收集方法返回有效的JSON字符串
```
## 注意事项
1. **隐私合规**
- 确保用户知情并同意收集设备信息
- 遵守 GDPR、CCPA 等隐私法规
- 在隐私政策中说明数据用途
2. **网络使用**
- 建议在 WiFi 环境下上传
- 可以添加网络类型检测
3. **频率控制**
- 不要频繁上传
- 建议每天或每周上传一次
4. **错误重试**
- 失败时可以实现重试机制
- 保存失败的数据,下次再试
## 完整示例
```kotlin
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
- ✅ 详细的中文注释