device-manager.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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. // 每次都重新扫描网络设备,不记录已连接的设备
  15. return await scanNetworkDevices(null);
  16. } catch (error) {
  17. console.error('获取设备列表失败:', error);
  18. return [];
  19. }
  20. }
  21. // 网络扫描:从 192.168.0.1 开始扫描网段,尝试连接设备(实时推送结果)
  22. export async function scanNetworkDevices(event) {
  23. const adbPath = getCachedAdbPath();
  24. const baseIP = '192.168.0';
  25. const port = 5555;
  26. const maxConcurrent = 50; // 限制并发数,避免过载
  27. const connectTimeout = 1500; // 连接超时时间(毫秒)
  28. const foundDevices = new Set(); // 使用 Set 避免重复
  29. // 生成 IP 地址列表
  30. const ipList = [];
  31. for (let i = 1; i <= 255; i++) {
  32. ipList.push(`${baseIP}.${i}`);
  33. }
  34. // 推送设备发现的辅助函数
  35. const pushDevice = (ipPort) => {
  36. if (!foundDevices.has(ipPort)) {
  37. foundDevices.add(ipPort);
  38. const device = {
  39. id: ipPort,
  40. status: 'device'
  41. };
  42. // 实时发送发现的设备
  43. if (event && event.sender) {
  44. event.sender.send('device-found', device);
  45. } else {
  46. const mainWindow = getMainWindow();
  47. if (mainWindow) {
  48. mainWindow.webContents.send('device-found', device);
  49. }
  50. }
  51. console.log('发现设备:', ipPort);
  52. }
  53. };
  54. // 分批并发扫描,扫描到一个显示一个
  55. for (let i = 0; i < ipList.length; i += maxConcurrent) {
  56. const batch = ipList.slice(i, i + maxConcurrent);
  57. const promises = batch.map(async (ip) => {
  58. const ipPort = `${ip}:${port}`;
  59. try {
  60. // 先尝试连接设备
  61. await execAsync(`${adbPath} connect ${ipPort}`, {
  62. timeout: connectTimeout,
  63. maxBuffer: 1024 * 1024
  64. });
  65. // 连接后稍等片刻,让设备注册到 ADB 服务器
  66. await new Promise(resolve => setTimeout(resolve, 500));
  67. } catch (error) {
  68. // 连接失败是正常的,继续检查设备列表
  69. }
  70. // 调用 adb devices 命令获取所有设备列表,检查是否包含端口 5555 的设备
  71. try {
  72. const { stdout } = await execAsync(`${adbPath} devices`, {
  73. timeout: 2000,
  74. maxBuffer: 1024 * 1024
  75. });
  76. // 检查输出中是否包含该 IP:PORT(匹配端口 5555)
  77. // 使用正则表达式匹配 IP:5555 格式
  78. const devicePattern = new RegExp(`${ip.replace(/\./g, '\\.')}:${port}\\s+device`, 'i');
  79. if (devicePattern.test(stdout)) {
  80. // 发现设备,立即推送显示(不等待整批完成)
  81. pushDevice(ipPort);
  82. return ipPort;
  83. }
  84. // 如果没有匹配到,说明没有设备
  85. } catch (checkError) {
  86. // 检查失败,忽略
  87. }
  88. return null;
  89. });
  90. // 并发执行当前批次,但不等待所有完成才推送
  91. // 每个 promise 一旦发现设备就会立即推送
  92. await Promise.all(promises);
  93. }
  94. // 返回所有发现的设备
  95. return Array.from(foundDevices).map(ipPort => ({
  96. id: ipPort,
  97. status: 'device'
  98. }));
  99. }
  100. // 连接 ADB 设备
  101. export async function connectDevice(ipPort) {
  102. try {
  103. const adbPath = getCachedAdbPath();
  104. await execAsync(`${adbPath} connect ${ipPort}`);
  105. return { success: true };
  106. } catch (error) {
  107. console.error('连接设备失败:', error);
  108. return { success: false, error: error.message };
  109. }
  110. }
  111. // 注册 IPC 处理器
  112. export function registerIpcHandlers() {
  113. // IPC 处理程序:获取 ADB 路径配置
  114. ipcMain.handle('get-adb-path-config', async () => {
  115. const config = loadConfig();
  116. return config ? config['adb-path'] : null;
  117. });
  118. // IPC 处理程序:获取 ADB 设备列表
  119. ipcMain.handle('get-adb-devices', async () => {
  120. return await getADBDevices();
  121. });
  122. // IPC 处理程序:扫描网络设备(支持实时推送)
  123. ipcMain.handle('scan-adb-devices', async (event) => {
  124. try {
  125. const devices = await scanNetworkDevices(event);
  126. return devices;
  127. } catch (error) {
  128. console.error('网络扫描失败:', error);
  129. return [];
  130. }
  131. });
  132. // IPC 处理程序:连接 ADB 设备
  133. ipcMain.handle('connect-adb-device', async (event, ipPort) => {
  134. return await connectDevice(ipPort);
  135. });
  136. }