mobile-mcp-ai 2.5.8__py3-none-any.whl → 2.5.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mobile_mcp/core/basic_tools_lite.py +39 -12
- mobile_mcp/core/mobile_client.py +23 -2
- {mobile_mcp_ai-2.5.8.dist-info → mobile_mcp_ai-2.5.9.dist-info}/METADATA +1 -1
- {mobile_mcp_ai-2.5.8.dist-info → mobile_mcp_ai-2.5.9.dist-info}/RECORD +8 -8
- {mobile_mcp_ai-2.5.8.dist-info → mobile_mcp_ai-2.5.9.dist-info}/WHEEL +0 -0
- {mobile_mcp_ai-2.5.8.dist-info → mobile_mcp_ai-2.5.9.dist-info}/entry_points.txt +0 -0
- {mobile_mcp_ai-2.5.8.dist-info → mobile_mcp_ai-2.5.9.dist-info}/licenses/LICENSE +0 -0
- {mobile_mcp_ai-2.5.8.dist-info → mobile_mcp_ai-2.5.9.dist-info}/top_level.txt +0 -0
|
@@ -53,7 +53,34 @@ class BasicMobileToolsLite:
|
|
|
53
53
|
}
|
|
54
54
|
self.operation_history.append(record)
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
def _get_full_hierarchy(self) -> str:
|
|
57
|
+
"""获取完整的 UI 层级 XML(包含 NAF 元素)
|
|
58
|
+
|
|
59
|
+
优先使用 ADB 直接 dump,比 uiautomator2.dump_hierarchy 更完整
|
|
60
|
+
"""
|
|
61
|
+
import sys
|
|
62
|
+
|
|
63
|
+
if self._is_ios():
|
|
64
|
+
# iOS 使用 page_source
|
|
65
|
+
ios_client = self._get_ios_client()
|
|
66
|
+
if ios_client and hasattr(ios_client, 'wda'):
|
|
67
|
+
return ios_client.wda.source()
|
|
68
|
+
return ""
|
|
69
|
+
|
|
70
|
+
# Android: 优先使用 ADB 直接 dump
|
|
71
|
+
try:
|
|
72
|
+
# 方法1: ADB dump(获取最完整的 UI 树,包括 NAF 元素)
|
|
73
|
+
self.client.u2.shell('uiautomator dump /sdcard/ui_dump.xml')
|
|
74
|
+
result = self.client.u2.shell('cat /sdcard/ui_dump.xml')
|
|
75
|
+
if result and isinstance(result, str) and result.strip().startswith('<?xml'):
|
|
76
|
+
xml_string = result.strip()
|
|
77
|
+
self.client.u2.shell('rm /sdcard/ui_dump.xml')
|
|
78
|
+
return xml_string
|
|
79
|
+
except Exception as e:
|
|
80
|
+
print(f" ⚠️ ADB dump 失败: {e}", file=sys.stderr)
|
|
81
|
+
|
|
82
|
+
# 方法2: 回退到 uiautomator2
|
|
83
|
+
return self.client.u2.dump_hierarchy(compressed=False)
|
|
57
84
|
|
|
58
85
|
# ==================== 截图 ====================
|
|
59
86
|
|
|
@@ -354,7 +381,7 @@ class BasicMobileToolsLite:
|
|
|
354
381
|
if show_popup_hints and not self._is_ios():
|
|
355
382
|
try:
|
|
356
383
|
import xml.etree.ElementTree as ET
|
|
357
|
-
xml_string = self.
|
|
384
|
+
xml_string = self._get_full_hierarchy()
|
|
358
385
|
root = ET.fromstring(xml_string)
|
|
359
386
|
|
|
360
387
|
# 检测弹窗区域
|
|
@@ -531,7 +558,7 @@ class BasicMobileToolsLite:
|
|
|
531
558
|
else:
|
|
532
559
|
try:
|
|
533
560
|
import xml.etree.ElementTree as ET
|
|
534
|
-
xml_string = self.
|
|
561
|
+
xml_string = self._get_full_hierarchy()
|
|
535
562
|
root = ET.fromstring(xml_string)
|
|
536
563
|
|
|
537
564
|
for elem in root.iter():
|
|
@@ -1087,9 +1114,9 @@ class BasicMobileToolsLite:
|
|
|
1087
1114
|
return {"success": False, "message": f"❌ 点击失败: {e}"}
|
|
1088
1115
|
|
|
1089
1116
|
def _find_element_in_tree(self, text: str) -> Optional[Dict]:
|
|
1090
|
-
"""在 XML
|
|
1117
|
+
"""在 XML 树中查找包含指定文本的元素(使用完整 UI 层级)"""
|
|
1091
1118
|
try:
|
|
1092
|
-
xml = self.
|
|
1119
|
+
xml = self._get_full_hierarchy()
|
|
1093
1120
|
import xml.etree.ElementTree as ET
|
|
1094
1121
|
root = ET.fromstring(xml)
|
|
1095
1122
|
|
|
@@ -1831,7 +1858,7 @@ class BasicMobileToolsLite:
|
|
|
1831
1858
|
return ios_client.list_elements()
|
|
1832
1859
|
return [{"error": "iOS 暂不支持元素列表,建议使用截图"}]
|
|
1833
1860
|
else:
|
|
1834
|
-
xml_string = self.
|
|
1861
|
+
xml_string = self._get_full_hierarchy()
|
|
1835
1862
|
elements = self.client.xml_parser.parse(xml_string)
|
|
1836
1863
|
|
|
1837
1864
|
result = []
|
|
@@ -1867,8 +1894,8 @@ class BasicMobileToolsLite:
|
|
|
1867
1894
|
screen_width = self.client.u2.info.get('displayWidth', 720)
|
|
1868
1895
|
screen_height = self.client.u2.info.get('displayHeight', 1280)
|
|
1869
1896
|
|
|
1870
|
-
#
|
|
1871
|
-
xml_string = self.
|
|
1897
|
+
# 获取元素列表(使用完整 UI 层级)
|
|
1898
|
+
xml_string = self._get_full_hierarchy()
|
|
1872
1899
|
import xml.etree.ElementTree as ET
|
|
1873
1900
|
root = ET.fromstring(xml_string)
|
|
1874
1901
|
|
|
@@ -2021,8 +2048,8 @@ class BasicMobileToolsLite:
|
|
|
2021
2048
|
screen_width = self.client.u2.info.get('displayWidth', 720)
|
|
2022
2049
|
screen_height = self.client.u2.info.get('displayHeight', 1280)
|
|
2023
2050
|
|
|
2024
|
-
# 获取原始 XML
|
|
2025
|
-
xml_string = self.
|
|
2051
|
+
# 获取原始 XML(使用完整 UI 层级)
|
|
2052
|
+
xml_string = self._get_full_hierarchy()
|
|
2026
2053
|
|
|
2027
2054
|
# 关闭按钮的文本特征
|
|
2028
2055
|
close_texts = ['×', 'X', 'x', '关闭', '取消', 'close', 'Close', 'CLOSE', '跳过', '知道了']
|
|
@@ -2893,8 +2920,8 @@ class BasicMobileToolsLite:
|
|
|
2893
2920
|
try:
|
|
2894
2921
|
import xml.etree.ElementTree as ET
|
|
2895
2922
|
|
|
2896
|
-
# ========== 第1
|
|
2897
|
-
xml_string = self.
|
|
2923
|
+
# ========== 第1步:控件树查找关闭按钮(使用完整 UI 层级)==========
|
|
2924
|
+
xml_string = self._get_full_hierarchy()
|
|
2898
2925
|
root = ET.fromstring(xml_string)
|
|
2899
2926
|
|
|
2900
2927
|
# 关闭按钮的常见特征
|
mobile_mcp/core/mobile_client.py
CHANGED
|
@@ -189,8 +189,29 @@ class MobileClient:
|
|
|
189
189
|
return xml_string
|
|
190
190
|
|
|
191
191
|
# Android平台
|
|
192
|
-
# 获取XML
|
|
193
|
-
xml_string =
|
|
192
|
+
# 获取XML - 优先使用 ADB 直接 dump(更完整,包含 NAF 元素)
|
|
193
|
+
xml_string = None
|
|
194
|
+
try:
|
|
195
|
+
# 方法1: 使用 ADB 直接 dump(获取最完整的 UI 树,包括 NAF 元素)
|
|
196
|
+
import subprocess
|
|
197
|
+
import tempfile
|
|
198
|
+
import os
|
|
199
|
+
|
|
200
|
+
# 在设备上执行 dump
|
|
201
|
+
self.u2.shell('uiautomator dump /sdcard/ui_dump.xml')
|
|
202
|
+
|
|
203
|
+
# 读取文件内容
|
|
204
|
+
result = self.u2.shell('cat /sdcard/ui_dump.xml')
|
|
205
|
+
if result and isinstance(result, str) and result.strip().startswith('<?xml'):
|
|
206
|
+
xml_string = result.strip()
|
|
207
|
+
# 清理临时文件
|
|
208
|
+
self.u2.shell('rm /sdcard/ui_dump.xml')
|
|
209
|
+
except Exception as e:
|
|
210
|
+
print(f" ⚠️ ADB dump 失败,使用 uiautomator2: {e}", file=sys.stderr)
|
|
211
|
+
|
|
212
|
+
# 方法2: 回退到 uiautomator2 的 dump_hierarchy
|
|
213
|
+
if not xml_string:
|
|
214
|
+
xml_string = self.u2.dump_hierarchy(compressed=False)
|
|
194
215
|
|
|
195
216
|
# 确保xml_string是字符串类型
|
|
196
217
|
if not isinstance(xml_string, str):
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
mobile_mcp/__init__.py,sha256=sQJZTL_sxQFzmcS7jOtS2AHCfUySz40vhX96N6u1qy4,816
|
|
2
2
|
mobile_mcp/config.py,sha256=yaFLAV4bc2wX0GQPtZDo7OYF9E88tXV-av41fQsJwK4,4480
|
|
3
3
|
mobile_mcp/core/__init__.py,sha256=ndMy-cLAIsQDG5op7gM_AIplycqZSZPWEkec1pEhvEY,170
|
|
4
|
-
mobile_mcp/core/basic_tools_lite.py,sha256=
|
|
4
|
+
mobile_mcp/core/basic_tools_lite.py,sha256=C9_mptagHKGgGfPUxzmoM0t080JNERYDDNb0OrbV8sQ,154736
|
|
5
5
|
mobile_mcp/core/device_manager.py,sha256=xG5DoeNFs45pl-FTEhEWblqVwxtFK-FmVEGlNL6EqRI,8798
|
|
6
6
|
mobile_mcp/core/dynamic_config.py,sha256=Ja1n1pfb0HspGByqk2_A472mYVniKmGtNEWyjUjmgK8,9811
|
|
7
7
|
mobile_mcp/core/ios_client_wda.py,sha256=Nq9WxevhTWpVpolM-Ymp-b0nUQV3tXLFszmJHbDC4wA,18770
|
|
8
8
|
mobile_mcp/core/ios_device_manager_wda.py,sha256=A44glqI-24un7qST-E3w6BQD8mV92YVUbxy4rLlTScY,11264
|
|
9
|
-
mobile_mcp/core/mobile_client.py,sha256=
|
|
9
|
+
mobile_mcp/core/mobile_client.py,sha256=AaBntQSW2loAw7xL3j_IABNzrJO_Uukf9-F1z1xl6xE,63672
|
|
10
10
|
mobile_mcp/core/template_matcher.py,sha256=tv8RU6zdeDobqphaP4Y8sicb1esg3gcQlZae1tNyitM,14559
|
|
11
11
|
mobile_mcp/core/templates/close_buttons/auto_x_0112_151217.png,sha256=s7tBVaYLBApNSEXjwi5kX8GXwUqgbNyNVEhXYjN9nd4,27373
|
|
12
12
|
mobile_mcp/core/templates/close_buttons/auto_x_0112_152037.png,sha256=s7tBVaYLBApNSEXjwi5kX8GXwUqgbNyNVEhXYjN9nd4,27373
|
|
@@ -24,9 +24,9 @@ mobile_mcp/utils/__init__.py,sha256=8EH0i7UGtx1y_j_GEgdN-cZdWn2sRtZSEOLlNF9HRnY,
|
|
|
24
24
|
mobile_mcp/utils/logger.py,sha256=Sqq2Nr0Y4p03erqcrbYKVPCGiFaNGHMcE_JwCkeOfU4,3626
|
|
25
25
|
mobile_mcp/utils/xml_formatter.py,sha256=uwTRb3vLbqhT8O-udzWT7s7LsV-DyDUz2DkofD3hXOE,4556
|
|
26
26
|
mobile_mcp/utils/xml_parser.py,sha256=QhL8CWbdmNDzmBLjtx6mEnjHgMFZzJeHpCL15qfXSpI,3926
|
|
27
|
-
mobile_mcp_ai-2.5.
|
|
28
|
-
mobile_mcp_ai-2.5.
|
|
29
|
-
mobile_mcp_ai-2.5.
|
|
30
|
-
mobile_mcp_ai-2.5.
|
|
31
|
-
mobile_mcp_ai-2.5.
|
|
32
|
-
mobile_mcp_ai-2.5.
|
|
27
|
+
mobile_mcp_ai-2.5.9.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
28
|
+
mobile_mcp_ai-2.5.9.dist-info/METADATA,sha256=j1KcGXfXaAeU3KJiSOAlo150FG9Mvg3cRlmDjJK3nZY,10495
|
|
29
|
+
mobile_mcp_ai-2.5.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
30
|
+
mobile_mcp_ai-2.5.9.dist-info/entry_points.txt,sha256=KB_FglozgPHBprSM1vFbIzGyheFuHFmGanscRdMJ_8A,68
|
|
31
|
+
mobile_mcp_ai-2.5.9.dist-info/top_level.txt,sha256=lLm6YpbTv855Lbh8BIA0rPxhybIrvYUzMEk9OErHT94,11
|
|
32
|
+
mobile_mcp_ai-2.5.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|