using ApkManager.Lib;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace ApkManager
{
public class Adb
{
public class Device
{
public string Name { get; set; }
public string Android { get; set; }
public string Abi { get; set; }
public int Sdk { get; set; }
public override string ToString()
{
return Name.ToString();
}
}
private static bool OVERRIDE_ONREPORTEVENT = false;
private static bool OVERRIDE_ONPROCESSEVENT = false;
public delegate void ProcessEventHandler(bool value);
public event ProcessEventHandler OnProcess;
public delegate void OutputEventHander(string message);
public event OutputEventHander OutputDataReceived;
public delegate void ErrorEventHandler(string message);
public event ErrorEventHandler ErrorDataReceived;
public Adb()
{
}
private async Task<string> RunAsync(string command, params object[] args)
{
using (var p = new Process())
{
var OutputMessage = string.Empty;
p.OutputDataReceived += (s, e) => {
if (string.IsNullOrWhiteSpace(e.Data)) return;
OutputMessage += e.Data + Environment.NewLine;
if (!OVERRIDE_ONREPORTEVENT)
OutputDataReceived?.Invoke(e.Data);
};
var ErrorMessage = string.Empty;
p.ErrorDataReceived += (s, e) => {
if (string.IsNullOrWhiteSpace(e.Data)) return;
ErrorMessage += e.Data + Environment.NewLine;
if (!OVERRIDE_ONREPORTEVENT)
ErrorDataReceived?.Invoke(e.Data);
};
p.StartInfo = new ProcessStartInfo()
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
WindowStyle = ProcessWindowStyle.Hidden,
FileName = Path.Combine("Lib", "adb.exe"),
Arguments = string.Format(command, args)
};
p.Start();
Debug.Print("Adb.Command: adb {0}", string.Format(command, args));
if (!OVERRIDE_ONPROCESSEVENT)
OnProcess?.Invoke(true);
p.BeginOutputReadLine();
p.BeginErrorReadLine();
await Task.Run(() => p.WaitForExit());
if (!OVERRIDE_ONPROCESSEVENT)
OnProcess?.Invoke(false);
if (p.ExitCode != 0) throw new Exception(ErrorMessage);
Debug.Print("Adb.Output: {0}", OutputMessage);
return OutputMessage;
};
}
public async Task<bool> StartServer()
{
try
{
await RunAsync("start-server");
return true;
}
catch (Exception e)
{
Debug.Print("Adb.StartServer: {0}", e.Message);
return false;
}
}
public async Task<bool> Reconnect()
{
try
{
await RunAsync("reconnect");
return true;
}
catch (Exception e)
{
Debug.Print("Adb.Reconnect: {0}", e.Message);
return false;
}
}
public async Task<bool> Connect(string address)
{
try
{
if (!address.Contains(":"))
address += ":5555";
var result = await RunAsync("connect {0}", address);
return result.Contains("connected");
}
catch (Exception e)
{
Debug.Print("Adb.Connect: {0}", e.Message);
return false;
}
}
public async Task<bool> Disconnect(string address)
{
try
{
if (!address.Contains(":"))
address += ":5555";
var result = await RunAsync("disconnect {0}", address);
return result.Contains("disconnected") || result.Contains("no such device");
}
catch (Exception e)
{
Debug.Print("Adb.Disconnect: {0}", e.Message);
return false;
}
}
public async Task<List<string>> GetDevices()
{
var devices = new List<string>();
try
{
var result = await RunAsync("devices");
var matches = Regex.Matches(result, @"(.+?)\tdevice");
foreach (Match match in matches)
{
devices.Add(match.Groups[1].Value);
}
}
catch (Exception e)
{
Debug.Print("Adb.GetDevices: {0}", e.Message);
}
return devices;
}
public async Task<bool> Install(string device, string pathApk)
{
try
{
var result = await RunAsync("-s {0} install -r \"{1}\"", device, pathApk.GetShortPathName());
return result.Contains("Success");
}
catch (Exception e)
{
Debug.Print("Adb.Install: {0}", e.Message);
return false;
}
}
public async Task<bool> Uninstall(string device, string package, bool keepData = false)
{
try
{
var command = keepData ? $"-s {device} shell pm uninstall -k {package}" : $"-s {device} uninstall {package}";
var result = await RunAsync(command);
return result.Contains("Success");
}
catch (Exception e)
{
Debug.Print("Adb.Uninstall: {0}", e.Message);
return false;
}
}
public async Task<bool> IsDeviceOnline(string device)
{
try
{
OVERRIDE_ONREPORTEVENT = true;
var result = await RunAsync("-s {0} get-state", device);
return result.ToLower().Contains("device");
}
catch (Exception e)
{
Debug.Print("Adb.IsDeviceOnline: {0}", e.Message);
return false;
}
finally
{
OVERRIDE_ONREPORTEVENT = false;
}
}
public async Task<bool> LaunchActivity(string device, Apk apk)
{
try
{
var result = await RunAsync("-s {0} shell am start -n \"{1}/{2}\" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER", device, apk.PackageName, apk.LaunchableActivity);
return result.ToLower().Contains("error");
}
catch (Exception e)
{
Debug.Print("Adb.LunchActivity: {0}", e.Message);
return false;
}
}
public async Task<string> GetProp(string device, string prop)
{
try
{
var result = await RunAsync("-s {0} shell getprop {1}", device, prop);
return string.IsNullOrWhiteSpace(result) ? "Unknown" : result.Trim();
}
catch (Exception e)
{
Debug.Print("Adb.Uninstall: {0}", e.Message);
return "Unknown";
}
}
public async Task<Device> GetDevice(string address)
{
OVERRIDE_ONPROCESSEVENT = true;
OnProcess?.Invoke(true);
var name = await GetProp(address, "ro.product.model");
if (string.IsNullOrWhiteSpace(name))
name = await GetProp(address, "ro.product.brand");
if (string.IsNullOrWhiteSpace(name))
name = await GetProp(address, "ro.product.device");
if (string.IsNullOrWhiteSpace(name))
name = "Unknown";
var android = await GetProp(address, "ro.build.version.release");
if (string.IsNullOrWhiteSpace(android))
android = "Unknown";
var sdk = await GetProp(address, "ro.build.version.sdk");
int.TryParse(sdk, out int _sdk);
var _abi = await GetProp(address, "ro.product.cpu.abi");
OnProcess?.Invoke(false);
OVERRIDE_ONPROCESSEVENT = false;
return new Device()
{
Name = name,
Android = android,
Sdk = _sdk,
Abi = _abi
};
}
}
}
调用示例
using ApkManager;
using System;
using System.Windows.Forms;
using System.Windows.Threading;
namespace FT_Tools
{
public partial class FormT20WriteConfig : Form
{
private void FormT20WriteConfig_Load(object sender, EventArgs e)
{
// define adb
adb = new Adb();
adb.OnProcess += (value) => ShowLoading(value);
adb.OutputDataReceived += (msg) => CommandOutput_Insert(msg, false);
adb.ErrorDataReceived += (msg) => CommandOutput_Insert(msg, true);
}
private Adb adb;
private async void buttonStart_Click(object sender, EventArgs e)
{
var devices = await adb.GetDevices();
foreach (var device in devices)
{
Log("Connected to:"+device);
//cbDevices.Items.Add(device);
}
}
private void CommandOutput_Insert(string message, bool error = false)
{
Log(message);
//Dispatcher.Invoke(() =>
//{
// var color = Brushes.WhiteSmoke;
// if (error || message.ToLower().Contains("failed"))
// color = Brushes.IndianRed;
// else if (message.ToLower().Contains("success"))
// color = Brushes.LightBlue;
// var item = new ListBoxItem()
// {
// Content = message.Trim(),
// Background = color
// };
// lbOutput.Items.Add(item);
// lbOutput.ScrollIntoView(item);
//});
}
private void ShowLoading(bool state = true)
{
Log("ShowLoading:" + state);
//Dispatcher.Invoke(() =>
//{
// isLoading = state;
// PanelLoading.Visibility = state ? Visibility.Visible : Visibility.Collapsed;
//});
}
public FormT20WriteConfig()
{
InitializeComponent();
}
public void Log(string str)
{
MyLog.MyLog.WriteLogs(MyLog.MyLog.fileName, "", str);
this.Invoke((EventHandler)(delegate
{
textBoxLog.Text += str + "\r\n";
textBoxLog.SelectionStart = textBoxLog.Text.Length;
textBoxLog.ScrollToCaret();
}));
}
}
}
C++版
#define MAX_LENGTH 22048
int pipe(char *cmd, char *out)
{
logger.INFO_F(cmd);
HANDLE hParentRead, hChildWrite; //创建2个句柄 父(当前应用)读子(cmd)写
//1.创建一个安全属性描述符,设置句柄可继承
SECURITY_ATTRIBUTES sa = { 0 }; //安全属性描述符
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE; //设置句柄可继承
//2.创建两个管道.父读->子写 子读->父写的
BOOL bRet = CreatePipe(&hParentRead, &hChildWrite, &sa, 0); //创建管道1. 父进程读 -> 子进程写入
if (!bRet) { logger.ERROR_F("CreatePipe error:" + to_string(GetLastError())); return GetLastError(); }
//bRet = CreatePipe(&hChildRead, &hParentWrite, &sa, 0);//创建管道2. 子进程读->父进程写.
//if (!bRet) { printf("error:%d", GetLastError()); return bRet; }
PROCESS_INFORMATION pi = { 0 }; //进程信息结构体
STARTUPINFO si = { 0 }; //启动信息结构体
si.cb = sizeof(si);
//3.重定向输出, 将子进程的读 以及子进程的写重定向.
//si.hStdInput = hChildRead; //将子进程读取重定向到stdinput中
si.hStdOutput = hChildWrite; //将子进程写重定向到 stdout中.
si.hStdError = hChildWrite; //将子进程写重定向到 stdout中.
si.dwFlags = STARTF_USESTDHANDLES; //设置窗口隐藏启动
//4.创建子进程
bRet = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);//创建cmd进程.默认寻找cmd进程.
if (!bRet) { logger.ERROR_F("CreateProcess error:" + to_string(GetLastError())); return GetLastError(); }
//DWORD dwFileSize = GetFileSize(hParentRead, NULL); //可以把头长度去掉
//char szBuffer[] = "ver\n";
//5.写入命令数据给子进程.
//DWORD dwWrite = 0; //实际写入字节数
//bRet = WriteFile(hParentWrite, szBuffer, strlen(szBuffer), &dwWrite, 0);//使用writeFile操作管道,给cmd发送数据命令.
//if (!bRet) { printf("error:%d", GetLastError()); return bRet; }
CloseHandle(pi.hThread); //关闭句柄
CloseHandle(hChildWrite);//关闭write ReadFile才不会阻塞
DWORD dwExitCode;
do {
GetExitCodeProcess(pi.hProcess, &dwExitCode);
//printf("GetExitCodeProcess:%d\n", dwExitCode);
char psBuffer[128] = { 0 };
DWORD outLength = 0;
if (NULL == ReadFile(hParentRead, psBuffer, sizeof(psBuffer) - 1, &outLength, NULL)) { logger.INFO_F(FUN_LINE"NULL " + to_string(GetLastError())); } //读cmd显示内容
if (outLength > 0) {
psBuffer[outLength] = 0;
logger.INFO_F(psBuffer);
if (strlen(out) > MAX_LENGTH / 2) { memset(out, 0, sizeof(MAX_LENGTH)); }
strcat(out, psBuffer);
}
} while (dwExitCode == STILL_ACTIVE);//等待子进程退出
//6.读出响应
//DWORD outLength;
//if (NULL == ReadFile(hParentRead, out, MAX_LENGTH - 1, &outLength, NULL)) { /*break;*/ } //读cmd显示内容
//if (outLength > 0) { out[outLength] = 0; logger.INFO_F(out); }
//7.退出子进程 退出cmd
//char *exit="exit\n";
//WriteFile(hParentWrite, exit, strlen(exit), NULL, 0);//使用writeFile操作管道,给cmd发送数据命令.
//if (!bRet) { printf("error:%d", GetLastError()); return bRet; }
TerminateProcess(pi.hProcess, 0); //退出子进程
//CloseHandle(hParentWrite); //关闭写入句柄
CloseHandle(hParentRead);
CloseHandle(pi.hProcess);
//CloseHandle(hChildRead);
//CloseHandle(pi.hProcess);
//printf("end\n");
return dwExitCode;
}
int pipe_cmd(char *cmd, char *out)
{
return pipe(CString("cmd.exe /c \"" + CString(cmd) + "\"").GetBuffer(), out);
}
int ADBHandShake()
{
CString out;
pipe("adb shell getprop ro.product.model", out.GetBuffer(MAX_LENGTH));
int ret = pipe(CString("adb shell getprop ro.product.model").GetBuffer(), out.GetBuffer(MAX_LENGTH));
if ((ret == 0 && out.Find("\n") != -1)) { logger.INFO_F("Connect to device via ADB. "); return 0; }
else { logger.ERROR_F("Failed to connect device via ADB. ret=" + to_string(ret)); }
return -100;
}