import 'dart:io'; import 'package:flutter/services.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; class ModelManager { /// 当前应用版本(用于初始化检查) static String? _currentVersion; /// 获取当前应用版本 static Future _getCurrentVersion() async { if (_currentVersion == null) { final packageInfo = await PackageInfo.fromPlatform(); _currentVersion = '${packageInfo.version}+${packageInfo.buildNumber}'; } return _currentVersion!; } /// 检查3D模型资源是否已完成初始化(基于版本号) static Future isInitialized() async { final supportDir = await getApplicationSupportDirectory(); final currentVersion = await _getCurrentVersion(); final initMarker = File( p.join(supportDir.path, '3d_models', '.initialized_$currentVersion'), ); return await initMarker.exists(); } /// 标记3D模型资源初始化完成 static Future markInitialized() async { final supportDir = await getApplicationSupportDirectory(); final currentVersion = await _getCurrentVersion(); final modelsDir = Directory(p.join(supportDir.path, '3d_models')); if (!await modelsDir.exists()) { await modelsDir.create(recursive: true); } final initMarker = File( p.join(modelsDir.path, '.initialized_$currentVersion'), ); await initMarker.writeAsString('${DateTime.now().toIso8601String()}\n'); } /// 从assets目录提取文件到指定路径 static Future _extractAsset(String assetPath, String localPath) async { final localFile = File(localPath); final localDir = Directory(p.dirname(localPath)); // 确保目录存在 if (!await localDir.exists()) { await localDir.create(recursive: true); } try { // 从assets中读取数据 final ByteData data = await rootBundle.load(assetPath); final List bytes = data.buffer.asUint8List(); // 写入本地文件 await localFile.writeAsBytes(bytes); print('成功提取3D模型文件: $assetPath -> $localPath'); } catch (e) { print('提取3D模型资源文件失败 $assetPath: $e'); rethrow; } } /// 初始化3D模型资源 static Future initializeAppResources() async { final currentVersion = await _getCurrentVersion(); if (await isInitialized()) { print('3D模型资源已初始化,当前版本: $currentVersion'); return; } try { // 迁移模型文件 await _migrateModels(); // 标记初始化完成 await markInitialized(); print('3D模型资源初始化完成'); } catch (e) { print('3D模型资源初始化失败: $e'); rethrow; } } /// 迁移3D模型文件 /// 迁移3D模型文件 static Future _migrateModels() async { print('开始迁移3D模型文件...'); final supportDir = await getApplicationSupportDirectory(); final modelsDir = Directory(p.join(supportDir.path, 'models')); // 创建3D模型目录 if (!await modelsDir.exists()) { await modelsDir.create(recursive: true); } // 创建cup子目录 final cupDir = Directory(p.join(modelsDir.path, 'cup')); if (!await cupDir.exists()) { await cupDir.create(recursive: true); } // 3D模型文件列表 - 修正路径 final modelFiles = [ 'cup/model.gltf', 'cup/model.bin', 'cup/texture.jpg', ]; // 迁移所有3D模型文件 for (final modelFile in modelFiles) { try { // 确保源文件路径正确 final assetPath = 'assets/$modelFile'; // 检查资源是否存在 try { await rootBundle.load(assetPath); } catch (e) { print('资源文件不存在: $assetPath'); continue; } await _extractAsset( assetPath, p.join(modelsDir.path, modelFile), ); } catch (e) { print('迁移3D模型文件失败 $modelFile: $e'); // 继续迁移其他模型文件 } } print('3D模型文件迁移完成'); } /// 获取3D模型文件目录路径 static Future getModelsPath() async { final supportDir = await getApplicationSupportDirectory(); return p.join(supportDir.path, 'models/cup/'); } /// 获取特定3D模型文件的路径 static Future getModelFilePath(String relativePath) async { final modelsPath = await getModelsPath(); final filePath = p.join(modelsPath, relativePath); final file = File(filePath); if (!await file.exists()) { throw FileSystemException( '3D模型文件不存在: $filePath\n请确保应用程序已正确初始化3D模型资源', filePath, ); } return filePath; } /// 获取GLTF模型文件路径 static Future getGltfModelPath() async { return getModelFilePath('cup/model.gltf'); } /// 获取BIN模型文件路径 static Future getBinModelPath() async { return getModelFilePath('cup/model.bin'); } /// 获取纹理文件路径 static Future getTexturePath() async { return getModelFilePath('cup/texture.jpg'); } /// 更新纹理文件 static Future updateTexture(File newTextureFile) async { try { final texturePath = await getTexturePath(); final textureFile = File(texturePath); // 删除旧纹理文件 if (await textureFile.exists()) { await textureFile.delete(); } // 复制新纹理文件 await newTextureFile.copy(texturePath); print('纹理文件更新成功: $texturePath'); } catch (e) { print('更新纹理文件失败: $e'); rethrow; } } }