init
This commit is contained in:
372
examples/flutter/animations/lib/utils/binary_manager.dart
Normal file
372
examples/flutter/animations/lib/utils/binary_manager.dart
Normal file
@@ -0,0 +1,372 @@
|
||||
import 'dart:convert';
|
||||
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 BinaryManager {
|
||||
/// 当前应用版本(用于初始化检查)
|
||||
static String? _currentVersion;
|
||||
|
||||
/// 获取当前应用版本
|
||||
static Future<String> _getCurrentVersion() async {
|
||||
if (_currentVersion == null) {
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
_currentVersion = '${packageInfo.version}+${packageInfo.buildNumber}';
|
||||
}
|
||||
return _currentVersion!;
|
||||
}
|
||||
|
||||
/// 检查是否已完成初始化(基于版本号)
|
||||
static Future<bool> isInitialized() async {
|
||||
final supportDir = await getApplicationSupportDirectory();
|
||||
final currentVersion = await _getCurrentVersion();
|
||||
final initMarker = File(
|
||||
p.join(supportDir.path, '.initialized_$currentVersion'),
|
||||
);
|
||||
|
||||
return await initMarker.exists();
|
||||
}
|
||||
|
||||
/// 标记初始化完成(文件名包含版本号)
|
||||
static Future<void> markInitialized() async {
|
||||
final supportDir = await getApplicationSupportDirectory();
|
||||
final currentVersion = await _getCurrentVersion();
|
||||
final initMarker = File(
|
||||
p.join(supportDir.path, '.initialized_$currentVersion'),
|
||||
);
|
||||
await initMarker.writeAsString('${DateTime.now().toIso8601String()}\n');
|
||||
}
|
||||
|
||||
/// 从assets目录提取文件到指定路径
|
||||
static Future<void> _extractAsset(String assetPath, String localPath) async {
|
||||
final localFile = File(localPath);
|
||||
|
||||
try {
|
||||
// 从assets中读取数据
|
||||
final ByteData data = await rootBundle.load(assetPath);
|
||||
final List<int> bytes = data.buffer.asUint8List();
|
||||
|
||||
// 确保目录存在
|
||||
final dir = Directory(p.dirname(localPath));
|
||||
if (!await dir.exists()) {
|
||||
await dir.create(recursive: true);
|
||||
}
|
||||
|
||||
// 写入本地文件
|
||||
await localFile.writeAsBytes(bytes);
|
||||
print('成功提取文件: $assetPath -> $localPath');
|
||||
} catch (e) {
|
||||
print('提取资源文件失败 $assetPath: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 初始化应用程序资源 - 将所有必要的assets迁移到系统文件夹
|
||||
static Future<void> initializeAppResources() async {
|
||||
final currentVersion = await _getCurrentVersion();
|
||||
|
||||
if (await isInitialized()) {
|
||||
print('应用程序资源已初始化,当前版本: $currentVersion');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 迁移shell脚本
|
||||
await _migrateShellScript();
|
||||
|
||||
// 迁移二进制文件
|
||||
await _migrateBinaries();
|
||||
|
||||
// 迁移模型文件
|
||||
await _migrateModels();
|
||||
|
||||
// 迁移3D模型文件
|
||||
await migrate3DModels();
|
||||
|
||||
// 标记初始化完成
|
||||
await markInitialized();
|
||||
|
||||
print('应用程序资源初始化完成');
|
||||
} catch (e) {
|
||||
print('应用程序资源初始化失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 迁移3D模型文件
|
||||
static Future<void> migrate3DModels() async {
|
||||
print('开始迁移3D模型文件...');
|
||||
|
||||
final supportDir = await getApplicationSupportDirectory();
|
||||
final models3dDir = Directory(p.join(supportDir.path, 'cup'));
|
||||
|
||||
// 创建3D模型目录
|
||||
if (!await models3dDir.exists()) {
|
||||
await models3dDir.create(recursive: true);
|
||||
}
|
||||
|
||||
// 3D模型文件列表
|
||||
final model3dFiles = ['model.gltf', 'model.bin', 'texture.jpg'];
|
||||
|
||||
// 迁移所有3D模型文件
|
||||
for (final modelFile in model3dFiles) {
|
||||
try {
|
||||
await _extractAsset(
|
||||
'assets/cup/$modelFile',
|
||||
p.join(models3dDir.path, modelFile),
|
||||
);
|
||||
} catch (e) {
|
||||
print('迁移3D模型文件失败 $modelFile: $e');
|
||||
// 继续迁移其他模型文件
|
||||
}
|
||||
}
|
||||
|
||||
print('3D模型文件迁移完成');
|
||||
}
|
||||
|
||||
static Future<void> _migrateShellScript() async {
|
||||
print('开始迁移脚本文件...');
|
||||
|
||||
final supportDir = await getApplicationSupportDirectory();
|
||||
|
||||
// 迁移 Shell 脚本 (macOS/Linux)
|
||||
final shellScriptPath = p.join(supportDir.path, 'upscale_to_8k_single.sh');
|
||||
await _extractAsset('assets/upscale_to_8k_single.sh', shellScriptPath);
|
||||
|
||||
// 设置脚本执行权限(仅限 macOS/Linux)
|
||||
if (Platform.isMacOS || Platform.isLinux) {
|
||||
try {
|
||||
final result = await Process.run('chmod', ['+x', shellScriptPath]);
|
||||
if (result.exitCode == 0) {
|
||||
print('成功设置Shell脚本执行权限: $shellScriptPath');
|
||||
} else {
|
||||
print('设置Shell脚本执行权限失败: ${result.stderr}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('设置Shell脚本权限异常: $e');
|
||||
}
|
||||
}
|
||||
|
||||
print('脚本文件迁移完成');
|
||||
}
|
||||
|
||||
/// 迁移二进制文件
|
||||
static Future<void> _migrateBinaries() async {
|
||||
print('开始迁移二进制文件...');
|
||||
|
||||
final supportDir = await getApplicationSupportDirectory();
|
||||
final binDir = Directory(p.join(supportDir.path, 'bin'));
|
||||
|
||||
// 创建bin目录
|
||||
if (!await binDir.exists()) {
|
||||
await binDir.create(recursive: true);
|
||||
}
|
||||
|
||||
// macOS 二进制文件
|
||||
final macBinDir = Directory(p.join(binDir.path, 'macos'));
|
||||
if (!await macBinDir.exists()) {
|
||||
await macBinDir.create(recursive: true);
|
||||
}
|
||||
|
||||
await _extractAsset(
|
||||
'assets/bin/mac/upscayl-bin',
|
||||
p.join(macBinDir.path, 'upscayl-bin'),
|
||||
);
|
||||
|
||||
// Windows 二进制文件
|
||||
final winBinDir = Directory(p.join(binDir.path, 'windows'));
|
||||
if (!await winBinDir.exists()) {
|
||||
await winBinDir.create(recursive: true);
|
||||
}
|
||||
|
||||
await _extractAsset(
|
||||
'assets/bin/windows/upscayl-bin.exe',
|
||||
p.join(winBinDir.path, 'upscayl-bin.exe'),
|
||||
);
|
||||
|
||||
await _extractAsset(
|
||||
'assets/bin/windows/vcomp140.dll',
|
||||
p.join(winBinDir.path, 'vcomp140.dll'),
|
||||
);
|
||||
|
||||
await _extractAsset(
|
||||
'assets/bin/windows/vcomp140d.dll',
|
||||
p.join(winBinDir.path, 'vcomp140d.dll'),
|
||||
);
|
||||
|
||||
// 设置 macOS/Linux 二进制文件执行权限
|
||||
if (Platform.isMacOS || Platform.isLinux) {
|
||||
final binPath = p.join(macBinDir.path, 'upscayl-bin');
|
||||
try {
|
||||
final result = await Process.run('chmod', ['+x', binPath]);
|
||||
if (result.exitCode == 0) {
|
||||
print('成功设置执行权限: $binPath');
|
||||
} else {
|
||||
print('设置执行权限失败: ${result.stderr}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('设置权限异常: $e');
|
||||
}
|
||||
}
|
||||
|
||||
print('二进制文件迁移完成');
|
||||
}
|
||||
|
||||
/// 迁移模型文件
|
||||
static Future<void> _migrateModels() async {
|
||||
print('开始迁移模型文件...');
|
||||
|
||||
final supportDir = await getApplicationSupportDirectory();
|
||||
final modelsDir = Directory(p.join(supportDir.path, 'models'));
|
||||
|
||||
// 创建models目录
|
||||
if (!await modelsDir.exists()) {
|
||||
await modelsDir.create(recursive: true);
|
||||
}
|
||||
|
||||
// 模型文件列表
|
||||
final modelFiles = [
|
||||
'high-fidelity-4x.bin',
|
||||
'high-fidelity-4x.param',
|
||||
'digital-art-4x.bin',
|
||||
'digital-art-4x.param',
|
||||
'remacri-4x.bin',
|
||||
'remacri-4x.param',
|
||||
'ultrasharp-4x.bin',
|
||||
'ultrasharp-4x.param',
|
||||
'upscayl-standard-4x.bin',
|
||||
'upscayl-standard-4x.param',
|
||||
'ultramix-balanced-4x.bin',
|
||||
'ultramix-balanced-4x.param',
|
||||
'upscayl-lite-4x.bin',
|
||||
'upscayl-lite-4x.param',
|
||||
];
|
||||
|
||||
// 迁移所有模型文件
|
||||
for (final modelFile in modelFiles) {
|
||||
try {
|
||||
await _extractAsset(
|
||||
'assets/models/$modelFile',
|
||||
p.join(modelsDir.path, modelFile),
|
||||
);
|
||||
} catch (e) {
|
||||
print('迁移模型文件失败 $modelFile: $e');
|
||||
// 继续迁移其他模型文件
|
||||
}
|
||||
}
|
||||
|
||||
print('模型文件迁移完成');
|
||||
}
|
||||
|
||||
/// 获取模型文件目录路径
|
||||
static Future<String> getModelsPath() async {
|
||||
final supportDir = await getApplicationSupportDirectory();
|
||||
return p.join(supportDir.path, 'cup', "model.gltf");
|
||||
}
|
||||
|
||||
/// 获取3D模型文件目录路径
|
||||
static Future<String> get3DModelsPath() async {
|
||||
final supportDir = await getApplicationSupportDirectory();
|
||||
return p.join(supportDir.path, 'cup');
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> readLocalJson() async {
|
||||
// 获取应用支持目录(默认在 ~/Library/Application Support/)
|
||||
final appSupportDir = await getApplicationSupportDirectory();
|
||||
final targetDir = Directory('${appSupportDir.path}/cup');
|
||||
|
||||
// 检查目录是否存在,若不存在则创建
|
||||
if (!await targetDir.exists()) {
|
||||
await targetDir.create(recursive: true);
|
||||
}
|
||||
print('file=${targetDir.path}/model.gltf');
|
||||
// 构建 JSON 文件路径
|
||||
final file = File('${targetDir.path}/model.gltf');
|
||||
|
||||
if (await file.exists()) {
|
||||
final content = await file.readAsString();
|
||||
return jsonDecode(content);
|
||||
} else {
|
||||
throw Exception('JSON 文件不存在');
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取特定的3D模型文件路径
|
||||
static Future<String> get3DModelPath(String filename) async {
|
||||
final models3dPath = await get3DModelsPath();
|
||||
return p.join(models3dPath, filename);
|
||||
}
|
||||
|
||||
/// 获取脚本文件路径 (仅适用于macOS/Linux)
|
||||
static Future<String> getScriptPath() async {
|
||||
if (Platform.isWindows) {
|
||||
throw UnsupportedError('Windows平台已使用专门的UpscaleWindowsService,不再需要脚本文件');
|
||||
}
|
||||
|
||||
final supportDir = await getApplicationSupportDirectory();
|
||||
final scriptName = 'upscale_to_8k_single.sh';
|
||||
final scriptPath = p.join(supportDir.path, scriptName);
|
||||
final scriptFile = File(scriptPath);
|
||||
|
||||
if (!await scriptFile.exists()) {
|
||||
throw FileSystemException(
|
||||
'脚本文件不存在: $scriptPath\n请确保应用程序已正确初始化资源',
|
||||
scriptPath,
|
||||
);
|
||||
}
|
||||
|
||||
return scriptPath;
|
||||
}
|
||||
|
||||
/// 获取二进制文件路径
|
||||
static Future<String> getBinaryPath() async {
|
||||
final supportDir = await getApplicationSupportDirectory();
|
||||
|
||||
String platformDir;
|
||||
String binaryName;
|
||||
|
||||
if (Platform.isMacOS) {
|
||||
platformDir = 'macos';
|
||||
binaryName = 'upscayl-bin';
|
||||
} else if (Platform.isWindows) {
|
||||
platformDir = 'windows';
|
||||
binaryName = 'upscayl-bin.exe';
|
||||
} else if (Platform.isLinux) {
|
||||
platformDir = 'macos'; // Linux 使用 macOS 的二进制文件
|
||||
binaryName = 'upscayl-bin';
|
||||
} else {
|
||||
throw UnsupportedError('不支持的操作系统: ${Platform.operatingSystem}');
|
||||
}
|
||||
|
||||
final binPath = p.join(supportDir.path, 'bin', platformDir, binaryName);
|
||||
|
||||
// 检查文件是否存在
|
||||
final binFile = File(binPath);
|
||||
if (!await binFile.exists()) {
|
||||
throw FileSystemException('二进制文件不存在: $binPath\n请确保应用程序已正确初始化资源', binPath);
|
||||
}
|
||||
|
||||
return binPath;
|
||||
}
|
||||
|
||||
/// 设置脚本执行权限
|
||||
static Future<void> setScriptExecutable(String scriptPath) async {
|
||||
// 设置脚本执行权限(仅限 macOS/Linux)
|
||||
if (Platform.isMacOS || Platform.isLinux) {
|
||||
try {
|
||||
final result = await Process.run('chmod', ['+x', scriptPath]);
|
||||
if (result.exitCode == 0) {
|
||||
print('成功设置脚本执行权限: $scriptPath');
|
||||
} else {
|
||||
print('设置脚本执行权限失败: ${result.stderr}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('设置脚本权限异常: $e');
|
||||
}
|
||||
}
|
||||
// Windows 不需要设置执行权限
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user