device-manager.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import { ipcMain, BrowserWindow } from 'electron';
  2. import { exec } from 'child_process';
  3. import { promisify } from 'util';
  4. import { getCachedAdbPath, loadConfig } from '../config.js';
  5. const execAsync = promisify(exec);
  6. // 获取主窗口引用(用于实时推送设备发现事件)
  7. function getMainWindow() {
  8. const windows = BrowserWindow.getAllWindows();
  9. return windows.length > 0 ? windows[0] : null;
  10. }
  11. // 获取已连接的 ADB 设备列表
  12. export async function getADBDevices() {
  13. try {
  14. const adbPath = getCachedAdbPath();
  15. const { stdout } = await execAsync(`${adbPath} devices`);
  16. const lines = stdout.split('\n').slice(1);
  17. const devices = [];
  18. for (const line of lines) {
  19. const parts = line.trim().split(/\s+/);
  20. if (parts.length >= 2 && parts[0] && parts[1] === 'device') {
  21. devices.push({
  22. id: parts[0],
  23. status: parts[1]
  24. });
  25. }
  26. }
  27. return devices;
  28. } catch (error) {
  29. console.error('获取设备列表失败:', error);
  30. return [];
  31. }
  32. }
  33. // 网络扫描:从 192.168.0.1 开始扫描网段,尝试连接设备(实时推送结果)
  34. export async function scanNetworkDevices(event) {
  35. const adbPath = getCachedAdbPath();
  36. const baseIP = '192.168.0';
  37. const port = 5555;
  38. const maxConcurrent = 20; // 限制并发数,避免过载
  39. const connectTimeout = 1500; // 连接超时时间(毫秒)
  40. // 生成 IP 地址列表
  41. const ipList = [];
  42. for (let i = 1; i <= 255; i++) {
  43. ipList.push(`${baseIP}.${i}`);
  44. }
  45. const foundDevices = new Set(); // 使用 Set 避免重复
  46. // 分批并发扫描
  47. for (let i = 0; i < ipList.length; i += maxConcurrent) {
  48. const batch = ipList.slice(i, i + maxConcurrent);
  49. const promises = batch.map(async (ip) => {
  50. const ipPort = `${ip}:${port}`;
  51. try {
  52. // 先尝试连接设备
  53. await execAsync(`${adbPath} connect ${ipPort}`, {
  54. timeout: connectTimeout,
  55. maxBuffer: 1024 * 1024
  56. });
  57. // 连接后稍等片刻,让设备注册到 ADB 服务器
  58. await new Promise(resolve => setTimeout(resolve, 500));
  59. } catch (error) {
  60. // 连接失败是正常的,继续检查设备列表
  61. }
  62. // 直接使用 adb -s IP:PORT devices 命令检查该设备是否在列表中
  63. try {
  64. const { stdout } = await execAsync(`${adbPath} -s ${ipPort} devices`, {
  65. timeout: 2000,
  66. maxBuffer: 1024 * 1024
  67. });
  68. // 检查输出中是否包含 IP:PORT,如果有则说明设备存在
  69. if (stdout.includes(ipPort)) {
  70. // 发现设备,实时推送
  71. if (!foundDevices.has(ipPort)) {
  72. foundDevices.add(ipPort);
  73. const device = {
  74. id: ipPort,
  75. status: 'device'
  76. };
  77. // 实时发送发现的设备
  78. if (event && event.sender) {
  79. event.sender.send('device-found', device);
  80. } else {
  81. const mainWindow = getMainWindow();
  82. if (mainWindow) {
  83. mainWindow.webContents.send('device-found', device);
  84. }
  85. }
  86. console.log('发现设备:', ipPort);
  87. }
  88. return ipPort;
  89. }
  90. } catch (checkError) {
  91. // 检查失败,忽略
  92. }
  93. return null;
  94. });
  95. await Promise.all(promises);
  96. }
  97. // 返回所有发现的设备
  98. return Array.from(foundDevices).map(ipPort => ({
  99. id: ipPort,
  100. status: 'device'
  101. }));
  102. }
  103. // 连接 ADB 设备
  104. export async function connectDevice(ipPort) {
  105. try {
  106. const adbPath = getCachedAdbPath();
  107. await execAsync(`${adbPath} connect ${ipPort}`);
  108. return { success: true };
  109. } catch (error) {
  110. console.error('连接设备失败:', error);
  111. return { success: false, error: error.message };
  112. }
  113. }
  114. // 注册 IPC 处理器
  115. export function registerIpcHandlers() {
  116. // IPC 处理程序:获取 ADB 路径配置
  117. ipcMain.handle('get-adb-path-config', async () => {
  118. const config = loadConfig();
  119. return config ? config['adb-path'] : null;
  120. });
  121. // IPC 处理程序:获取 ADB 设备列表
  122. ipcMain.handle('get-adb-devices', async () => {
  123. return await getADBDevices();
  124. });
  125. // IPC 处理程序:扫描网络设备(支持实时推送)
  126. ipcMain.handle('scan-adb-devices', async (event) => {
  127. try {
  128. const devices = await scanNetworkDevices(event);
  129. return devices;
  130. } catch (error) {
  131. console.error('网络扫描失败:', error);
  132. return [];
  133. }
  134. });
  135. // IPC 处理程序:连接 ADB 设备
  136. ipcMain.handle('connect-adb-device', async (event, ipPort) => {
  137. return await connectDevice(ipPort);
  138. });
  139. }