fix(wp-wx-04): improve scan probe and u2 fallback
This commit is contained in:
@@ -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_text(dump 不到时失败)+ 坐标兜底
|
||||
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}"}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user