// lib/utils/device_manager.dart import 'dart:io'; import 'dart:convert'; import 'package:crypto/crypto.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:get/get.dart'; import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart'; import 'package:uuid/uuid.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import '../app/data/sp/ix_sp.dart'; import 'log/logger.dart'; import 'permission_manager.dart'; class DeviceManager { static const String TAG = 'DeviceManager'; static final DeviceInfoPlugin _deviceInfo = DeviceInfoPlugin(); static const String _folderPrefix = '.omon_cache_'; static const String _iosDeviceIdKey = 'omon_device_id'; static const String _iosDeviceFolderKey = 'omon_device_folder'; /// 获取设备唯一标识并确保文件夹存在 static Future getDeviceId() async { try { // 1. 先从 SharedPreferences 获取 String? deviceId = IXSP.getDeviceId(); // 2. 如果SP中没有,尝试从存储位置获取 if (deviceId == null || deviceId.isEmpty) { try { deviceId = await _getDeviceIdFromStorage(); } catch (e) { log(TAG, 'Error reading from storage: $e'); } } // 3. 如果还是没有,生成新的 if (deviceId == null || deviceId.isEmpty) { try { deviceId = await _generateNewDeviceId(); } catch (e) { log(TAG, 'Error generating device ID: $e'); deviceId = _generateFallbackId(); } } // 4. 确保保存到存储位置 try { await _saveDeviceId(deviceId); } catch (e) { log(TAG, 'Error saving device ID: $e'); } // 5. 尝试创建文件夹(仅Android),但不影响返回结果 try { await _ensureDeviceFolder(deviceId); } catch (e) { log(TAG, 'Error creating folder: $e'); // 文件夹创建失败不影响 ID 的使用 } return deviceId; } catch (e) { log(TAG, 'Critical error in getDeviceId: $e'); // 最后的后备方案:生成随机ID final fallbackId = _generateFallbackId(); try { await _saveDeviceId(fallbackId); } catch (e) { log(TAG, 'Error saving fallback ID: $e'); } return fallbackId; } } /// 获取缓存 static String getCacheDeviceId() { return IXSP.getDeviceId() ?? ''; } /// 从存储位置获取设备ID static Future _getDeviceIdFromStorage() async { if (Platform.isIOS) { // iOS 从钥匙串获取 try { const storage = FlutterSecureStorage(); final deviceId = await storage.read(key: _iosDeviceIdKey); if (deviceId != null && deviceId.isNotEmpty) { await IXSP.setDeviceId(deviceId); return deviceId; } } catch (e) { log(TAG, 'Error reading from iOS keychain: $e'); } } else { // Android 从文件夹获取 try { final downloadsDir = await _getDownloadsDirectory(); if (downloadsDir == null || !await downloadsDir.exists()) { return null; } final entities = await downloadsDir.list().toList(); for (var entity in entities) { if (entity is Directory) { final folderName = path.basename(entity.path); if (folderName.startsWith(_folderPrefix)) { final uuid = folderName.substring(_folderPrefix.length); // 验证UUID格式 if (_isValidUuid(uuid)) { // 找到有效的UUID,保存到SP await IXSP.setDeviceId(uuid); return uuid; } } } } } catch (e) { log(TAG, 'Error getting device ID from Android folder: $e'); } } return null; } /// 保存设备ID到存储位置 static Future _saveDeviceId(String deviceId) async { // 保存到 SharedPreferences(跨平台) await IXSP.setDeviceId(deviceId); if (Platform.isIOS) { // iOS 保存到钥匙串 try { const storage = FlutterSecureStorage(); await storage.write(key: _iosDeviceIdKey, value: deviceId); } catch (e) { log(TAG, 'Error saving to iOS keychain: $e'); } } } /// 生成新的设备ID static Future _generateNewDeviceId() async { if (GetPlatform.isAndroid) { final AndroidDeviceInfo androidInfo = await _deviceInfo.androidInfo; final deviceInfo = { 'androidId': androidInfo.id, 'brand': androidInfo.brand, 'model': androidInfo.model, 'product': androidInfo.product, 'hardware': androidInfo.hardware, 'manufacturer': androidInfo.manufacturer, 'uuid': const Uuid().v4(), }; final deviceId = _generateHash(jsonEncode(deviceInfo)); await _saveDeviceId(deviceId); return deviceId; } else if (GetPlatform.isIOS) { final IosDeviceInfo iosInfo = await _deviceInfo.iosInfo; final deviceInfo = { 'identifierForVendor': iosInfo.identifierForVendor, 'model': iosInfo.model, 'systemVersion': iosInfo.systemVersion, 'uuid': const Uuid().v4(), }; final deviceId = _generateHash(jsonEncode(deviceInfo)); await _saveDeviceId(deviceId); return deviceId; } return _generateFallbackId(); } /// 确保设备文件夹存在 static Future _ensureDeviceFolder(String deviceId) async { // iOS 不需要创建文件夹,数据存储在钥匙串中 if (Platform.isIOS) { return; } try { final downloadsDir = await _getDownloadsDirectory(); if (downloadsDir == null || !await downloadsDir.exists()) { throw Exception('Downloads directory not found'); } final folderName = '$_folderPrefix$deviceId'; final deviceFolder = Directory('${downloadsDir.path}/$folderName'); if (!await deviceFolder.exists()) { await deviceFolder.create(); // 创建.nomedia文件 final nomedia = File('${deviceFolder.path}/.nomedia'); await nomedia.create(); } } catch (e) { log(TAG, 'Error ensuring device folder: $e'); rethrow; } } /// 获取下载目录 static Future _getDownloadsDirectory() async { if (Platform.isAndroid) { try { // 首先尝试获取应用的外部存储目录 // 判断是不是Android10以下 final hasPermission = await PermissionManager.requestStoragePermission(); if (!hasPermission) { throw Exception('Storage permission denied'); } final downloadsDir = Directory('/storage/emulated/0/Download'); return downloadsDir; } catch (e) { log(TAG, 'Error getting downloads directory: $e'); final downloadsDir = getExternalStorageDirectory(); return downloadsDir; } } return null; } /// 生成哈希值 static String _generateHash(String input) { final bytes = utf8.encode(input); final digest = md5.convert(bytes); return digest.toString(); } /// 生成后备ID static String _generateFallbackId() { final random = DateTime.now().millisecondsSinceEpoch.toString(); return _generateHash(random); } /// 验证UUID格式 static bool _isValidUuid(String uuid) { // 验证是否为32位十六进制字符 return RegExp(r'^[a-f0-9]{32}$').hasMatch(uuid); } /// 获取设备文件夹路径 static Future getDeviceFolderPath() async { if (Platform.isIOS) { // iOS 返回钥匙串标识符 return 'iOS Keychain: $_iosDeviceIdKey'; } final deviceId = await getDeviceId(); return '/storage/emulated/0/Download/$_folderPrefix$deviceId'; } /// 清除所有数据 static Future clearAll() async { try { if (Platform.isIOS) { // iOS 清除钥匙串数据 try { const storage = FlutterSecureStorage(); await storage.delete(key: _iosDeviceIdKey); await storage.delete(key: _iosDeviceFolderKey); } catch (e) { log(TAG, 'Error clearing iOS keychain: $e'); } } else { // Android 删除文件夹 try { final downloadsDir = await _getDownloadsDirectory(); if (downloadsDir != null && await downloadsDir.exists()) { final entities = await downloadsDir.list().toList(); for (var entity in entities) { if (entity is Directory) { final folderName = path.basename(entity.path); if (folderName.startsWith(_folderPrefix)) { await entity.delete(recursive: true); } } } } } catch (e) { log(TAG, 'Error clearing Android folders: $e'); } } // 清除 SP 中的 UUID await IXSP.setDeviceId(''); } catch (e) { log(TAG, 'Error clearing device data: $e'); } } }