529 lines
14 KiB
Markdown
529 lines
14 KiB
Markdown
# 设备信息收集和上传使用指南
|
||
|
||
## 概述
|
||
本功能提供了完整的设备信息收集、序列化、加密和上传功能。所有信息收集都是异步并发执行,性能优化且不会阻塞主线程。
|
||
|
||
## 功能特性
|
||
|
||
### 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
|
||
- ✅ 详细的中文注释
|
||
|