c# 企业级ADB通信示例

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ADB_Demo
{
    /// <summary>
    /// ADB管理器,提供与Android设备的通信功能
    /// </summary>
    public class AdbManager : IDisposable
    {
        private readonly string _adbPath;
        private readonly Dictionary<string, Process> _runningProcesses = new();
        private readonly object _processLock = new();
        private bool _disposed;

        /// <summary>
        /// ADB管理器构造函数
        /// </summary>
        /// <param name="adbPath">ADB可执行文件路径,默认自动查找</param>
        public AdbManager(string adbPath = null)
        {
            _adbPath = FindAdbPath(adbPath);
            if (string.IsNullOrEmpty(_adbPath))
                throw new FileNotFoundException("ADB executable not found");
        }

        private string FindAdbPath(string customPath)
        {
            if (!string.IsNullOrEmpty(customPath) && File.Exists(customPath))
                return Path.GetFullPath(customPath);

            // 查找环境变量中的adb
            var paths = Environment.GetEnvironmentVariable("PATH")?.Split(Path.PathSeparator) ?? Array.Empty<string>();
            foreach (var path in paths)
            {
                try
                {
                    var fullPath = Path.Combine(path, "adb.exe");
                    if (File.Exists(fullPath))
                        return fullPath;
                }
                catch
                {
                    // 忽略无效路径
                }
            }

            // 尝试Android SDK默认位置
            var sdkPaths = new[]
            {
                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Android", "android-sdk", "platform-tools", "adb.exe"),
                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "AppData", "Local", "Android", "Sdk", "platform-tools", "adb.exe")
            };

            return sdkPaths.FirstOrDefault(File.Exists);
        }

        /// <summary>
        /// 执行ADB命令并返回结果
        /// </summary>
        public async Task<AdbCommandResult> ExecuteCommandAsync(
            string command,
            CancellationToken cancellationToken = default,
            int timeoutMilliseconds = 30000)
        {
            if (_disposed)
                throw new ObjectDisposedException(nameof(AdbManager));

            var processInfo = new ProcessStartInfo
            {
                FileName = _adbPath,
                Arguments = command,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
                StandardOutputEncoding = System.Text.Encoding.UTF8,
                StandardErrorEncoding = System.Text.Encoding.UTF8
            };

            var process = new Process { StartInfo = processInfo };
            var processId = Guid.NewGuid().ToString();

            lock (_processLock)
            {
                _runningProcesses.Add(processId, process);
            }

            try
            {
                process.Start();
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                var outputBuilder = new System.Text.StringBuilder();
                var errorBuilder = new System.Text.StringBuilder();

                process.OutputDataReceived += (_, e) => { if (e.Data != null) outputBuilder.AppendLine(e.Data); };
                process.ErrorDataReceived += (_, e) => { if (e.Data != null) errorBuilder.AppendLine(e.Data); };

                // 等待进程退出或超时
                var processTask = Task.Run(() => process.WaitForExit(), cancellationToken);
                var completedTask = await Task.WhenAny(processTask, Task.Delay(timeoutMilliseconds, cancellationToken));

                if (completedTask != processTask)
                {
                    throw new TimeoutException($"ADB command timed out after {timeoutMilliseconds}ms");
                }

                if (process.ExitCode != 0)
                {
                    throw new AdbCommandException($"ADB command failed with exit code {process.ExitCode}",
                        errorBuilder.ToString(), process.ExitCode);
                }

                return new AdbCommandResult(outputBuilder.ToString().Trim(), errorBuilder.ToString().Trim());
            }
            finally
            {
                lock (_processLock)
                {
                    _runningProcesses.Remove(processId);
                }

                if (!process.HasExited)
                {
                    process.Kill();
                }

                process.Dispose();
            }
        }

        /// <summary>
        /// 获取连接的设备列表
        /// </summary>
        public async Task<List<AdbDevice>> GetDevicesAsync(CancellationToken cancellationToken = default)
        {
            var result = await ExecuteCommandAsync("devices -l", cancellationToken);
            var lines = result.Output.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

            // 跳过第一行标题行
            return lines.Skip(1)
                .Select(line => line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
                .Where(parts => parts.Length >= 2)
                .Select(parts => new AdbDevice
                {
                    SerialNumber = parts[0],
                    Status = parts[1],
                    Properties = parts.Skip(2)
                        .Select(p => p.Split(':'))
                        .Where(p => p.Length == 2)
                        .ToDictionary(p => p[0], p => p[1])
                })
                .ToList();
        }

        /// <summary>
        /// 停止所有正在运行的ADB进程
        /// </summary>
        public void StopAllProcesses()
        {
            lock (_processLock)
            {
                foreach (var process in _runningProcesses.Values)
                {
                    try
                    {
                        if (!process.HasExited)
                        {
                            process.Kill();
                        }
                    }
                    catch
                    {
                        // 忽略停止过程中的错误
                    }
                }
                _runningProcesses.Clear();
            }
        }

        public void Dispose()
        {
            if (_disposed) return;

            StopAllProcesses();
            _disposed = true;
            GC.SuppressFinalize(this);
        }

        ~AdbManager()
        {
            Dispose();
        }
    }

    /// <summary>
    /// ADB命令执行结果
    /// </summary>
    public class AdbCommandResult
    {
        public string Output { get; }
        public string Error { get; }

        public AdbCommandResult(string output, string error)
        {
            Output = output;
            Error = error;
        }
    }

    /// <summary>
    /// ADB设备信息
    /// </summary>
    public class AdbDevice
    {
        public string SerialNumber { get; set; }
        public string Status { get; set; }
        public Dictionary<string, string> Properties { get; set; } = new();

        public override string ToString() => $"{SerialNumber} ({Status})";
    }

    /// <summary>
    /// ADB命令异常
    /// </summary>
    public class AdbCommandException : Exception
    {
        public string ErrorOutput { get; }
        public int ExitCode { get; }

        public AdbCommandException(string message, string errorOutput, int exitCode)
            : base(message)
        {
            ErrorOutput = errorOutput;
            ExitCode = exitCode;
        }
    }
}

