hi-client/lib/app/services/kr_device_info_service.dart

483 lines
16 KiB
Dart
Raw 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.

import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_udid/flutter_udid.dart';
import '../utils/kr_secure_storage.dart';
import '../utils/kr_log_util.dart';
import 'package:crypto/crypto.dart';
import 'dart:convert';
/// 设备信息服务
/// 用于获取设备唯一标识和其他设备信息
class KRDeviceInfoService {
static final KRDeviceInfoService _instance = KRDeviceInfoService._internal();
factory KRDeviceInfoService() => _instance;
KRDeviceInfoService._internal();
final DeviceInfoPlugin _deviceInfo = DeviceInfoPlugin();
String? _deviceId;
Map<String, dynamic>? _deviceDetails;
// 获取设备唯一标识
String? get deviceId => _deviceId;
// 获取设备详细信息
Map<String, dynamic>? get deviceDetails => _deviceDetails;
/// 初始化设备信息
Future<void> initialize() async {
try {
if (kDebugMode) {
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
print('📱 开始初始化设备信息服务');
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
}
KRLogUtil.kr_i('📱 开始初始化设备信息', tag: 'KRDeviceInfoService');
_deviceId = await _getDeviceId();
_deviceDetails = await _getDeviceDetails();
if (kDebugMode) {
print('✅ 设备信息初始化成功');
print('📱 设备ID: $_deviceId');
print('📱 设备平台: ${getPlatformName()}');
print('📱 设备型号: ${getDeviceModel()}');
print('📱 系统版本: ${getOSVersion()}');
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
}
KRLogUtil.kr_i('✅ 设备信息初始化成功', tag: 'KRDeviceInfoService');
KRLogUtil.kr_i('📱 设备ID - $_deviceId', tag: 'KRDeviceInfoService');
KRLogUtil.kr_i('📱 设备详情 - $_deviceDetails', tag: 'KRDeviceInfoService');
} catch (e) {
if (kDebugMode) {
print('❌ 设备信息初始化失败: $e');
}
KRLogUtil.kr_e('❌ 设备信息初始化失败 - $e', tag: 'KRDeviceInfoService');
}
}
/// 获取设备唯一标识
/// 使用多因子组合策略确保唯一性和稳定性
Future<String> _getDeviceId() async {
try {
String identifier;
if (Platform.isAndroid) {
identifier = await _getAndroidDeviceId();
} else if (Platform.isIOS) {
identifier = await _getIOSDeviceId();
} else if (Platform.isMacOS) {
identifier = await _getMacOSDeviceId();
} else if (Platform.isWindows) {
identifier = await _getWindowsDeviceId();
} else if (Platform.isLinux) {
identifier = await _getLinuxDeviceId();
} else {
// Web或其他平台,使用生成的UUID
identifier = await _getOrCreateStoredDeviceId();
}
// 如果获取失败,使用存储的或生成新的ID
if (identifier.isEmpty) {
identifier = await _getOrCreateStoredDeviceId();
}
return identifier;
} catch (e) {
if (kDebugMode) {
print('❌ 获取设备ID失败: $e');
}
KRLogUtil.kr_e('❌ 获取设备ID失败 - $e', tag: 'KRDeviceInfoService');
// 如果获取失败,返回存储的或生成新的ID
return await _getOrCreateStoredDeviceId();
}
}
/// Android设备ID - 多因子组合
/// 组合: AndroidID + 设备型号 + 主板信息 + 硬件信息
Future<String> _getAndroidDeviceId() async {
try {
final androidInfo = await _deviceInfo.androidInfo;
// 优先使用 flutter_udid (封装了多种Android标识获取方式)
String udid = await FlutterUdid.consistentUdid;
// 构建多因子字符串
final factors = [
udid,
androidInfo.id, // Android ID
androidInfo.board, // 主板
androidInfo.bootloader, // Bootloader
androidInfo.brand, // 品牌
androidInfo.device, // 设备名
androidInfo.fingerprint, // 系统指纹
androidInfo.hardware, // 硬件名
androidInfo.manufacturer, // 制造商
androidInfo.model, // 型号
androidInfo.product, // 产品名
];
// 过滤空值并组合
final combined = factors
.where((f) => f != null && f.isNotEmpty)
.join('|');
// 生成SHA256哈希
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
if (kDebugMode) {
print('📱 Android多因子ID生成 - 因子数: ${factors.where((f) => f != null && f.isNotEmpty).length}');
}
KRLogUtil.kr_i('📱 Android多因子ID - $hash', tag: 'KRDeviceInfoService');
return hash.toString();
} catch (e) {
if (kDebugMode) {
print('❌ Android设备ID获取失败: $e');
}
KRLogUtil.kr_e('❌ Android设备ID获取失败 - $e', tag: 'KRDeviceInfoService');
return '';
}
}
/// iOS设备ID - 优先使用identifierForVendor,配合持久化存储
/// iOS限制较严,无法获取IMEI等敏感信息
Future<String> _getIOSDeviceId() async {
try {
final iosInfo = await _deviceInfo.iosInfo;
// 优先使用 flutter_udid
String udid = await FlutterUdid.consistentUdid;
// 构建多因子字符串
final factors = [
udid,
iosInfo.identifierForVendor ?? '', // Vendor标识
iosInfo.model, // 型号
iosInfo.systemName, // 系统名
iosInfo.systemVersion, // 系统版本
iosInfo.name, // 设备名(如"iPhone 14 Pro")
iosInfo.utsname.machine, // 机器类型
];
final combined = factors
.where((f) => f.isNotEmpty)
.join('|');
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
if (kDebugMode) {
print('📱 iOS多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
}
KRLogUtil.kr_i('📱 iOS多因子ID - $hash', tag: 'KRDeviceInfoService');
return hash.toString();
} catch (e) {
if (kDebugMode) {
print('❌ iOS设备ID获取失败: $e');
}
KRLogUtil.kr_e('❌ iOS设备ID获取失败 - $e', tag: 'KRDeviceInfoService');
return '';
}
}
/// macOS设备ID - 使用硬件UUID
Future<String> _getMacOSDeviceId() async {
try {
final macInfo = await _deviceInfo.macOsInfo;
// 优先使用 flutter_udid
String udid = await FlutterUdid.consistentUdid;
// 构建多因子字符串
final factors = [
udid,
macInfo.systemGUID ?? '', // 系统GUID (最稳定)
macInfo.model, // 型号
macInfo.hostName, // 主机名
macInfo.arch, // 架构
macInfo.kernelVersion, // 内核版本
];
final combined = factors
.where((f) => f.isNotEmpty)
.join('|');
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
if (kDebugMode) {
print('📱 macOS多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
}
KRLogUtil.kr_i('📱 macOS多因子ID - $hash', tag: 'KRDeviceInfoService');
return hash.toString();
} catch (e) {
if (kDebugMode) {
print('❌ macOS设备ID获取失败: $e');
}
KRLogUtil.kr_e('❌ macOS设备ID获取失败 - $e', tag: 'KRDeviceInfoService');
return '';
}
}
/// Windows设备ID - 使用机器GUID
/// 🔧 修复:不使用 flutter_udid因为它会调用 wmic 命令弹出黑窗口
Future<String> _getWindowsDeviceId() async {
try {
final windowsInfo = await _deviceInfo.windowsInfo;
// 🔧 修复:不使用 FlutterUdid.consistentUdid
// 因为它在 Windows 上会调用 "cmd.exe /c wmic csproduct get UUID"
// 这个调用没有使用 CREATE_NO_WINDOW 标志,会弹出黑色命令行窗口
// 直接使用 device_info_plus 提供的信息构建唯一标识
// windowsInfo.deviceId 已经是一个稳定的设备标识
// 构建多因子字符串
final factors = [
windowsInfo.deviceId, // 设备ID (最稳定,来自注册表 MachineGuid)
windowsInfo.computerName, // 计算机名
windowsInfo.productName, // 产品名
windowsInfo.numberOfCores.toString(), // CPU核心数
windowsInfo.systemMemoryInMegabytes.toString(), // 内存大小
];
final combined = factors
.where((f) => f.isNotEmpty)
.join('|');
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
if (kDebugMode) {
print('📱 Windows多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
}
KRLogUtil.kr_i('📱 Windows多因子ID - $hash', tag: 'KRDeviceInfoService');
return hash.toString();
} catch (e) {
if (kDebugMode) {
print('❌ Windows设备ID获取失败: $e');
}
KRLogUtil.kr_e('❌ Windows设备ID获取失败 - $e', tag: 'KRDeviceInfoService');
return '';
}
}
/// Linux设备ID - 使用machine-id
Future<String> _getLinuxDeviceId() async {
try {
final linuxInfo = await _deviceInfo.linuxInfo;
// 优先使用 flutter_udid
String udid = await FlutterUdid.consistentUdid;
// 构建多因子字符串
final factors = [
udid,
linuxInfo.machineId ?? '', // Machine ID (最稳定)
linuxInfo.id, // 发行版ID
linuxInfo.name, // 发行版名称
linuxInfo.version ?? '', // 版本
linuxInfo.variant ?? '', // 变体
];
final combined = factors
.where((f) => f.isNotEmpty)
.join('|');
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
if (kDebugMode) {
print('📱 Linux多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
}
KRLogUtil.kr_i('📱 Linux多因子ID - $hash', tag: 'KRDeviceInfoService');
return hash.toString();
} catch (e) {
if (kDebugMode) {
print('❌ Linux设备ID获取失败: $e');
}
KRLogUtil.kr_e('❌ Linux设备ID获取失败 - $e', tag: 'KRDeviceInfoService');
return '';
}
}
/// 获取或创建存储的设备ID
Future<String> _getOrCreateStoredDeviceId() async {
try {
const key = 'kr_device_unique_id';
final storage = KRSecureStorage();
String? storedId = await storage.kr_readData(key: key);
if (storedId == null || storedId.isEmpty) {
// 生成新的UUID
storedId = _generateUniqueId();
await storage.kr_saveData(key: key, value: storedId);
if (kDebugMode) {
print('📱 生成新的设备ID: $storedId');
}
KRLogUtil.kr_i('📱 生成新的设备ID - $storedId', tag: 'KRDeviceInfoService');
} else {
if (kDebugMode) {
print('📱 使用存储的设备ID: $storedId');
}
KRLogUtil.kr_i('📱 使用存储的设备ID - $storedId', tag: 'KRDeviceInfoService');
}
return storedId;
} catch (e) {
if (kDebugMode) {
print('❌ 获取存储的设备ID失败: $e');
}
KRLogUtil.kr_e('❌ 获取存储的设备ID失败 - $e', tag: 'KRDeviceInfoService');
return _generateUniqueId();
}
}
/// 生成唯一ID
String _generateUniqueId() {
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
final random = DateTime.now().microsecondsSinceEpoch.toString();
final combined = '$timestamp-$random';
// 使用MD5生成唯一标识
final bytes = utf8.encode(combined);
final digest = md5.convert(bytes);
return digest.toString();
}
/// 获取设备详细信息
Future<Map<String, dynamic>> _getDeviceDetails() async {
try {
if (Platform.isAndroid) {
final androidInfo = await _deviceInfo.androidInfo;
return {
'platform': 'android',
'device': androidInfo.device,
'model': androidInfo.model,
'brand': androidInfo.brand,
'manufacturer': androidInfo.manufacturer,
'androidId': androidInfo.id,
'version': androidInfo.version.release,
'sdkInt': androidInfo.version.sdkInt,
};
} else if (Platform.isIOS) {
final iosInfo = await _deviceInfo.iosInfo;
return {
'platform': 'ios',
'name': iosInfo.name,
'model': iosInfo.model,
'systemName': iosInfo.systemName,
'systemVersion': iosInfo.systemVersion,
'identifierForVendor': iosInfo.identifierForVendor,
'isPhysicalDevice': iosInfo.isPhysicalDevice,
};
} else if (Platform.isMacOS) {
final macInfo = await _deviceInfo.macOsInfo;
return {
'platform': 'macos',
'computerName': macInfo.computerName,
'model': macInfo.model,
'hostName': macInfo.hostName,
'arch': macInfo.arch,
'systemGUID': macInfo.systemGUID,
};
} else if (Platform.isWindows) {
final windowsInfo = await _deviceInfo.windowsInfo;
return {
'platform': 'windows',
'computerName': windowsInfo.computerName,
'numberOfCores': windowsInfo.numberOfCores,
'systemMemoryInMegabytes': windowsInfo.systemMemoryInMegabytes,
};
} else if (Platform.isLinux) {
final linuxInfo = await _deviceInfo.linuxInfo;
return {
'platform': 'linux',
'name': linuxInfo.name,
'version': linuxInfo.version,
'id': linuxInfo.id,
'machineId': linuxInfo.machineId,
};
} else if (kIsWeb) {
final webInfo = await _deviceInfo.webBrowserInfo;
return {
'platform': 'web',
'browserName': webInfo.browserName.toString(),
'userAgent': webInfo.userAgent,
'vendor': webInfo.vendor,
};
}
return {
'platform': 'unknown',
};
} catch (e) {
if (kDebugMode) {
print('❌ 获取设备详情失败: $e');
}
KRLogUtil.kr_e('❌ 获取设备详情失败 - $e', tag: 'KRDeviceInfoService');
return {
'platform': 'unknown',
'error': e.toString(),
};
}
}
/// 获取平台名称
String getPlatformName() {
if (Platform.isAndroid) return 'Android';
if (Platform.isIOS) return 'iOS';
if (Platform.isMacOS) return 'macOS';
if (Platform.isWindows) return 'Windows';
if (Platform.isLinux) return 'Linux';
if (kIsWeb) return 'Web';
return 'Unknown';
}
/// 获取设备型号
String getDeviceModel() {
if (_deviceDetails == null) return 'Unknown';
if (Platform.isAndroid) {
return '${_deviceDetails!['brand']} ${_deviceDetails!['model']}';
} else if (Platform.isIOS) {
return _deviceDetails!['model'] ?? 'Unknown';
} else if (Platform.isMacOS) {
return _deviceDetails!['model'] ?? 'Unknown';
}
return 'Unknown';
}
/// 获取操作系统版本
String getOSVersion() {
if (_deviceDetails == null) return 'Unknown';
if (Platform.isAndroid) {
return _deviceDetails!['version'] ?? 'Unknown';
} else if (Platform.isIOS) {
return _deviceDetails!['systemVersion'] ?? 'Unknown';
}
return 'Unknown';
}
/// 获取User-Agent信息
String getUserAgent() {
final platform = getPlatformName();
final model = getDeviceModel();
final osVersion = getOSVersion();
return 'HiVPN/1.0.0 ($platform; $model; $osVersion) Flutter';
}
}