init server python để điều khiển adb

This commit is contained in:
Victor Phan
2026-07-21 08:54:30 +07:00
parent d36007d989
commit 7625bdd37b
1557 changed files with 326 additions and 53 deletions
+139
View File
@@ -0,0 +1,139 @@
const { exec } = require('child_process');
const fs = require('fs');
const path = require('path');
// Lưu ý: Cần cài đặt thư viện fast-xml-parser để phân tích XML dễ dàng hơn: npm install fast-xml-parser
const { XMLParser } = require('fast-xml-parser');
// Hàm chạy lệnh shell/adb
function runCommand(cmd) {
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) {
reject(error);
} else {
resolve(stdout.trim());
}
});
});
}
// 1. Chụp màn hình và lấy cấu trúc giao diện XML từ điện thoại
async function dumpScreenUI() {
try {
console.log("Đang quét màn hình điện thoại...");
// Dump giao diện hiện tại thành file XML trên điện thoại
await runCommand('adb shell uiautomator dump /sdcard/window_dump.xml');
// Tải file XML đó về thư mục trên Armbian/máy tính
const localPath = path.join(__dirname, 'window_dump.xml');
await runCommand(`adb pull /sdcard/window_dump.xml "${localPath}"`);
console.log(`Đã tải cấu trúc màn hình về: ${localPath}`);
return localPath;
} catch (error) {
console.error("Lỗi khi dump màn hình:", error.message);
throw error;
}
}
// 2. Đọc và phân tích file XML để tìm tọa độ của chữ/nút trên màn hình
function findElementCoordinates(xmlFilePath, targetText) {
const xmlData = fs.readFileSync(xmlFilePath, 'utf8');
const parser = new XMLParser({ ignoreAttributes: false });
const jsonObj = parser.parse(xmlData);
let foundBounds = null;
// Hàm đệ quy duyệt qua toàn bộ các node XML để tìm text trùng khớp
function traverse(node) {
if (!node) return;
// Kiểm tra node hiện tại có chứa text mục tiêu không
const textAttr = node['@_text'] || '';
const descAttr = node['@_content-desc'] || '';
if (textAttr.toLowerCase().includes(targetText.toLowerCase()) ||
descAttr.toLowerCase().includes(targetText.toLowerCase())) {
foundBounds = node['@_bounds'];
return;
}
// Nếu node có các node con (node có thể là mảng hoặc object đơn lẻ)
const children = node.node;
if (children) {
if (Array.isArray(children)) {
for (let child of children) {
traverse(child);
if (foundBounds) break;
}
} else {
traverse(children);
}
}
}
// Bắt đầu duyệt từ node gốc hierarchy
if (jsonObj.hierarchy && jsonObj.hierarchy.node) {
traverse(jsonObj.hierarchy.node);
}
if (foundBounds) {
// bounds có định dạng: "[x1,y1][x2,y2]" (Ví dụ: "[100,200][300,400]")
const matches = foundBounds.match(/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/);
if (matches) {
const x1 = parseInt(matches[1]);
const y1 = parseInt(matches[2]);
const x2 = parseInt(matches[3]);
const y2 = parseInt(matches[4]);
// Tính tọa độ trung tâm của phần tử để click
const centerX = Math.floor((x1 + x2) / 2);
const centerY = Math.floor((y1 + y2) / 2);
return { x: centerX, y: centerY };
}
}
return null;
}
// 3. Điều khiển điện thoại bằng ADB
async function clickAt(x, y) {
console.log(`Đang click vào tọa độ: X=${x}, Y=${y}`);
await runCommand(`adb shell input tap ${x} ${y}`);
}
async function swipe(x1, y1, x2, y2, duration = 300) {
console.log(`Đang cuộn màn hình từ (${x1}, ${y1}) tới (${x2}, ${y2})`);
await runCommand(`adb shell input swipe ${x1} ${y1} ${x2} ${y2} ${duration}`);
}
async function inputText(text) {
console.log(`Đang nhập văn bản: "${text}"`);
// Gửi text qua ADB shell (Lưu ý: ADB mặc định không hỗ trợ tiếng Việt có dấu tốt)
await runCommand(`adb shell input text "${text}"`);
}
// 4. Kịch bản chạy mẫu (Ví dụ: Tìm nút "Mua ngay" trên Shopee và click vào)
async function startAutomation() {
try {
// Bước 1: Dump giao diện hiện tại
const xmlFile = await dumpScreenUI();
// Bước 2: Tìm tọa độ của nút có chữ "Mua ngay" hoặc "Mua Với Voucher"
const coords = findElementCoordinates(xmlFile, "Mua ngay");
if (coords) {
console.log(`Đã tìm thấy phần tử tại tọa độ:`, coords);
// Bước 3: Click vào phần tử đó
await clickAt(coords.x, coords.y);
} else {
console.log("Không tìm thấy chữ 'Mua ngay' trên màn hình hiện tại.");
// Thử cuộn màn hình xuống nếu không thấy
await swipe(500, 1500, 500, 500);
}
} catch (error) {
console.error("Lỗi kịch bản:", error);
}
}
// Chạy thử nghiệm
startAutomation();