245 lines
No EOL
8.2 KiB
C#
245 lines
No EOL
8.2 KiB
C#
using System.Reflection;
|
||
using AdvancedSharpAdbClient;
|
||
using AdvancedSharpAdbClient.DeviceCommands;
|
||
using AdvancedSharpAdbClient.Models;
|
||
|
||
namespace MetaforceInstaller.Cli;
|
||
|
||
class Program
|
||
{
|
||
// 1. Получить имя апк и зипки, если не предоставлены - забить дефолтными значениями
|
||
// 2. Распаковать в временную директорию adb (готово)
|
||
// 3. Установить апк
|
||
// 4. Получить имя пакета
|
||
// 5. Сформировать строку пути для контента
|
||
// 6. Копировать зип по сформированному пути
|
||
|
||
static AdbClient adbClient;
|
||
static DeviceData deviceData;
|
||
|
||
static void Main(string[] args)
|
||
{
|
||
try
|
||
{
|
||
var (apkPath, zipPath, outputPath) = ParseArguments(args);
|
||
|
||
if (string.IsNullOrEmpty(apkPath) || string.IsNullOrEmpty(zipPath) || string.IsNullOrEmpty(outputPath))
|
||
{
|
||
ShowUsage();
|
||
return;
|
||
}
|
||
|
||
var adbPath = ExtractAdbFiles();
|
||
|
||
var server = new AdbServer();
|
||
var result = server.StartServer(adbPath, restartServerIfNewer: false);
|
||
Console.WriteLine($"ADB сервер запущен: {result}");
|
||
|
||
adbClient = new AdbClient();
|
||
|
||
var devices = adbClient.GetDevices();
|
||
|
||
if (!devices.Any())
|
||
{
|
||
Console.WriteLine("Устройства не найдены. Подключите Android-устройство и включите отладку по USB.");
|
||
return;
|
||
}
|
||
|
||
deviceData = devices.FirstOrDefault();
|
||
Console.WriteLine($"Найдено устройство: {deviceData.Serial}");
|
||
Console.WriteLine($"Состояние: {deviceData.State}");
|
||
Console.WriteLine($"Имя устройства: {deviceData.Name} - {deviceData.Model}");
|
||
|
||
InstallApk(apkPath);
|
||
CopyFileToDevice(zipPath, outputPath);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"Ошибка: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
static void ShowUsage()
|
||
{
|
||
Console.WriteLine("Использование:");
|
||
Console.WriteLine(
|
||
" MetaforceInstaller.exe --apk <путь_к_apk> --content <путь_к_zip> --output <путь_для контента>");
|
||
Console.WriteLine(" MetaforceInstaller.exe -a <путь_к_apk> -c <путь_к_zip> -o <путь_для_контента>");
|
||
Console.WriteLine();
|
||
Console.WriteLine("Параметры:");
|
||
Console.WriteLine(" --apk, -a Путь к APK файлу");
|
||
Console.WriteLine(" --content, -c Путь к ZIP файлу с контентом");
|
||
Console.WriteLine(" --output, -o Путь для копирования контента");
|
||
Console.WriteLine(" --help, -h Показать эту справку");
|
||
Console.WriteLine();
|
||
Console.WriteLine("Пример:");
|
||
Console.WriteLine(
|
||
" MetaforceInstaller.exe --apk \"C:\\app.apk\" --content \"C:\\data.zip\" --output \"/sdcard/data.zip\"");
|
||
Console.WriteLine(" MetaforceInstaller.exe -a app.apk -c data.zip -o /sdcard/data.zip");
|
||
}
|
||
|
||
|
||
private static (string? apkPath, string? zipPath, string? outputPath) ParseArguments(string[] args)
|
||
{
|
||
string apkPath = null;
|
||
string zipPath = null;
|
||
string outputPath = null;
|
||
|
||
for (int i = 0; i < args.Length; i++)
|
||
{
|
||
switch (args[i].ToLower())
|
||
{
|
||
case "--apk":
|
||
case "-a":
|
||
if (i + 1 < args.Length)
|
||
{
|
||
apkPath = args[i + 1];
|
||
i++;
|
||
}
|
||
|
||
break;
|
||
|
||
case "--content":
|
||
case "-c":
|
||
if (i + 1 < args.Length)
|
||
{
|
||
zipPath = args[i + 1];
|
||
i++;
|
||
}
|
||
|
||
break;
|
||
|
||
case "--output":
|
||
case "-o":
|
||
if (i + 1 < args.Length)
|
||
{
|
||
outputPath = args[i + 1];
|
||
i++;
|
||
}
|
||
|
||
break;
|
||
|
||
case "--help":
|
||
case "-h":
|
||
ShowUsage();
|
||
Environment.Exit(0);
|
||
break;
|
||
}
|
||
}
|
||
|
||
return (apkPath, zipPath, outputPath);
|
||
}
|
||
|
||
private static void ExtractResource(string resourceName, string outputPath)
|
||
{
|
||
using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
|
||
using var fileStream = File.Create(outputPath);
|
||
stream.CopyTo(fileStream);
|
||
}
|
||
|
||
private static string ExtractAdbFiles()
|
||
{
|
||
var tempDir = Path.Combine(Path.GetTempPath(), "MetaforceInstaller", "adb");
|
||
Directory.CreateDirectory(tempDir);
|
||
|
||
var adbPath = Path.Combine(tempDir, "adb.exe");
|
||
|
||
if (!File.Exists(adbPath))
|
||
{
|
||
ExtractResource("MetaforceInstaller.Cli.adb.adb.exe", adbPath);
|
||
ExtractResource("MetaforceInstaller.Cli.adb.AdbWinApi.dll", Path.Combine(tempDir, "AdbWinApi.dll"));
|
||
ExtractResource("MetaforceInstaller.Cli.adb.AdbWinUsbApi.dll", Path.Combine(tempDir, "AdbWinUsbApi.dll"));
|
||
}
|
||
|
||
return adbPath;
|
||
}
|
||
|
||
private static void InstallApk(string apkPath)
|
||
{
|
||
try
|
||
{
|
||
if (!File.Exists(apkPath))
|
||
{
|
||
Console.WriteLine($"APK файл не найден: {apkPath}");
|
||
return;
|
||
}
|
||
|
||
Console.WriteLine($"Установка APK: {apkPath}");
|
||
|
||
var packageManager = new PackageManager(adbClient, deviceData);
|
||
packageManager.InstallPackage(apkPath, new Action<InstallProgressEventArgs>(o => { }));
|
||
|
||
Console.WriteLine("APK успешно установлен!");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"Ошибка установки APK: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private static void CopyFileToDevice(string localPath, string remotePath)
|
||
{
|
||
try
|
||
{
|
||
if (!File.Exists(localPath))
|
||
{
|
||
Console.WriteLine($"Локальный файл не найден: {localPath}");
|
||
return;
|
||
}
|
||
|
||
Console.WriteLine($"Копирование файла {localPath} в {remotePath}");
|
||
|
||
var lastProgress = -1;
|
||
|
||
using var fileStream = File.OpenRead(localPath);
|
||
var syncService = new SyncService(adbClient, deviceData);
|
||
|
||
syncService.Push(fileStream, remotePath, UnixFileStatus.DefaultFileMode, DateTime.Now,
|
||
new Action<SyncProgressChangedEventArgs>(progress =>
|
||
{
|
||
var currentProgress = progress.ProgressPercentage;
|
||
|
||
if (currentProgress != lastProgress)
|
||
{
|
||
lastProgress = (int)currentProgress;
|
||
DrawProgressBar(lastProgress, progress.ReceivedBytesSize, progress.TotalBytesToReceive);
|
||
}
|
||
}));
|
||
|
||
Console.WriteLine();
|
||
Console.WriteLine("Файл успешно скопирован!");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"Ошибка копирования файла: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private static void DrawProgressBar(int progress, long receivedBytes, long totalBytes)
|
||
{
|
||
Console.SetCursorPosition(0, Console.CursorTop);
|
||
|
||
var barLength = 40;
|
||
var filledLength = (int)(barLength * progress / 100.0);
|
||
|
||
var bar = "[" + new string('█', filledLength) + new string('░', barLength - filledLength) + "]";
|
||
var bytesText = $" {FormatBytes(receivedBytes)} / {FormatBytes(totalBytes)}";
|
||
|
||
Console.Write($"\r{bar} {progress}%{bytesText}");
|
||
}
|
||
|
||
private static string FormatBytes(long bytes)
|
||
{
|
||
string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
|
||
var counter = 0;
|
||
double number = bytes;
|
||
|
||
while (Math.Round(number / 1024) >= 1)
|
||
{
|
||
number /= 1024;
|
||
counter++;
|
||
}
|
||
|
||
return $"{number:N1} {suffixes[counter]}";
|
||
}
|
||
} |