init server python để điều khiển adb
This commit is contained in:
@@ -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();
|
||||
Reference in New Issue
Block a user