应用示例:

csharp 复制代码
namespace ADB_Demo
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            using var adb = new AdbManager();

            var ret = await adb.ExecuteCommandAsync("version");

            // 1. 获取设备列表
            var devices = await adb.GetDevicesAsync();
            Console.WriteLine("Connected devices:");
            foreach (var device in devices)
            {
                Console.WriteLine($"- {device.SerialNumber} ({device.Status})");
            }

        }
    }
}

各函数的功能说明:


AdbManager 类

1. 构造函数 AdbManager(string adbPath = null)

功能 :初始化 ADB 管理器,自动查找或使用指定的 ADB 可执行文件路径。

参数

adbPath:可选,自定义 ADB 路径。若未提供,则自动搜索。

2. FindAdbPath(string customPath)(私有方法)

功能 :查找 ADB 可执行文件的完整路径。

查找顺序

  1. 优先使用 customPath(如果有效)。
  2. 搜索系统 PATH 环境变量。
  3. 检查 Android SDK 默认安装路径(Windows 平台)。
3. ExecuteCommandAsync(string command, CancellationToken cancellationToken = default, int timeoutMilliseconds = 30000)

功能 :异步执行指定的 ADB 命令,并返回输出结果。

参数

command:要执行的 ADB 命令(如 "devices -l")。

cancellationToken:支持取消操作。

timeoutMilliseconds:超时时间(默认 30 秒)。

返回值AdbCommandResult,包含标准输出和错误输出。

4. GetDevicesAsync(CancellationToken cancellationToken = default)

功能 :获取当前连接的 Android 设备列表。

实现 :调用 adb devices -l 并解析输出。

返回值List<AdbDevice>,包含设备序列号、状态和属性(如 model)。

5. StopAllProcesses()

功能 :强制终止所有正在运行的 ADB 进程。

用途:通常在释放资源时调用。

6. Dispose() 和析构函数 ~AdbManager()

功能 :实现 IDisposable 接口,清理资源(停止所有进程)。


辅助类

1. AdbCommandResult

功能 :封装 ADB 命令的执行结果。

属性

Output:标准输出内容。

Error:错误输出内容。

2. AdbDevice

功能 :表示一个连接的 Android 设备。

属性

SerialNumber:设备序列号(如 emulator-5554)。

Status:设备状态(如 device/offline)。

Properties:设备属性字典(如 model:Android_SDK_built_for_x86)。

3. AdbCommandException

功能 :自定义异常,表示 ADB 命令执行失败。

属性

ErrorOutput:错误输出内容。

ExitCode:进程退出码。


相关推荐
落沐萧萧2 分钟前
Java利用无外网(下):ClassPathXmlApplicationContext的不出网利用
java·开发语言
窦再兴20 分钟前
CentOS8.5 LLaMA-Factory训练模型
开发语言·人工智能·python·llama-factory·llama3.2
yivifu33 分钟前
使用pybind11开发c++扩展模块输出到控制台的中文信息显示乱码的问题
开发语言·python·pybind11
烁34744 分钟前
每日一题(小白)暴力娱乐篇22
java·开发语言·算法·娱乐
浅陌sss44 分钟前
C#容器源码分析 --- Queue<T>
c#
极客先躯2 小时前
高级java每日一道面试题-2025年3月31日-微服务篇[Nacos篇]-Nacos集群模式下的部署方案有哪些?
java·开发语言·微服务
go_bai2 小时前
list的常见接口使用
开发语言·c++·经验分享·笔记·list
鑫—萍2 小时前
数据结构与算法——链表OJ题详解(2)
c语言·开发语言·数据结构·学习·算法·链表
大锦终2 小时前
【C++】继承
c语言·开发语言·数据结构·c++
stevenzqzq2 小时前
kotlin扩展函数
android·开发语言·kotlin