UI自动化能力优化
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
"""安装 Airtest 辅助工具(minicap/yosemite)到设备"""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
def emit(event_type, level="INFO", message="", **extra):
|
||||
payload = {"type": event_type, "level": level, "message": message}
|
||||
payload.update(extra)
|
||||
print(json.dumps(payload, ensure_ascii=False), flush=True)
|
||||
|
||||
|
||||
def find_adb():
|
||||
"""查找 adb 可执行文件"""
|
||||
venv_dir = os.path.join(os.path.dirname(__file__), "..", ".venv")
|
||||
candidates = [
|
||||
os.path.join(venv_dir, "Lib", "site-packages", "airtest", "core", "android", "static", "adb", "windows", "adb.exe"),
|
||||
os.path.join(venv_dir, "lib", "python3.11", "site-packages", "airtest", "core", "android", "static", "adb", "linux", "adb"),
|
||||
os.path.join(venv_dir, "lib", "python3.10", "site-packages", "airtest", "core", "android", "static", "adb", "linux", "adb"),
|
||||
]
|
||||
for c in candidates:
|
||||
if os.path.exists(c):
|
||||
return c
|
||||
return "adb"
|
||||
|
||||
|
||||
def install_minicap(device_uri):
|
||||
"""通过 Airtest 安装 minicap 并验证"""
|
||||
try:
|
||||
from airtest.core.api import auto_setup
|
||||
import logging
|
||||
logging.getLogger("airtest").setLevel(logging.INFO)
|
||||
|
||||
# 提取 serial
|
||||
serial = device_uri.replace("Android:///", "").strip()
|
||||
serial = serial.split("?")[0] if "?" in serial else serial
|
||||
|
||||
emit("log", "INFO", "正在连接设备并安装 minicap...")
|
||||
# 不使用 cap_method=adbcap,让 Airtest 尝试安装 minicap
|
||||
auto_setup(__file__, devices=[device_uri])
|
||||
|
||||
# 等待安装完成
|
||||
time.sleep(3)
|
||||
|
||||
# 通过 ADB 检查 minicap 二进制文件是否存在于设备上
|
||||
adb = find_adb()
|
||||
check_cmd = [adb]
|
||||
if serial:
|
||||
check_cmd.extend(["-s", serial])
|
||||
check_cmd.extend(["shell", "ls", "/data/local/tmp/minicap"])
|
||||
|
||||
emit("log", "INFO", "检查 minicap 是否已安装到设备...")
|
||||
result = subprocess.run(check_cmd, capture_output=True, text=True, timeout=10)
|
||||
combined = (result.stdout + result.stderr).strip()
|
||||
|
||||
if "No such file" in combined or "not found" in combined.lower():
|
||||
emit("log", "WARN", "minicap 二进制文件未找到,安装失败")
|
||||
return False
|
||||
|
||||
# minicap 文件存在,进一步验证是否能正常运行
|
||||
# 尝试启动 minicap 并立即停止
|
||||
test_cmd = [adb]
|
||||
if serial:
|
||||
test_cmd.extend(["-s", serial])
|
||||
test_cmd.extend(["shell", "LD_LIBRARY_PATH=/data/local/tmp", "/data/local/tmp/minicap", "-i"])
|
||||
|
||||
emit("log", "INFO", "验证 minicap 是否可正常运行...")
|
||||
try:
|
||||
test_result = subprocess.run(test_cmd, capture_output=True, text=True, timeout=5)
|
||||
test_output = (test_result.stdout + test_result.stderr).strip()
|
||||
if "pid=" in test_output or "web socket" in test_output.lower() or result.returncode == 0:
|
||||
emit("log", "INFO", "minicap 安装成功且可正常运行")
|
||||
return True
|
||||
else:
|
||||
emit("log", "WARN", f"minicap 运行测试输出: {test_output}")
|
||||
# 即使测试输出不明确,文件存在也算安装成功
|
||||
return True
|
||||
except subprocess.TimeoutExpired:
|
||||
# minicap 作为服务运行会超时,这是正常的
|
||||
emit("log", "INFO", "minicap 安装成功(服务进程已启动)")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
emit("log", "ERROR", f"安装 minicap 失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def install_yosemite(device_uri):
|
||||
"""安装 Yosemite APK(用于 javacap 截图)"""
|
||||
try:
|
||||
from airtest.core.api import auto_setup, connect_device
|
||||
import logging
|
||||
logging.getLogger("airtest").setLevel(logging.INFO)
|
||||
|
||||
serial = device_uri.replace("Android:///", "").strip()
|
||||
serial = serial.split("?")[0] if "?" in serial else serial
|
||||
|
||||
emit("log", "INFO", "正在连接设备...")
|
||||
auto_setup(__file__, devices=[device_uri])
|
||||
time.sleep(1)
|
||||
|
||||
# 通过 Airtest 的 Android 设备对象直接安装 Yosemite
|
||||
from airtest.core.helper import G
|
||||
device = G.DEVICE
|
||||
|
||||
emit("log", "INFO", "正在安装 Yosemite APK...")
|
||||
# 使用设备对象的 yosemite 安装方法
|
||||
try:
|
||||
from airtest.core.android.yosemite import Yosemite
|
||||
yosemite = Yosemite(device.adb)
|
||||
yosemite.install_or_upgrade()
|
||||
emit("log", "INFO", "Yosemite 安装成功")
|
||||
return True
|
||||
except TypeError:
|
||||
# 旧版本 API 兼容
|
||||
from airtest.core.android.yosemite import Yosemite
|
||||
yosemite = Yosemite(device)
|
||||
yosemite.install_or_upgrade()
|
||||
emit("log", "INFO", "Yosemite 安装成功")
|
||||
return True
|
||||
except Exception as e:
|
||||
emit("log", "WARN", f"Yosemite 安装失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="安装 Airtest 辅助工具")
|
||||
parser.add_argument("--device", default="Android:///")
|
||||
parser.add_argument("--tool", default="minicap", choices=["minicap", "yosemite", "all"])
|
||||
parser.add_argument("--marker-dir", required=True, help="标记文件存放目录")
|
||||
args = parser.parse_args()
|
||||
|
||||
os.makedirs(args.marker_dir, exist_ok=True)
|
||||
# 从设备 URI 中提取 serial 用于标记文件名
|
||||
serial = args.device.replace("Android:///", "").strip()
|
||||
serial = serial.split("?")[0] if "?" in serial else serial
|
||||
serial = serial if serial else "default"
|
||||
safe_serial = serial.replace(":", "_").replace("/", "_")
|
||||
|
||||
results = {"minicap": False, "yosemite": False}
|
||||
|
||||
if args.tool in ("minicap", "all"):
|
||||
results["minicap"] = install_minicap(args.device)
|
||||
|
||||
if args.tool in ("yosemite", "all"):
|
||||
results["yosemite"] = install_yosemite(args.device)
|
||||
|
||||
# 写入标记文件
|
||||
for tool_name, success in results.items():
|
||||
marker_file = os.path.join(args.marker_dir, f".{tool_name}-{safe_serial}")
|
||||
if success:
|
||||
with open(marker_file, "w") as f:
|
||||
f.write(json.dumps({"installed": True, "time": time.strftime("%Y-%m-%d %H:%M:%S")}))
|
||||
emit("log", "INFO", f"{tool_name} 安装成功,已写入标记文件")
|
||||
else:
|
||||
# 如果失败,删除已有标记文件
|
||||
if os.path.exists(marker_file):
|
||||
os.remove(marker_file)
|
||||
emit("log", "WARN", f"{tool_name} 安装失败,已清除标记")
|
||||
|
||||
# 输出最终结果
|
||||
any_success = any(results.values())
|
||||
emit("result", "INFO" if any_success else "ERROR",
|
||||
json.dumps(results, ensure_ascii=False),
|
||||
success=any_success)
|
||||
return 0 if any_success else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
"""安装 Airtest 辅助工具(minicap/yosemite)到设备"""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
def emit(event_type, level="INFO", message="", **extra):
|
||||
payload = {"type": event_type, "level": level, "message": message}
|
||||
payload.update(extra)
|
||||
print(json.dumps(payload, ensure_ascii=False), flush=True)
|
||||
|
||||
|
||||
def install_minicap(device_uri):
|
||||
"""通过 Airtest 安装 minicap 并验证"""
|
||||
try:
|
||||
from airtest.core.api import auto_setup, snapshot
|
||||
from airtest.core.android import Android as AndroidDevice
|
||||
import logging
|
||||
logging.getLogger("airtest").setLevel(logging.INFO)
|
||||
|
||||
emit("log", "INFO", "正在连接设备...")
|
||||
# 不使用 cap_method=adbcap,让 Airtest 尝试安装 minicap
|
||||
auto_setup(__file__, devices=[device_uri])
|
||||
|
||||
emit("log", "INFO", "设备已连接,正在初始化截图组件...")
|
||||
# Airtest 在 auto_setup 时会自动安装 minicap,
|
||||
# 尝试截图来验证是否安装成功
|
||||
time.sleep(2)
|
||||
test_path = os.path.join(os.path.dirname(__file__), "..", "test_minicap.png")
|
||||
try:
|
||||
snapshot(filename=test_path)
|
||||
if os.path.exists(test_path) and os.path.getsize(test_path) > 100:
|
||||
os.remove(test_path)
|
||||
emit("log", "INFO", "minicap 安装成功,截图验证通过")
|
||||
return True
|
||||
else:
|
||||
emit("log", "WARN", "截图文件过小,minicap 可能未正确安装")
|
||||
if os.path.exists(test_path):
|
||||
os.remove(test_path)
|
||||
return False
|
||||
except Exception as e:
|
||||
emit("log", "WARN", f"minicap 截图测试失败: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
emit("log", "ERROR", f"安装 minicap 失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def install_yosemite(device_uri):
|
||||
"""安装 Yosemite APK(用于 javacap 截图)"""
|
||||
try:
|
||||
from airtest.core.api import auto_setup
|
||||
from airtest.core.android.yosemite import Yosemite
|
||||
import logging
|
||||
logging.getLogger("airtest").setLevel(logging.INFO)
|
||||
|
||||
emit("log", "INFO", "正在安装 Yosemite APK...")
|
||||
auto_setup(__file__, devices=[device_uri])
|
||||
yosemite = Yosemite()
|
||||
yosemite.install_or_upgrade()
|
||||
emit("log", "INFO", "Yosemite 安装成功")
|
||||
return True
|
||||
except Exception as e:
|
||||
emit("log", "WARN", f"Yosemite 安装失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="安装 Airtest 辅助工具")
|
||||
parser.add_argument("--device", default="Android:///")
|
||||
parser.add_argument("--tool", default="minicap", choices=["minicap", "yosemite", "all"])
|
||||
parser.add_argument("--marker-dir", required=True, help="标记文件存放目录")
|
||||
args = parser.parse_args()
|
||||
|
||||
os.makedirs(args.marker_dir, exist_ok=True)
|
||||
# 从设备 URI 中提取 serial 用于标记文件名
|
||||
serial = args.device.replace("Android:///", "").strip()
|
||||
serial = serial.split("?")[0] if "?" in serial else serial
|
||||
serial = serial if serial else "default"
|
||||
safe_serial = serial.replace(":", "_").replace("/", "_")
|
||||
|
||||
results = {"minicap": False, "yosemite": False}
|
||||
|
||||
if args.tool in ("minicap", "all"):
|
||||
results["minicap"] = install_minicap(args.device)
|
||||
|
||||
if args.tool in ("yosemite", "all"):
|
||||
results["yosemite"] = install_yosemite(args.device)
|
||||
|
||||
# 写入标记文件
|
||||
for tool_name, success in results.items():
|
||||
marker_file = os.path.join(args.marker_dir, f".{tool_name}-{safe_serial}")
|
||||
if success:
|
||||
with open(marker_file, "w") as f:
|
||||
f.write(json.dumps({"installed": True, "time": time.strftime("%Y-%m-%d %H:%M:%S")}))
|
||||
emit("log", "INFO", f"{tool_name} 安装成功,已写入标记文件")
|
||||
else:
|
||||
# 如果失败,删除已有标记文件
|
||||
if os.path.exists(marker_file):
|
||||
os.remove(marker_file)
|
||||
|
||||
# 输出最终结果
|
||||
any_success = any(results.values())
|
||||
emit("result", "INFO" if any_success else "ERROR",
|
||||
json.dumps(results, ensure_ascii=False),
|
||||
success=any_success)
|
||||
return 0 if any_success else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user