14 KiB
14 KiB
设备信息收集和上传使用指南
概述
本功能提供了完整的设备信息收集、序列化、加密和上传功能。所有信息收集都是异步并发执行,性能优化且不会阻塞主线程。
功能特性
1. 信息收集模块
自动收集以下 24 类设备信息:
- CPU 信息
- GPU 信息
- 屏幕信息
- 内存信息
- 磁盘信息
- 网络信息
- 电池信息
- 设备信息
- 应用信息
- 系统信息
- 定位信息
- 相机信息
- 传感器信息
- 系统属性
- 蓝牙信息
- WiFi 信息
- NFC 信息
- USB 信息
- 构建信息
- DRM 信息
- 输入设备信息
- Device ID
- GAID
2. 数据处理流程
- 异步收集 - 并发收集所有信息,提高性能
- JSON 序列化 - 将所有信息转换为 JSON 格式
- AES 加密 - 使用 AES 加密保护数据
- HTTP POST - 发送加密数据到服务器
- 响应处理 - 解析服务器响应
使用方法
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.Default或Dispatchers.IO - 加密操作:使用
Dispatchers.Default - 网络请求:使用
Dispatchers.IO
错误处理
常见错误及解决方案
- 网络错误
// 错误: java.net.UnknownHostException
// 解决: 检查网络连接和URL是否正确
- 加密错误
// 错误: 加密失败
// 解决: 检查密钥长度是否为16/24/32字节
- 序列化错误
// 错误: JSON解析失败
// 解决: 确保所有收集方法返回有效的JSON字符串
注意事项
-
隐私合规:
- 确保用户知情并同意收集设备信息
- 遵守 GDPR、CCPA 等隐私法规
- 在隐私政策中说明数据用途
-
网络使用:
- 建议在 WiFi 环境下上传
- 可以添加网络类型检测
-
频率控制:
- 不要频繁上传
- 建议每天或每周上传一次
-
错误重试:
- 失败时可以实现重试机制
- 保存失败的数据,下次再试
完整示例
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
- ✅ 详细的中文注释