fix(wp-wx-04): improve scan probe and u2 fallback

This commit is contained in:
Manus AI
2026-06-28 06:09:29 +08:00
parent ad477806be
commit 9947c02c63
6 changed files with 1594 additions and 204 deletions

View File

@@ -3072,10 +3072,36 @@ class WechatSkill(BaseSkill):
def _save_qr_image_to_album(self, image_base64: str = "", image_url: str = "") -> str:
"""WP-WX-04二维码图落盘相册并触发媒体扫描失败返回空串。"""
import base64
import shutil
import subprocess
import tempfile
dst = f"/sdcard/Pictures/wp_qr_{int(time.time())}.png"
try:
self.d.shell(f"mkdir -p {shlex.quote(os.path.dirname(dst))}", timeout=8)
def adb_push_fallback(local_path: str) -> bool:
adb_bin = shutil.which("adb")
serial = (
getattr(self.d, "serial", "")
or getattr(self, "device_id", "")
or os.environ.get("ANDROID_SERIAL", "")
)
if not adb_bin or not serial:
return False
try:
subprocess.run(
[adb_bin, "-s", serial, "push", local_path, dst],
check=True,
capture_output=True,
text=True,
timeout=30,
)
return True
except Exception as adb_err:
logger.warning("save_qr_image_to_album adb push fallback failed: %s", adb_err)
return False
if image_url:
self.d.shell(
f"curl -sL -o {shlex.quote(dst)} {shlex.quote(image_url)}",
@@ -3088,7 +3114,14 @@ class WechatSkill(BaseSkill):
f.write(raw)
local = f.name
try:
self.d.push(local, dst)
pushed = False
try:
self.d.push(local, dst)
pushed = True
except Exception as push_err:
logger.warning("save_qr_image_to_album u2 push failed: %s", push_err)
if not pushed and not adb_push_fallback(local):
return ""
finally:
os.unlink(local)
else:
@@ -3114,48 +3147,68 @@ class WechatSkill(BaseSkill):
- u2 dump_hierarchy 不到微信节点SurfaceView/自绘限制)
- u2 click 被 MIUI INJECT_EVENTS 拦截
- 改用 root am start + root input tap 坐标点击
- 坐标基于真机截图分析验证
- 权限弹窗与 AlbumPreviewUI 用多坐标兜底
"""
import subprocess as _sp
try:
def current_focus() -> str:
try:
return self.d.shell("dumpsys window | grep mCurrentFocus").output or ""
except Exception:
return ""
def tap(x: int, y: int, wait_sec: float = 1.5) -> None:
self.d.shell(f"su -c 'input tap {x} {y}'")
self.sleep(wait_sec)
# 1. root am start 直接打开扫一扫(绕过 u2 click "+" 菜单)
self.d.shell("su -c 'am start -n com.tencent.mm/.plugin.scanner.ui.BaseScanUI'")
self.sleep(2)
# 2. 点相册按钮937,2012 · 真机验证)
self.d.shell("su -c 'input tap 937 2012'")
self.sleep(2)
# 3. 处理可能的 MIUI 权限弹窗(第一次点相册会弹存储权限)
try:
focus = self.d.shell("dumpsys window | grep mCurrentFocus").output or ""
if "GrantPermissions" in focus:
self.d.shell("su -c 'input tap 540 1700'") # 允许
self.sleep(2)
tap(937, 2012, 2)
# 3. 处理 MIUI/微信自有权限弹窗;焦点有时不叫 GrantPermissions
focus = current_focus()
focus_norm = focus.lower()
if any(key in focus_norm for key in ("grantpermissions", "permission", "permis")):
for allow_x, allow_y in ((830, 1710), (540, 1710)):
tap(allow_x, allow_y, 1.5)
self.d.shell("su -c 'am start -n com.tencent.mm/.plugin.scanner.ui.BaseScanUI'")
self.sleep(1.5)
self.d.shell("su -c 'input tap 937 2012'") # 再点相册
self.sleep(2)
except Exception:
pass
# 4. 检查是否进入相册(焦点应含 AlbumPreviewUI 或 AlbumPickerUI
try:
focus2 = self.d.shell("dumpsys window | grep mCurrentFocus").output or ""
if "gallery" not in focus2.lower() and "album" not in focus2.lower():
return {"success": False, "error": f"未进入相册界面(焦点={focus2[:80]})"}
except Exception:
pass
tap(937, 2012, 2)
focus_norm = current_focus().lower()
if "gallery" in focus_norm or "album" in focus_norm:
break
# 4. 检查是否进入相册(焦点应含 AlbumPreviewUI / AlbumPickerUI / gallery
focus2 = current_focus()
focus2_norm = focus2.lower()
if "gallery" not in focus2_norm and "album" not in focus2_norm:
return {"success": False, "error": f"未进入相册界面(焦点={focus2[:120]})"}
# 5. 点第一张图270,400 · 3列网格第一张 · 真机验证)
self.d.shell("su -c 'input tap 270 400'")
self.sleep(2)
tap(270, 400, 2)
# 6. 在 AlbumPreviewUI 点"完成"按钮
# 尝试 u2 click_textdump 不到时失败)+ 坐标兜底
ok = self.click_text("完成") or self.click_contains("完成")
if not ok:
# 坐标兜底:完成按钮通常在右下角(真机待精确定位,暂用常见位置)
self.d.shell("su -c 'input tap 950 2300'")
self.sleep(2)
# `/tmp/find_btn_out.txt` 像素分析显示底部中心高亮明显,优先点底部中心,再试右下/右上。
for finish_x, finish_y in ((528, 2330), (950, 2300), (950, 120)):
tap(finish_x, finish_y, 1.5)
xml_try = self.d.dump_hierarchy(compressed=True)
if any(flag in xml_try for flag in ("添加到通讯录", "发消息", "二维码已过期", "二维码无效")):
ok = True
break
xml = self.d.dump_hierarchy(compressed=True)
texts = re.findall(r'text="([^"]+)"', xml)[:15]
return {"success": True, "note": "已从相册选取图片识别二维码", "page_texts": texts}
if any(flag in xml for flag in ("添加到通讯录", "发消息", "二维码已过期", "二维码无效")):
return {"success": True, "note": "已从相册选取图片识别二维码", "page_texts": texts}
return {
"success": False,
"error": "已选取图片但未进入二维码结果页",
"page_texts": texts,
}
except Exception as e:
return {"success": False, "error": f"扫一扫相册流程异常: {e}"}