208 lines
5.3 KiB
Python
208 lines
5.3 KiB
Python
"""
|
||
工作手机SDK v3.0 - ADB设备路由
|
||
直接ADB控制模式(支持模拟器和真机)
|
||
|
||
所有端点使用 def(非 async def),FastAPI 自动在线程池中执行,
|
||
避免同步 ADB shell 命令阻塞事件循环。
|
||
"""
|
||
|
||
from fastapi import APIRouter, HTTPException
|
||
from pydantic import BaseModel
|
||
from typing import Optional
|
||
import sys
|
||
import os
|
||
|
||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||
from services.adb_device import adb_manager
|
||
|
||
router = APIRouter(prefix="/api/v3/adb", tags=["ADB设备控制"])
|
||
|
||
|
||
# ========== 请求模型 ==========
|
||
|
||
class ClickRequest(BaseModel):
|
||
x: int
|
||
y: int
|
||
|
||
|
||
class ClickTextRequest(BaseModel):
|
||
text: str
|
||
timeout: float = 10
|
||
|
||
|
||
class InputRequest(BaseModel):
|
||
text: str
|
||
clear: bool = True
|
||
|
||
|
||
class SwipeRequest(BaseModel):
|
||
direction: str
|
||
scale: float = 0.5
|
||
|
||
|
||
class AppRequest(BaseModel):
|
||
package: str
|
||
|
||
|
||
class KeyRequest(BaseModel):
|
||
key: str
|
||
|
||
|
||
# ========== 设备管理 ==========
|
||
|
||
@router.get("/devices")
|
||
def list_devices():
|
||
"""获取所有ADB设备"""
|
||
devices = adb_manager.list_devices()
|
||
return {"code": 200, "data": devices}
|
||
|
||
|
||
@router.get("/scan")
|
||
@router.post("/scan")
|
||
def scan_devices():
|
||
"""扫描设备(含未授权设备的完整信息)"""
|
||
serials = adb_manager.scan_devices()
|
||
all_devices = adb_manager.scan_all_devices()
|
||
return {
|
||
"code": 200,
|
||
"data": {
|
||
"devices": serials,
|
||
"all_devices": all_devices,
|
||
"authorized_count": len(serials),
|
||
"total_count": len(all_devices),
|
||
},
|
||
}
|
||
|
||
|
||
@router.get("/devices/{serial}")
|
||
def get_device_info(serial: str):
|
||
"""获取设备详情"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
info = device.get_info()
|
||
info["status"] = "online" if device.is_online() else "offline"
|
||
return {"code": 200, "data": info}
|
||
|
||
|
||
# ========== 基础操作 ==========
|
||
|
||
@router.post("/devices/{serial}/screenshot")
|
||
def screenshot(serial: str):
|
||
"""截图"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
return device.screenshot()
|
||
|
||
|
||
@router.post("/devices/{serial}/click")
|
||
def click(serial: str, req: ClickRequest):
|
||
"""点击坐标"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
return device.click(req.x, req.y)
|
||
|
||
|
||
@router.post("/devices/{serial}/click-text")
|
||
def click_text(serial: str, req: ClickTextRequest):
|
||
"""点击文字"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
return device.click_text(req.text, req.timeout)
|
||
|
||
|
||
@router.post("/devices/{serial}/input")
|
||
def input_text(serial: str, req: InputRequest):
|
||
"""输入文字"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
return device.input_text(req.text, req.clear)
|
||
|
||
|
||
@router.post("/devices/{serial}/swipe")
|
||
def swipe(serial: str, req: SwipeRequest):
|
||
"""滑动"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
return device.swipe(req.direction, req.scale)
|
||
|
||
|
||
@router.post("/devices/{serial}/key")
|
||
def press_key(serial: str, req: KeyRequest):
|
||
"""按键"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
return device.press_key(req.key)
|
||
|
||
|
||
# ========== APP操作 ==========
|
||
|
||
@router.post("/devices/{serial}/app/start")
|
||
def start_app(serial: str, req: AppRequest):
|
||
"""启动APP"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
return device.start_app(req.package)
|
||
|
||
|
||
@router.post("/devices/{serial}/app/stop")
|
||
def stop_app(serial: str, req: AppRequest):
|
||
"""停止APP"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
return device.stop_app(req.package)
|
||
|
||
|
||
@router.get("/devices/{serial}/app/current")
|
||
def current_app(serial: str):
|
||
"""获取当前APP"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
return device.current_app()
|
||
|
||
|
||
@router.get("/devices/{serial}/app/list")
|
||
def list_apps(serial: str):
|
||
"""获取已安装APP"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
return device.installed_apps()
|
||
|
||
|
||
# ========== UI ==========
|
||
|
||
@router.get("/devices/{serial}/ui-tree")
|
||
def get_ui_tree(serial: str):
|
||
"""获取UI树(XML 已做 JSON-safe 转义)"""
|
||
device = adb_manager.get_device(serial)
|
||
if not device:
|
||
raise HTTPException(status_code=404, detail="设备不存在")
|
||
|
||
result = device.get_ui_tree()
|
||
if isinstance(result, dict) and "data" in result:
|
||
xml = result["data"].get("xml", "")
|
||
if isinstance(xml, str):
|
||
result["data"]["xml"] = xml.replace("\x00", "").replace("\r", "")
|
||
return result
|