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
@@ -208,7 +208,7 @@ class DeviceManager:
208
208
 
209
209
  try:
210
210
  # 尝试获取页面结构,如果失败可能是无障碍服务未启用
211
- xml = self.u2.dump_hierarchy()
211
+ xml = self.u2.dump_hierarchy(compressed=False)
212
212
  if xml and len(xml) > 100: # 有内容说明无障碍服务正常
213
213
  print(f" ✅ 无障碍服务: 已启用", file=sys.stderr)
214
214
  return
@@ -235,7 +235,7 @@ class DeviceManager:
235
235
 
236
236
  try:
237
237
  # 尝试获取页面结构
238
- xml = self.u2.dump_hierarchy()
238
+ xml = self.u2.dump_hierarchy(compressed=False)
239
239
  if xml and len(xml) > 100:
240
240
  return {
241
241
  'enabled': True,
@@ -0,0 +1,272 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ 动态配置管理器 - 运行时可调整的自动化行为配置
5
+
6
+ 功能:
7
+ 1. 提供默认配置(与硬编码值完全一致,保证兼容性)
8
+ 2. 支持运行时动态调整(通过 mobile_configure 工具)
9
+ 3. 让 AI 可以根据 App 特性和场景优化配置
10
+
11
+ 设计原则:
12
+ - 默认值 = 当前硬编码值(保证向后兼容)
13
+ - 所有配置都可选(不调用就用默认值)
14
+ - 运行时可修改(无需重启)
15
+ """
16
+ import sys
17
+ from typing import Dict, Any, Optional
18
+
19
+
20
+ class DynamicConfig:
21
+ """
22
+ 动态配置管理器(运行时可调整)
23
+
24
+ 所有默认值都与当前硬编码值完全一致,保证 100% 向后兼容
25
+ """
26
+
27
+ # ==================== 等待时间策略 ====================
28
+
29
+ # 点击后等待时间(秒)- 让页面有时间响应
30
+ wait_after_click: float = 0.3
31
+
32
+ # 输入后等待时间(秒)- 让UI更新
33
+ wait_after_input: float = 0.3
34
+
35
+ # 页面稳定等待时间(秒)- 确保动画/过渡完成
36
+ wait_page_stable: float = 0.8
37
+
38
+ # 元素等待默认超时(秒)
39
+ element_wait_timeout: float = 10.0
40
+
41
+ # 页面变化检测超时(秒)
42
+ page_change_timeout: float = 2.0
43
+
44
+ # ==================== 验证策略 ====================
45
+
46
+ # 是否验证点击操作
47
+ verify_clicks: bool = True
48
+
49
+ # 是否验证输入操作
50
+ verify_inputs: bool = False
51
+
52
+ # 是否验证按键操作
53
+ verify_keys: bool = True
54
+
55
+ # ==================== 页面检测阈值 ====================
56
+
57
+ # 页面变化阈值(0-1)- 百分比
58
+ # 默认 0.05 = 5% 变化就认为页面发生了变化
59
+ page_change_threshold: float = 0.05
60
+
61
+ # 页面稳定阈值(秒)- 连续多久无变化认为稳定
62
+ page_stable_threshold: float = 0.3
63
+
64
+ # ==================== 屏幕方向控制 ====================
65
+
66
+ # 屏幕方向:portrait(竖屏), landscape(横屏), auto(跟随App)
67
+ screen_orientation: str = "portrait"
68
+
69
+ # 是否锁定屏幕方向
70
+ lock_screen_orientation: bool = True
71
+
72
+ # ==================== 广告/弹窗处理 ====================
73
+
74
+ # 是否自动关闭广告
75
+ auto_close_ads: bool = True
76
+
77
+ # 点击关闭按钮前的等待时间(秒)
78
+ wait_before_close_ad: float = 0.3
79
+
80
+ # 最多点击多少个关闭按钮(避免误点击)
81
+ max_close_buttons: int = 1
82
+
83
+ # ==================== 截图策略 ====================
84
+
85
+ # 截图策略:always(总是), on_failure(失败时), never(从不), smart(智能)
86
+ screenshot_strategy: str = "smart"
87
+
88
+ # ==================== 重试策略 ====================
89
+
90
+ # 操作失败时的最大重试次数
91
+ max_retries: int = 3
92
+
93
+ # 重试间隔(秒)
94
+ retry_delay: float = 1.0
95
+
96
+ # ==================== 配置管理 ====================
97
+
98
+ @classmethod
99
+ def update(cls, config: Dict[str, Any]) -> Dict[str, Any]:
100
+ """
101
+ 更新配置
102
+
103
+ Args:
104
+ config: 配置字典,支持嵌套结构
105
+
106
+ Returns:
107
+ 更新后的配置摘要
108
+
109
+ 示例:
110
+ DynamicConfig.update({
111
+ "wait_strategy": {
112
+ "click_wait": 0.5,
113
+ "input_wait": 0.5
114
+ },
115
+ "screen_orientation": "landscape",
116
+ "page_change_threshold": 0.1
117
+ })
118
+ """
119
+ updated = []
120
+
121
+ # 处理嵌套的等待策略
122
+ if "wait_strategy" in config:
123
+ wait = config["wait_strategy"]
124
+ if "click_wait" in wait:
125
+ cls.wait_after_click = float(wait["click_wait"])
126
+ updated.append(f"wait_after_click={cls.wait_after_click}")
127
+ if "input_wait" in wait:
128
+ cls.wait_after_input = float(wait["input_wait"])
129
+ updated.append(f"wait_after_input={cls.wait_after_input}")
130
+ if "page_stable_wait" in wait:
131
+ cls.wait_page_stable = float(wait["page_stable_wait"])
132
+ updated.append(f"wait_page_stable={cls.wait_page_stable}")
133
+ if "element_timeout" in wait:
134
+ cls.element_wait_timeout = float(wait["element_timeout"])
135
+ updated.append(f"element_wait_timeout={cls.element_wait_timeout}")
136
+ if "page_change_timeout" in wait:
137
+ cls.page_change_timeout = float(wait["page_change_timeout"])
138
+ updated.append(f"page_change_timeout={cls.page_change_timeout}")
139
+
140
+ # 处理验证策略
141
+ if "verify_strategy" in config:
142
+ verify = config["verify_strategy"]
143
+ if "verify_clicks" in verify:
144
+ cls.verify_clicks = bool(verify["verify_clicks"])
145
+ updated.append(f"verify_clicks={cls.verify_clicks}")
146
+ if "verify_inputs" in verify:
147
+ cls.verify_inputs = bool(verify["verify_inputs"])
148
+ updated.append(f"verify_inputs={cls.verify_inputs}")
149
+ if "verify_keys" in verify:
150
+ cls.verify_keys = bool(verify["verify_keys"])
151
+ updated.append(f"verify_keys={cls.verify_keys}")
152
+
153
+ # 处理广告策略
154
+ if "ad_handling" in config:
155
+ ad = config["ad_handling"]
156
+ if "auto_close" in ad:
157
+ cls.auto_close_ads = bool(ad["auto_close"])
158
+ updated.append(f"auto_close_ads={cls.auto_close_ads}")
159
+ if "wait_before_close" in ad:
160
+ cls.wait_before_close_ad = float(ad["wait_before_close"])
161
+ updated.append(f"wait_before_close_ad={cls.wait_before_close_ad}")
162
+ if "max_close_buttons" in ad:
163
+ cls.max_close_buttons = int(ad["max_close_buttons"])
164
+ updated.append(f"max_close_buttons={cls.max_close_buttons}")
165
+
166
+ # 处理重试策略
167
+ if "retry_strategy" in config:
168
+ retry = config["retry_strategy"]
169
+ if "max_retries" in retry:
170
+ cls.max_retries = int(retry["max_retries"])
171
+ updated.append(f"max_retries={cls.max_retries}")
172
+ if "retry_delay" in retry:
173
+ cls.retry_delay = float(retry["retry_delay"])
174
+ updated.append(f"retry_delay={cls.retry_delay}")
175
+
176
+ # 处理简单配置项
177
+ simple_configs = {
178
+ "page_change_threshold": (float, "page_change_threshold"),
179
+ "page_stable_threshold": (float, "page_stable_threshold"),
180
+ "screen_orientation": (str, "screen_orientation"),
181
+ "lock_screen_orientation": (bool, "lock_screen_orientation"),
182
+ "screenshot_strategy": (str, "screenshot_strategy"),
183
+ }
184
+
185
+ for key, (type_cast, attr_name) in simple_configs.items():
186
+ if key in config:
187
+ setattr(cls, attr_name, type_cast(config[key]))
188
+ updated.append(f"{attr_name}={getattr(cls, attr_name)}")
189
+
190
+ print(f" ✅ 配置已更新: {', '.join(updated)}", file=sys.stderr)
191
+
192
+ return {
193
+ "success": True,
194
+ "updated": updated,
195
+ "message": f"成功更新 {len(updated)} 项配置"
196
+ }
197
+
198
+ @classmethod
199
+ def get_current(cls) -> Dict[str, Any]:
200
+ """
201
+ 获取当前配置
202
+
203
+ Returns:
204
+ 当前所有配置的字典
205
+ """
206
+ return {
207
+ "wait_strategy": {
208
+ "click_wait": cls.wait_after_click,
209
+ "input_wait": cls.wait_after_input,
210
+ "page_stable_wait": cls.wait_page_stable,
211
+ "element_timeout": cls.element_wait_timeout,
212
+ "page_change_timeout": cls.page_change_timeout,
213
+ },
214
+ "verify_strategy": {
215
+ "verify_clicks": cls.verify_clicks,
216
+ "verify_inputs": cls.verify_inputs,
217
+ "verify_keys": cls.verify_keys,
218
+ },
219
+ "thresholds": {
220
+ "page_change_threshold": cls.page_change_threshold,
221
+ "page_stable_threshold": cls.page_stable_threshold,
222
+ },
223
+ "screen": {
224
+ "orientation": cls.screen_orientation,
225
+ "lock_orientation": cls.lock_screen_orientation,
226
+ },
227
+ "ad_handling": {
228
+ "auto_close": cls.auto_close_ads,
229
+ "wait_before_close": cls.wait_before_close_ad,
230
+ "max_close_buttons": cls.max_close_buttons,
231
+ },
232
+ "screenshot_strategy": cls.screenshot_strategy,
233
+ "retry_strategy": {
234
+ "max_retries": cls.max_retries,
235
+ "retry_delay": cls.retry_delay,
236
+ }
237
+ }
238
+
239
+ @classmethod
240
+ def reset(cls) -> Dict[str, str]:
241
+ """
242
+ 重置所有配置为默认值
243
+
244
+ Returns:
245
+ 重置结果
246
+ """
247
+ cls.wait_after_click = 0.3
248
+ cls.wait_after_input = 0.3
249
+ cls.wait_page_stable = 0.8
250
+ cls.element_wait_timeout = 10.0
251
+ cls.page_change_timeout = 2.0
252
+ cls.verify_clicks = True
253
+ cls.verify_inputs = False
254
+ cls.verify_keys = True
255
+ cls.page_change_threshold = 0.05
256
+ cls.page_stable_threshold = 0.3
257
+ cls.screen_orientation = "portrait"
258
+ cls.lock_screen_orientation = True
259
+ cls.auto_close_ads = True
260
+ cls.wait_before_close_ad = 0.3
261
+ cls.max_close_buttons = 1
262
+ cls.screenshot_strategy = "smart"
263
+ cls.max_retries = 3
264
+ cls.retry_delay = 1.0
265
+
266
+ print(" ✅ 配置已重置为默认值", file=sys.stderr)
267
+
268
+ return {
269
+ "success": True,
270
+ "message": "所有配置已重置为默认值"
271
+ }
272
+