mobile-mcp-ai 2.1.2__py3-none-any.whl → 2.5.8__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.
Files changed (65) hide show
  1. mobile_mcp/__init__.py +34 -0
  2. mobile_mcp/config.py +142 -0
  3. mobile_mcp/core/basic_tools_lite.py +3266 -0
  4. {core → mobile_mcp/core}/device_manager.py +2 -2
  5. mobile_mcp/core/dynamic_config.py +272 -0
  6. mobile_mcp/core/ios_client_wda.py +569 -0
  7. mobile_mcp/core/ios_device_manager_wda.py +306 -0
  8. {core → mobile_mcp/core}/mobile_client.py +279 -39
  9. mobile_mcp/core/template_matcher.py +429 -0
  10. mobile_mcp/core/templates/close_buttons/auto_x_0112_151217.png +0 -0
  11. mobile_mcp/core/templates/close_buttons/auto_x_0112_152037.png +0 -0
  12. mobile_mcp/core/templates/close_buttons/auto_x_0112_152840.png +0 -0
  13. mobile_mcp/core/templates/close_buttons/auto_x_0112_153256.png +0 -0
  14. mobile_mcp/core/templates/close_buttons/auto_x_0112_154847.png +0 -0
  15. mobile_mcp/core/templates/close_buttons/gray_x_stock_ad.png +0 -0
  16. {core → mobile_mcp/core}/utils/smart_wait.py +3 -3
  17. mobile_mcp/mcp_tools/__init__.py +10 -0
  18. mobile_mcp/mcp_tools/mcp_server.py +1071 -0
  19. mobile_mcp_ai-2.5.8.dist-info/METADATA +469 -0
  20. mobile_mcp_ai-2.5.8.dist-info/RECORD +32 -0
  21. mobile_mcp_ai-2.5.8.dist-info/entry_points.txt +2 -0
  22. mobile_mcp_ai-2.5.8.dist-info/licenses/LICENSE +201 -0
  23. mobile_mcp_ai-2.5.8.dist-info/top_level.txt +1 -0
  24. core/ai/__init__.py +0 -11
  25. core/ai/ai_analyzer.py +0 -197
  26. core/ai/ai_config.py +0 -116
  27. core/ai/ai_platform_adapter.py +0 -399
  28. core/ai/smart_test_executor.py +0 -520
  29. core/ai/test_generator.py +0 -365
  30. core/ai/test_generator_from_history.py +0 -391
  31. core/ai/test_generator_standalone.py +0 -293
  32. core/assertion/__init__.py +0 -9
  33. core/assertion/smart_assertion.py +0 -341
  34. core/basic_tools.py +0 -377
  35. core/h5/__init__.py +0 -10
  36. core/h5/h5_handler.py +0 -548
  37. core/ios_client.py +0 -219
  38. core/ios_device_manager.py +0 -252
  39. core/locator/__init__.py +0 -10
  40. core/locator/cursor_ai_auto_analyzer.py +0 -119
  41. core/locator/cursor_vision_helper.py +0 -414
  42. core/locator/mobile_smart_locator.py +0 -1640
  43. core/locator/position_analyzer.py +0 -813
  44. core/locator/script_updater.py +0 -157
  45. core/nl_test_runner.py +0 -585
  46. core/smart_app_launcher.py +0 -334
  47. core/smart_tools.py +0 -311
  48. mcp/__init__.py +0 -8
  49. mcp/mcp_server.py +0 -1919
  50. mcp/mcp_server_simple.py +0 -476
  51. mobile_mcp_ai-2.1.2.dist-info/METADATA +0 -567
  52. mobile_mcp_ai-2.1.2.dist-info/RECORD +0 -45
  53. mobile_mcp_ai-2.1.2.dist-info/entry_points.txt +0 -2
  54. mobile_mcp_ai-2.1.2.dist-info/top_level.txt +0 -4
  55. vision/__init__.py +0 -10
  56. vision/vision_locator.py +0 -404
  57. {core → mobile_mcp/core}/__init__.py +0 -0
  58. {core → mobile_mcp/core}/utils/__init__.py +0 -0
  59. {core → mobile_mcp/core}/utils/logger.py +0 -0
  60. {core → mobile_mcp/core}/utils/operation_history_manager.py +0 -0
  61. {utils → mobile_mcp/utils}/__init__.py +0 -0
  62. {utils → mobile_mcp/utils}/logger.py +0 -0
  63. {utils → mobile_mcp/utils}/xml_formatter.py +0 -0
  64. {utils → mobile_mcp/utils}/xml_parser.py +0 -0
  65. {mobile_mcp_ai-2.1.2.dist-info → mobile_mcp_ai-2.5.8.dist-info}/WHEEL +0 -0
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- 断言模块
5
- """
6
- from .smart_assertion import SmartAssertion
7
-
8
- __all__ = ['SmartAssertion']
9
-
@@ -1,341 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- 智能断言系统 - XML分析 + AI视觉识别
5
-
6
- 策略:
7
- 1. 优先XML分析(快速+免费)
8
- 2. 失败时降级到AI视觉识别(智能+付费)
9
- 3. 支持多种断言类型
10
- """
11
- from typing import Optional, Dict, Any
12
- import time
13
-
14
-
15
- class SmartAssertion:
16
- """智能断言系统"""
17
-
18
- def __init__(self, mobile_client):
19
- """
20
- 初始化智能断言系统
21
-
22
- Args:
23
- mobile_client: MobileClient实例
24
- """
25
- self.mobile_client = mobile_client
26
-
27
- # 统计
28
- self.stats = {
29
- 'total': 0,
30
- 'xml_success': 0,
31
- 'ai_success': 0,
32
- 'failed': 0,
33
- 'total_time': 0.0,
34
- }
35
-
36
- async def assert_text_exists(self, text: str, timeout: float = 5.0) -> bool:
37
- """
38
- 断言:文本存在
39
-
40
- Args:
41
- text: 要查找的文本
42
- timeout: 超时时间(秒)
43
-
44
- Returns:
45
- True: 找到文本
46
- False: 未找到文本
47
- """
48
- start_time = time.time()
49
- self.stats['total'] += 1
50
-
51
- print(f"\n🔍 断言:文本存在 - '{text}'")
52
-
53
- # Level 1: XML文本查找(快速+免费)
54
- print(f" 📋 Level 1: XML文本查找...")
55
- xml_result = await self._xml_text_search(text, timeout)
56
-
57
- if xml_result:
58
- self.stats['xml_success'] += 1
59
- elapsed = (time.time() - start_time) * 1000
60
- self.stats['total_time'] += elapsed
61
- print(f" ✅ XML查找成功!耗时: {elapsed:.2f}ms")
62
- return True
63
-
64
- # Level 2: AI视觉识别(智能+付费)
65
- print(f" 🤖 Level 2: AI视觉识别...")
66
- ai_result = await self._ai_visual_search(text)
67
-
68
- if ai_result:
69
- self.stats['ai_success'] += 1
70
- elapsed = (time.time() - start_time) * 1000
71
- self.stats['total_time'] += elapsed
72
- print(f" ✅ AI识别成功!耗时: {elapsed:.2f}ms")
73
- return True
74
-
75
- # 断言失败
76
- self.stats['failed'] += 1
77
- elapsed = (time.time() - start_time) * 1000
78
- self.stats['total_time'] += elapsed
79
- print(f" ❌ 断言失败:未找到文本 '{text}',耗时: {elapsed:.2f}ms")
80
- return False
81
-
82
- async def assert_element_exists(self, query: str, timeout: float = 5.0) -> bool:
83
- """
84
- 断言:元素存在
85
-
86
- Args:
87
- query: 元素查询(自然语言)
88
- timeout: 超时时间(秒)
89
-
90
- Returns:
91
- True: 找到元素
92
- False: 未找到元素
93
- """
94
- start_time = time.time()
95
- self.stats['total'] += 1
96
-
97
- print(f"\n🔍 断言:元素存在 - '{query}'")
98
-
99
- # 使用SmartLocator定位元素
100
- try:
101
- from ..locator.mobile_smart_locator import MobileSmartLocator
102
-
103
- locator = MobileSmartLocator(self.mobile_client)
104
- result = await locator.locate(query)
105
-
106
- if result:
107
- self.stats['xml_success'] += 1 # 简化统计,实际可能是AI
108
- elapsed = (time.time() - start_time) * 1000
109
- self.stats['total_time'] += elapsed
110
- print(f" ✅ 元素存在!耗时: {elapsed:.2f}ms")
111
- return True
112
- else:
113
- self.stats['failed'] += 1
114
- elapsed = (time.time() - start_time) * 1000
115
- self.stats['total_time'] += elapsed
116
- print(f" ❌ 断言失败:未找到元素 '{query}',耗时: {elapsed:.2f}ms")
117
- return False
118
-
119
- except Exception as e:
120
- self.stats['failed'] += 1
121
- elapsed = (time.time() - start_time) * 1000
122
- self.stats['total_time'] += elapsed
123
- print(f" ❌ 断言异常: {e},耗时: {elapsed:.2f}ms")
124
- return False
125
-
126
- async def assert_visual_exists(self, description: str) -> bool:
127
- """
128
- 断言:视觉元素存在(纯AI识别)
129
-
130
- 适用场景:
131
- - 图标、图片
132
- - 视觉状态(如"选中"、"高亮")
133
- - 布局检查(如"底部有4个图标")
134
-
135
- Args:
136
- description: 视觉描述
137
-
138
- Returns:
139
- True: 找到元素
140
- False: 未找到元素
141
- """
142
- start_time = time.time()
143
- self.stats['total'] += 1
144
-
145
- print(f"\n🔍 断言:视觉元素存在 - '{description}'")
146
-
147
- # 直接使用AI视觉识别
148
- ai_result = await self._ai_visual_search(description)
149
-
150
- if ai_result:
151
- self.stats['ai_success'] += 1
152
- elapsed = (time.time() - start_time) * 1000
153
- self.stats['total_time'] += elapsed
154
- print(f" ✅ AI识别成功!耗时: {elapsed:.2f}ms")
155
- return True
156
- else:
157
- self.stats['failed'] += 1
158
- elapsed = (time.time() - start_time) * 1000
159
- self.stats['total_time'] += elapsed
160
- print(f" ❌ 断言失败:未找到视觉元素 '{description}',耗时: {elapsed:.2f}ms")
161
- return False
162
-
163
- async def assert_element_enabled(self, query: str) -> bool:
164
- """
165
- 断言:元素可用(enabled=true)
166
-
167
- Args:
168
- query: 元素查询
169
-
170
- Returns:
171
- True: 元素可用
172
- False: 元素不可用或不存在
173
- """
174
- start_time = time.time()
175
- self.stats['total'] += 1
176
-
177
- print(f"\n🔍 断言:元素可用 - '{query}'")
178
-
179
- # 读取XML
180
- xml_string = self.mobile_client.u2.dump_hierarchy()
181
- elements = self.mobile_client.xml_parser.parse(xml_string)
182
-
183
- # 查找元素
184
- query_lower = query.lower()
185
- for elem in elements:
186
- text = elem.get('text', '').lower()
187
- desc = elem.get('content_desc', '').lower()
188
-
189
- if query_lower in text or query_lower in desc:
190
- enabled = elem.get('enabled', False)
191
-
192
- if enabled:
193
- self.stats['xml_success'] += 1
194
- elapsed = (time.time() - start_time) * 1000
195
- self.stats['total_time'] += elapsed
196
- print(f" ✅ 元素可用!耗时: {elapsed:.2f}ms")
197
- return True
198
- else:
199
- self.stats['failed'] += 1
200
- elapsed = (time.time() - start_time) * 1000
201
- self.stats['total_time'] += elapsed
202
- print(f" ❌ 断言失败:元素不可用,耗时: {elapsed:.2f}ms")
203
- return False
204
-
205
- # 未找到元素
206
- self.stats['failed'] += 1
207
- elapsed = (time.time() - start_time) * 1000
208
- self.stats['total_time'] += elapsed
209
- print(f" ❌ 断言失败:未找到元素 '{query}',耗时: {elapsed:.2f}ms")
210
- return False
211
-
212
- async def assert_element_count(self, query: str, expected_count: int) -> bool:
213
- """
214
- 断言:元素数量
215
-
216
- Args:
217
- query: 元素查询
218
- expected_count: 期望数量
219
-
220
- Returns:
221
- True: 数量匹配
222
- False: 数量不匹配
223
- """
224
- start_time = time.time()
225
- self.stats['total'] += 1
226
-
227
- print(f"\n🔍 断言:元素数量 - '{query}' (期望: {expected_count})")
228
-
229
- # 读取XML
230
- xml_string = self.mobile_client.u2.dump_hierarchy()
231
- elements = self.mobile_client.xml_parser.parse(xml_string)
232
-
233
- # 查找所有匹配元素
234
- query_lower = query.lower()
235
- matched = []
236
-
237
- for elem in elements:
238
- text = elem.get('text', '').lower()
239
- desc = elem.get('content_desc', '').lower()
240
-
241
- if query_lower in text or query_lower in desc:
242
- matched.append(elem)
243
-
244
- actual_count = len(matched)
245
-
246
- if actual_count == expected_count:
247
- self.stats['xml_success'] += 1
248
- elapsed = (time.time() - start_time) * 1000
249
- self.stats['total_time'] += elapsed
250
- print(f" ✅ 数量匹配!实际: {actual_count},耗时: {elapsed:.2f}ms")
251
- return True
252
- else:
253
- self.stats['failed'] += 1
254
- elapsed = (time.time() - start_time) * 1000
255
- self.stats['total_time'] += elapsed
256
- print(f" ❌ 断言失败:数量不匹配!期望: {expected_count},实际: {actual_count},耗时: {elapsed:.2f}ms")
257
- return False
258
-
259
- # ========================================
260
- # 内部方法
261
- # ========================================
262
-
263
- async def _xml_text_search(self, text: str, timeout: float) -> bool:
264
- """
265
- XML文本查找
266
-
267
- Args:
268
- text: 要查找的文本
269
- timeout: 超时时间(秒)
270
-
271
- Returns:
272
- True: 找到文本
273
- False: 未找到文本
274
- """
275
- start_time = time.time()
276
- text_lower = text.lower()
277
-
278
- while time.time() - start_time < timeout:
279
- # 读取XML
280
- xml_string = self.mobile_client.u2.dump_hierarchy()
281
- elements = self.mobile_client.xml_parser.parse(xml_string)
282
-
283
- # 查找文本
284
- for elem in elements:
285
- elem_text = elem.get('text', '').lower()
286
- elem_desc = elem.get('content_desc', '').lower()
287
-
288
- if text_lower in elem_text or text_lower in elem_desc:
289
- print(f" ✅ 找到文本: {elem.get('text') or elem.get('content_desc')}")
290
- return True
291
-
292
- # 未找到,等待100ms后重试
293
- await self.mobile_client.wait(0.1)
294
-
295
- print(f" ❌ 超时未找到文本")
296
- return False
297
-
298
- async def _ai_visual_search(self, description: str) -> bool:
299
- """
300
- AI视觉识别
301
-
302
- Args:
303
- description: 视觉描述
304
-
305
- Returns:
306
- True: 找到元素
307
- False: 未找到元素
308
- """
309
- try:
310
- from ...vision.vision_locator import MobileVisionLocator
311
-
312
- vision_locator = MobileVisionLocator(self.mobile_client)
313
- result = await vision_locator.locate_element_by_vision(description)
314
-
315
- if result and result.get('found'):
316
- print(f" ✅ AI识别成功: {description}")
317
- return True
318
- else:
319
- print(f" ❌ AI未识别到: {description}")
320
- return False
321
-
322
- except ImportError:
323
- print(f" ⚠️ 视觉识别模块未安装")
324
- return False
325
- except Exception as e:
326
- print(f" ⚠️ AI识别失败: {e}")
327
- return False
328
-
329
- def print_stats(self):
330
- """打印统计信息"""
331
- print("\n" + "=" * 80)
332
- print("📊 断言统计")
333
- print("=" * 80)
334
- print(f" 总断言次数: {self.stats['total']}")
335
- print(f" XML成功: {self.stats['xml_success']} ({self.stats['xml_success']/max(1, self.stats['total'])*100:.1f}%)")
336
- print(f" AI成功: {self.stats['ai_success']} ({self.stats['ai_success']/max(1, self.stats['total'])*100:.1f}%)")
337
- print(f" 失败: {self.stats['failed']} ({self.stats['failed']/max(1, self.stats['total'])*100:.1f}%)")
338
- print(f" 总耗时: {self.stats['total_time']:.2f}ms")
339
- print(f" 平均耗时: {self.stats['total_time']/max(1, self.stats['total']):.2f}ms")
340
- print("=" * 80)
341
-