mobile-mcp-ai 2.5.3__tar.gz → 2.5.5__tar.gz

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 (57) hide show
  1. {mobile_mcp_ai-2.5.3/mobile_mcp_ai.egg-info → mobile_mcp_ai-2.5.5}/PKG-INFO +14 -1
  2. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/README.md +13 -0
  3. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/__init__.py +1 -1
  4. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/basic_tools_lite.py +42 -7
  5. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/mcp_tools/mcp_server.py +83 -9
  6. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5/mobile_mcp_ai.egg-info}/PKG-INFO +14 -1
  7. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/mobile_mcp_ai.egg-info/SOURCES.txt +0 -10
  8. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/setup.py +1 -1
  9. mobile_mcp_ai-2.5.3/tests/test_mind_cloud_my_space.py +0 -80
  10. mobile_mcp_ai-2.5.3/tests/test_mind_correct.py +0 -73
  11. mobile_mcp_ai-2.5.3/tests/test_mind_improved.py +0 -83
  12. mobile_mcp_ai-2.5.3/tests/test_mind_optimized.py +0 -77
  13. mobile_mcp_ai-2.5.3/tests/test_open_mind.py +0 -37
  14. mobile_mcp_ai-2.5.3/tests/test_priority_demo.py +0 -81
  15. mobile_mcp_ai-2.5.3/tests/test_simple.py +0 -76
  16. mobile_mcp_ai-2.5.3/tests/test_/344/270/276/346/212/245.py +0 -136
  17. mobile_mcp_ai-2.5.3/tests/test_/345/210/207/346/215/242/350/257/255/350/250/200/345/210/260English.py +0 -158
  18. mobile_mcp_ai-2.5.3/tests/test_/346/265/213/350/257/225.py +0 -114
  19. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/LICENSE +0 -0
  20. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/MANIFEST.in +0 -0
  21. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/config.py +0 -0
  22. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/__init__.py +0 -0
  23. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/device_manager.py +0 -0
  24. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/dynamic_config.py +0 -0
  25. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/ios_client_wda.py +0 -0
  26. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/ios_device_manager_wda.py +0 -0
  27. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/mobile_client.py +0 -0
  28. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/template_matcher.py +0 -0
  29. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/templates/close_buttons/auto_x_0112_151217.png +0 -0
  30. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/templates/close_buttons/auto_x_0112_152037.png +0 -0
  31. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/templates/close_buttons/auto_x_0112_152840.png +0 -0
  32. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/templates/close_buttons/auto_x_0112_153256.png +0 -0
  33. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/templates/close_buttons/auto_x_0112_154847.png +0 -0
  34. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/templates/close_buttons/gray_x_stock_ad.png +0 -0
  35. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/utils/__init__.py +0 -0
  36. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/utils/logger.py +0 -0
  37. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/utils/operation_history_manager.py +0 -0
  38. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/core/utils/smart_wait.py +0 -0
  39. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/docs/iOS_SETUP_GUIDE.md +0 -0
  40. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/mcp_tools/__init__.py +0 -0
  41. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/mobile_mcp_ai.egg-info/dependency_links.txt +0 -0
  42. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/mobile_mcp_ai.egg-info/entry_points.txt +0 -0
  43. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/mobile_mcp_ai.egg-info/not-zip-safe +0 -0
  44. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/mobile_mcp_ai.egg-info/requires.txt +0 -0
  45. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/mobile_mcp_ai.egg-info/top_level.txt +0 -0
  46. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/requirements.txt +0 -0
  47. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/setup.cfg +0 -0
  48. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/templates/close_buttons/auto_x_0112_151217.png +0 -0
  49. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/templates/close_buttons/auto_x_0112_152037.png +0 -0
  50. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/templates/close_buttons/auto_x_0112_152840.png +0 -0
  51. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/templates/close_buttons/auto_x_0112_153256.png +0 -0
  52. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/templates/close_buttons/auto_x_0112_154847.png +0 -0
  53. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/templates/close_buttons/gray_x_stock_ad.png +0 -0
  54. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/utils/__init__.py +0 -0
  55. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/utils/logger.py +0 -0
  56. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/utils/xml_formatter.py +0 -0
  57. {mobile_mcp_ai-2.5.3 → mobile_mcp_ai-2.5.5}/utils/xml_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mobile-mcp-ai
3
- Version: 2.5.3
3
+ Version: 2.5.5
4
4
  Summary: 移动端自动化 MCP Server - 支持 Android/iOS,AI 功能可选(基础工具不需要 AI)
5
5
  Home-page: https://github.com/test111ddff-hash/mobile-mcp-ai
6
6
  Author: douzi
@@ -408,10 +408,18 @@ tidevice list
408
408
  |:---:|------|------|
409
409
  | 📋 | `mobile_list_elements` | 列出页面元素 |
410
410
  | 📸 | `mobile_take_screenshot` | 截图 |
411
+ | 📸 | `mobile_screenshot_with_som` | Set-of-Mark 截图(智能标注) |
412
+ | 📸 | `mobile_screenshot_with_grid` | 带网格坐标的截图 |
411
413
  | 📐 | `mobile_get_screen_size` | 屏幕尺寸 |
412
414
  | 👆 | `mobile_click_by_text` | 文本点击 |
413
415
  | 👆 | `mobile_click_by_id` | ID 点击 |
414
416
  | 👆 | `mobile_click_at_coords` | 坐标点击 |
417
+ | 👆 | `mobile_click_by_percent` | 百分比点击 |
418
+ | 👆 | `mobile_click_by_som` | SoM 编号点击 |
419
+ | 👆 | `mobile_long_press_by_id` | ID 长按 |
420
+ | 👆 | `mobile_long_press_by_text` | 文本长按 |
421
+ | 👆 | `mobile_long_press_by_percent` | 百分比长按 |
422
+ | 👆 | `mobile_long_press_at_coords` | 坐标长按 |
415
423
  | ⌨️ | `mobile_input_text_by_id` | ID 输入 |
416
424
  | ⌨️ | `mobile_input_at_coords` | 坐标输入 |
417
425
  | 👆 | `mobile_swipe` | 滑动 |
@@ -422,6 +430,11 @@ tidevice list
422
430
  | 📦 | `mobile_list_apps` | 列出应用 |
423
431
  | 📱 | `mobile_list_devices` | 列出设备 |
424
432
  | 🔌 | `mobile_check_connection` | 检查连接 |
433
+ | 🔍 | `mobile_find_close_button` | 查找关闭按钮 |
434
+ | 🚫 | `mobile_close_popup` | 关闭弹窗 |
435
+ | 🚫 | `mobile_close_ad` | 智能关闭广告弹窗 |
436
+ | 🎯 | `mobile_template_close` | 模板匹配关闭弹窗 |
437
+ | ➕ | `mobile_template_add` | 添加 X 号模板 |
425
438
  | ✅ | `mobile_assert_text` | 断言文本 |
426
439
  | 📜 | `mobile_get_operation_history` | 操作历史 |
427
440
  | 🗑️ | `mobile_clear_operation_history` | 清空历史 |
@@ -337,10 +337,18 @@ tidevice list
337
337
  |:---:|------|------|
338
338
  | 📋 | `mobile_list_elements` | 列出页面元素 |
339
339
  | 📸 | `mobile_take_screenshot` | 截图 |
340
+ | 📸 | `mobile_screenshot_with_som` | Set-of-Mark 截图(智能标注) |
341
+ | 📸 | `mobile_screenshot_with_grid` | 带网格坐标的截图 |
340
342
  | 📐 | `mobile_get_screen_size` | 屏幕尺寸 |
341
343
  | 👆 | `mobile_click_by_text` | 文本点击 |
342
344
  | 👆 | `mobile_click_by_id` | ID 点击 |
343
345
  | 👆 | `mobile_click_at_coords` | 坐标点击 |
346
+ | 👆 | `mobile_click_by_percent` | 百分比点击 |
347
+ | 👆 | `mobile_click_by_som` | SoM 编号点击 |
348
+ | 👆 | `mobile_long_press_by_id` | ID 长按 |
349
+ | 👆 | `mobile_long_press_by_text` | 文本长按 |
350
+ | 👆 | `mobile_long_press_by_percent` | 百分比长按 |
351
+ | 👆 | `mobile_long_press_at_coords` | 坐标长按 |
344
352
  | ⌨️ | `mobile_input_text_by_id` | ID 输入 |
345
353
  | ⌨️ | `mobile_input_at_coords` | 坐标输入 |
346
354
  | 👆 | `mobile_swipe` | 滑动 |
@@ -351,6 +359,11 @@ tidevice list
351
359
  | 📦 | `mobile_list_apps` | 列出应用 |
352
360
  | 📱 | `mobile_list_devices` | 列出设备 |
353
361
  | 🔌 | `mobile_check_connection` | 检查连接 |
362
+ | 🔍 | `mobile_find_close_button` | 查找关闭按钮 |
363
+ | 🚫 | `mobile_close_popup` | 关闭弹窗 |
364
+ | 🚫 | `mobile_close_ad` | 智能关闭广告弹窗 |
365
+ | 🎯 | `mobile_template_close` | 模板匹配关闭弹窗 |
366
+ | ➕ | `mobile_template_add` | 添加 X 号模板 |
354
367
  | ✅ | `mobile_assert_text` | 断言文本 |
355
368
  | 📜 | `mobile_get_operation_history` | 操作历史 |
356
369
  | 🗑️ | `mobile_clear_operation_history` | 清空历史 |
@@ -22,7 +22,7 @@
22
22
  await client.type_text("用户名输入框", "test@example.com")
23
23
  """
24
24
 
25
- __version__ = "1.0.0"
25
+ __version__ = "2.5.5"
26
26
 
27
27
  from .core.mobile_client import MobileClient
28
28
  from .core.device_manager import DeviceManager
@@ -1587,8 +1587,14 @@ class BasicMobileToolsLite:
1587
1587
 
1588
1588
  # ==================== 导航操作 ====================
1589
1589
 
1590
- async def swipe(self, direction: str) -> Dict:
1591
- """滑动屏幕"""
1590
+ async def swipe(self, direction: str, y: Optional[int] = None, y_percent: Optional[float] = None) -> Dict:
1591
+ """滑动屏幕
1592
+
1593
+ Args:
1594
+ direction: 滑动方向 (up/down/left/right)
1595
+ y: 左右滑动时指定的高度坐标(像素)
1596
+ y_percent: 左右滑动时指定的高度百分比 (0-100)
1597
+ """
1592
1598
  try:
1593
1599
  if self._is_ios():
1594
1600
  ios_client = self._get_ios_client()
@@ -1602,11 +1608,26 @@ class BasicMobileToolsLite:
1602
1608
 
1603
1609
  center_x, center_y = width // 2, height // 2
1604
1610
 
1611
+ # 对于左右滑动,如果指定了 y 或 y_percent,使用指定的高度
1612
+ if direction in ['left', 'right']:
1613
+ if y_percent is not None:
1614
+ if not (0 <= y_percent <= 100):
1615
+ return {"success": False, "message": f"❌ y_percent 必须在 0-100 之间: {y_percent}"}
1616
+ swipe_y = int(height * y_percent / 100)
1617
+ elif y is not None:
1618
+ if not (0 <= y <= height):
1619
+ return {"success": False, "message": f"❌ y 坐标超出屏幕范围 (0-{height}): {y}"}
1620
+ swipe_y = y
1621
+ else:
1622
+ swipe_y = center_y
1623
+ else:
1624
+ swipe_y = center_y
1625
+
1605
1626
  swipe_map = {
1606
1627
  'up': (center_x, int(height * 0.8), center_x, int(height * 0.2)),
1607
1628
  'down': (center_x, int(height * 0.2), center_x, int(height * 0.8)),
1608
- 'left': (int(width * 0.8), center_y, int(width * 0.2), center_y),
1609
- 'right': (int(width * 0.2), center_y, int(width * 0.8), center_y),
1629
+ 'left': (int(width * 0.8), swipe_y, int(width * 0.2), swipe_y),
1630
+ 'right': (int(width * 0.2), swipe_y, int(width * 0.8), swipe_y),
1610
1631
  }
1611
1632
 
1612
1633
  if direction not in swipe_map:
@@ -1619,9 +1640,23 @@ class BasicMobileToolsLite:
1619
1640
  else:
1620
1641
  self.client.u2.swipe(x1, y1, x2, y2, duration=0.5)
1621
1642
 
1622
- self._record_operation('swipe', direction=direction)
1623
-
1624
- return {"success": True, "message": f"✅ 滑动成功: {direction}"}
1643
+ # 记录操作信息
1644
+ record_info = {'direction': direction}
1645
+ if y is not None:
1646
+ record_info['y'] = y
1647
+ if y_percent is not None:
1648
+ record_info['y_percent'] = y_percent
1649
+ self._record_operation('swipe', **record_info)
1650
+
1651
+ # 构建返回消息
1652
+ msg = f"✅ 滑动成功: {direction}"
1653
+ if direction in ['left', 'right']:
1654
+ if y_percent is not None:
1655
+ msg += f" (高度: {y_percent}% = {swipe_y}px)"
1656
+ elif y is not None:
1657
+ msg += f" (高度: {y}px)"
1658
+
1659
+ return {"success": True, "message": msg}
1625
1660
  except Exception as e:
1626
1661
  return {"success": False, "message": f"❌ 滑动失败: {e}"}
1627
1662
 
@@ -34,9 +34,21 @@ from pathlib import Path
34
34
  from typing import Optional
35
35
 
36
36
  # 添加项目根目录到 Python 路径
37
- # __file__ 在 mcp/ 目录下,需要往上两级到项目根目录
38
- project_root = Path(__file__).parent.parent
39
- sys.path.insert(0, str(project_root))
37
+ # 支持两种运行方式:
38
+ # 1. 从源码运行:__file__ 在 mcp_tools/ 目录下,往上两级到项目根目录
39
+ # 2. 从已安装包运行:包已安装时,mobile_mcp 应该可以直接导入
40
+ # 先尝试从已安装的包导入,如果失败则从源码路径导入
41
+ try:
42
+ # 尝试导入已安装的包
43
+ import mobile_mcp.core.mobile_client
44
+ import mobile_mcp.core.basic_tools_lite
45
+ # 如果成功,说明包已安装,不需要添加路径
46
+ except ImportError:
47
+ # 包未安装或导入失败,从源码运行
48
+ # __file__ 在 mcp_tools/ 目录下,往上两级到项目根目录
49
+ project_root = Path(__file__).parent.parent
50
+ if str(project_root) not in sys.path:
51
+ sys.path.insert(0, str(project_root))
40
52
 
41
53
  # 尝试导入 MCP,处理可能的路径冲突
42
54
  try:
@@ -100,15 +112,34 @@ class MobileMCPServer:
100
112
 
101
113
  async def initialize(self):
102
114
  """延迟初始化设备连接"""
103
- # 如果已成功初始化,直接返回
115
+ # 如果已成功初始化,检查连接是否仍然有效
104
116
  if self._initialized and self.tools is not None:
105
- return
117
+ # 验证设备连接是否仍然有效
118
+ if self._is_connection_valid():
119
+ return
120
+ else:
121
+ # 连接已失效,重置状态
122
+ print("⚠️ 检测到设备连接已断开,正在重新连接...", file=sys.stderr)
123
+ self._initialized = False
124
+ self.client = None
125
+ self.tools = None
106
126
 
107
127
  platform = self._detect_platform()
108
128
 
109
129
  try:
110
- from mobile_mcp.core.mobile_client import MobileClient
111
- from mobile_mcp.core.basic_tools_lite import BasicMobileToolsLite
130
+ # 尝试导入,如果失败会抛出 ImportError
131
+ try:
132
+ from mobile_mcp.core.mobile_client import MobileClient
133
+ from mobile_mcp.core.basic_tools_lite import BasicMobileToolsLite
134
+ except ImportError as import_err:
135
+ # 如果导入失败,尝试从源码路径导入
136
+ # 这通常发生在开发模式下,包未安装时
137
+ project_root = Path(__file__).parent.parent
138
+ if str(project_root) not in sys.path:
139
+ sys.path.insert(0, str(project_root))
140
+ # 再次尝试导入
141
+ from mobile_mcp.core.mobile_client import MobileClient
142
+ from mobile_mcp.core.basic_tools_lite import BasicMobileToolsLite
112
143
 
113
144
  self.client = MobileClient(platform=platform)
114
145
  self.tools = BasicMobileToolsLite(self.client)
@@ -122,6 +153,33 @@ class MobileMCPServer:
122
153
  self._last_error = error_msg # 保存错误信息
123
154
  # 不设置 _initialized = True,下次调用会重试
124
155
 
156
+ def _is_connection_valid(self) -> bool:
157
+ """检查设备连接是否仍然有效"""
158
+ try:
159
+ if self.client is None:
160
+ return False
161
+
162
+ # Android: 检查 u2 连接
163
+ if hasattr(self.client, 'u2') and self.client.u2:
164
+ # 尝试获取设备信息,如果失败说明连接断开
165
+ self.client.u2.info
166
+ return True
167
+
168
+ # iOS: 检查 wda 连接
169
+ if hasattr(self.client, 'wda') and self.client.wda:
170
+ self.client.wda.status()
171
+ return True
172
+
173
+ # iOS (通过 _ios_client)
174
+ if hasattr(self.client, '_ios_client') and self.client._ios_client:
175
+ if hasattr(self.client._ios_client, 'wda') and self.client._ios_client.wda:
176
+ self.client._ios_client.wda.status()
177
+ return True
178
+
179
+ return False
180
+ except Exception:
181
+ return False
182
+
125
183
  def _detect_platform(self) -> str:
126
184
  """自动检测设备平台"""
127
185
  platform = os.getenv("MOBILE_PLATFORM", "").lower()
@@ -445,7 +503,11 @@ class MobileMCPServer:
445
503
  # ==================== 导航操作 ====================
446
504
  tools.append(Tool(
447
505
  name="mobile_swipe",
448
- description="👆 滑动屏幕。方向:up/down/left/right",
506
+ description="👆 滑动屏幕。方向:up/down/left/right\n\n"
507
+ "💡 左右滑动时,可指定高度坐标或百分比:\n"
508
+ "- y: 指定高度坐标(像素)\n"
509
+ "- y_percent: 指定高度百分比 (0-100)\n"
510
+ "- 两者都未指定时,使用屏幕中心高度",
449
511
  inputSchema={
450
512
  "type": "object",
451
513
  "properties": {
@@ -453,6 +515,14 @@ class MobileMCPServer:
453
515
  "type": "string",
454
516
  "enum": ["up", "down", "left", "right"],
455
517
  "description": "滑动方向"
518
+ },
519
+ "y": {
520
+ "type": "integer",
521
+ "description": "左右滑动时指定的高度坐标(像素,0-屏幕高度)"
522
+ },
523
+ "y_percent": {
524
+ "type": "number",
525
+ "description": "左右滑动时指定的高度百分比 (0-100)"
456
526
  }
457
527
  },
458
528
  "required": ["direction"]
@@ -845,7 +915,11 @@ class MobileMCPServer:
845
915
 
846
916
  # 导航
847
917
  elif name == "mobile_swipe":
848
- result = await self.tools.swipe(arguments["direction"])
918
+ result = await self.tools.swipe(
919
+ arguments["direction"],
920
+ y=arguments.get("y"),
921
+ y_percent=arguments.get("y_percent")
922
+ )
849
923
  return [TextContent(type="text", text=self.format_response(result))]
850
924
 
851
925
  elif name == "mobile_press_key":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mobile-mcp-ai
3
- Version: 2.5.3
3
+ Version: 2.5.5
4
4
  Summary: 移动端自动化 MCP Server - 支持 Android/iOS,AI 功能可选(基础工具不需要 AI)
5
5
  Home-page: https://github.com/test111ddff-hash/mobile-mcp-ai
6
6
  Author: douzi
@@ -408,10 +408,18 @@ tidevice list
408
408
  |:---:|------|------|
409
409
  | 📋 | `mobile_list_elements` | 列出页面元素 |
410
410
  | 📸 | `mobile_take_screenshot` | 截图 |
411
+ | 📸 | `mobile_screenshot_with_som` | Set-of-Mark 截图(智能标注) |
412
+ | 📸 | `mobile_screenshot_with_grid` | 带网格坐标的截图 |
411
413
  | 📐 | `mobile_get_screen_size` | 屏幕尺寸 |
412
414
  | 👆 | `mobile_click_by_text` | 文本点击 |
413
415
  | 👆 | `mobile_click_by_id` | ID 点击 |
414
416
  | 👆 | `mobile_click_at_coords` | 坐标点击 |
417
+ | 👆 | `mobile_click_by_percent` | 百分比点击 |
418
+ | 👆 | `mobile_click_by_som` | SoM 编号点击 |
419
+ | 👆 | `mobile_long_press_by_id` | ID 长按 |
420
+ | 👆 | `mobile_long_press_by_text` | 文本长按 |
421
+ | 👆 | `mobile_long_press_by_percent` | 百分比长按 |
422
+ | 👆 | `mobile_long_press_at_coords` | 坐标长按 |
415
423
  | ⌨️ | `mobile_input_text_by_id` | ID 输入 |
416
424
  | ⌨️ | `mobile_input_at_coords` | 坐标输入 |
417
425
  | 👆 | `mobile_swipe` | 滑动 |
@@ -422,6 +430,11 @@ tidevice list
422
430
  | 📦 | `mobile_list_apps` | 列出应用 |
423
431
  | 📱 | `mobile_list_devices` | 列出设备 |
424
432
  | 🔌 | `mobile_check_connection` | 检查连接 |
433
+ | 🔍 | `mobile_find_close_button` | 查找关闭按钮 |
434
+ | 🚫 | `mobile_close_popup` | 关闭弹窗 |
435
+ | 🚫 | `mobile_close_ad` | 智能关闭广告弹窗 |
436
+ | 🎯 | `mobile_template_close` | 模板匹配关闭弹窗 |
437
+ | ➕ | `mobile_template_add` | 添加 X 号模板 |
425
438
  | ✅ | `mobile_assert_text` | 断言文本 |
426
439
  | 📜 | `mobile_get_operation_history` | 操作历史 |
427
440
  | 🗑️ | `mobile_clear_operation_history` | 清空历史 |
@@ -65,16 +65,6 @@ templates/close_buttons/auto_x_0112_152840.png
65
65
  templates/close_buttons/auto_x_0112_153256.png
66
66
  templates/close_buttons/auto_x_0112_154847.png
67
67
  templates/close_buttons/gray_x_stock_ad.png
68
- tests/test_mind_cloud_my_space.py
69
- tests/test_mind_correct.py
70
- tests/test_mind_improved.py
71
- tests/test_mind_optimized.py
72
- tests/test_open_mind.py
73
- tests/test_priority_demo.py
74
- tests/test_simple.py
75
- tests/test_举报.py
76
- tests/test_切换语言到English.py
77
- tests/test_测试.py
78
68
  utils/__init__.py
79
69
  utils/logger.py
80
70
  utils/xml_formatter.py
@@ -25,7 +25,7 @@ if requirements_file.exists():
25
25
 
26
26
  setup(
27
27
  name="mobile-mcp-ai",
28
- version="2.5.3", # 修复:设备连接失败时显示详细错误和解决方案
28
+ version="2.5.5", # 支持左右滑动指定高度坐标和百分比
29
29
  author="douzi",
30
30
  author_email="1492994674@qq.com",
31
31
  description="移动端自动化 MCP Server - 支持 Android/iOS,AI 功能可选(基础工具不需要 AI)",
@@ -1,80 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- 测试用例: Mind云文档我的空间
5
- 生成时间: 2025-12-17 11:00:00
6
- """
7
- import time
8
- import uiautomator2 as u2
9
-
10
- PACKAGE_NAME = "com.im30.mind"
11
-
12
- # 广告关闭按钮关键词(可自定义)
13
- AD_CLOSE_KEYWORDS = ['关闭', '跳过', 'Skip', 'Close', '×', 'X', '我知道了', '稍后再说']
14
-
15
-
16
- def smart_wait(d, timeout=10):
17
- """智能等待页面稳定"""
18
- d.implicitly_wait(timeout)
19
- time.sleep(0.5) # 额外等待动画
20
-
21
-
22
- def close_ad_if_exists(d):
23
- """尝试关闭广告弹窗"""
24
- for keyword in AD_CLOSE_KEYWORDS:
25
- elem = d(textContains=keyword)
26
- if elem.exists(timeout=0.5):
27
- try:
28
- elem.click()
29
- print(f' 📢 关闭广告: {keyword}')
30
- time.sleep(0.5)
31
- return True
32
- except:
33
- pass
34
- return False
35
-
36
-
37
- def safe_click(d, selector, timeout=5):
38
- """安全点击(带等待和重试)"""
39
- try:
40
- if selector.exists(timeout=timeout):
41
- selector.click()
42
- return True
43
- return False
44
- except Exception as e:
45
- print(f' ⚠️ 点击失败: {e}')
46
- return False
47
-
48
-
49
- def test_main():
50
- # 连接设备
51
- d = u2.connect()
52
- d.implicitly_wait(10) # 设置全局等待
53
-
54
- # 启动应用
55
- d.app_start(PACKAGE_NAME)
56
- smart_wait(d)
57
-
58
- # 尝试关闭启动广告
59
- close_ad_if_exists(d)
60
-
61
- # 步骤1: 点击文本 'Mind'
62
- safe_click(d, d(text='Mind'))
63
- smart_wait(d)
64
- close_ad_if_exists(d) # 检查广告
65
-
66
- # 步骤2: 点击坐标 (756, 2277)
67
- d.click(756, 2277)
68
- smart_wait(d)
69
- close_ad_if_exists(d) # 检查广告
70
-
71
- # 步骤3: 点击坐标 (815, 285)
72
- d.click(815, 285)
73
- smart_wait(d)
74
- close_ad_if_exists(d) # 检查广告
75
-
76
- print('✅ 测试完成')
77
-
78
-
79
- if __name__ == '__main__':
80
- test_main()
@@ -1,73 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- 测试用例: Mind云文档我的空间_正确版
5
- 生成时间: 2025-12-17 11:08:10
6
- """
7
- import time
8
- import uiautomator2 as u2
9
-
10
- PACKAGE_NAME = "com.im30.mind"
11
-
12
- # 广告关闭按钮关键词(可自定义)
13
- AD_CLOSE_KEYWORDS = ['关闭', '跳过', 'Skip', 'Close', '×', 'X', '我知道了', '稍后再说']
14
-
15
-
16
- def smart_wait(d, seconds=1):
17
- """等待页面稳定"""
18
- time.sleep(seconds)
19
-
20
-
21
- def close_ad_if_exists(d, quick=False):
22
- """尝试关闭广告弹窗(quick=True 时只检查常见的)"""
23
- keywords = AD_CLOSE_KEYWORDS[:3] if quick else AD_CLOSE_KEYWORDS
24
- for keyword in keywords:
25
- elem = d(textContains=keyword)
26
- if elem.exists(timeout=0.3): # 缩短超时
27
- try:
28
- elem.click()
29
- print(f' 📢 关闭广告: {keyword}')
30
- time.sleep(0.3)
31
- return True
32
- except:
33
- pass
34
- return False
35
-
36
-
37
- def safe_click(d, selector, timeout=3):
38
- """安全点击(带等待)"""
39
- try:
40
- if selector.exists(timeout=timeout):
41
- selector.click()
42
- return True
43
- return False
44
- except Exception as e:
45
- print(f' ⚠️ 点击失败: {e}')
46
- return False
47
-
48
-
49
- def test_main():
50
- # 连接设备
51
- d = u2.connect()
52
- d.implicitly_wait(10) # 设置全局等待
53
-
54
- # 启动应用
55
- d.app_start(PACKAGE_NAME)
56
- smart_wait(d)
57
-
58
- # 尝试关闭启动广告
59
- close_ad_if_exists(d)
60
-
61
- # 步骤1: 点击坐标 (756, 2277)
62
- d.click(756, 2277)
63
- time.sleep(0.5) # 等待响应
64
-
65
- # 步骤2: 点击坐标 (815, 285)
66
- d.click(815, 285)
67
- time.sleep(0.5) # 等待响应
68
-
69
- print('✅ 测试完成')
70
-
71
-
72
- if __name__ == '__main__':
73
- test_main()
@@ -1,83 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- 测试用例: 打开Mind应用测试
5
- 生成时间: 2025-12-17 10:52:37
6
- """
7
- import time
8
- import uiautomator2 as u2
9
-
10
- PACKAGE_NAME = "com.im30.mind"
11
-
12
- # 广告关闭按钮关键词(可自定义)
13
- AD_CLOSE_KEYWORDS = ['关闭', '跳过', 'Skip', 'Close', '×', 'X', '我知道了', '稍后再说']
14
-
15
-
16
- def smart_wait(d, timeout=10):
17
- """智能等待页面稳定"""
18
- d.implicitly_wait(timeout)
19
- time.sleep(0.5) # 额外等待动画
20
-
21
-
22
- def close_ad_if_exists(d):
23
- """尝试关闭广告弹窗"""
24
- for keyword in AD_CLOSE_KEYWORDS:
25
- elem = d(textContains=keyword)
26
- if elem.exists(timeout=0.5):
27
- try:
28
- elem.click()
29
- print(f' 📢 关闭广告: {keyword}')
30
- time.sleep(0.5)
31
- return True
32
- except:
33
- pass
34
- return False
35
-
36
-
37
- def safe_click(d, selector, timeout=5):
38
- """安全点击(带等待和重试)"""
39
- try:
40
- if selector.exists(timeout=timeout):
41
- selector.click()
42
- return True
43
- return False
44
- except Exception as e:
45
- print(f' ⚠️ 点击失败: {e}')
46
- return False
47
-
48
-
49
- def test_main():
50
- # 连接设备
51
- d = u2.connect()
52
- d.implicitly_wait(10) # 设置全局等待
53
-
54
- # 启动应用
55
- d.app_start(PACKAGE_NAME)
56
- smart_wait(d)
57
-
58
- # 尝试关闭启动广告
59
- close_ad_if_exists(d)
60
-
61
- # 步骤1: 点击文本 'Mind'
62
- safe_click(d, d(text='Mind'))
63
- smart_wait(d)
64
- close_ad_if_exists(d) # 检查广告
65
-
66
- # 步骤2: 点击坐标 (540, 1200)
67
- d.click(540, 1200)
68
- smart_wait(d)
69
- close_ad_if_exists(d) # 检查广告
70
-
71
- # 步骤3: 输入文本 '测试'
72
- d(resourceId='com.im30.mind:id/search').set_text('测试')
73
- smart_wait(d)
74
-
75
- # 步骤4: 滑动 up
76
- d.swipe_ext('up')
77
- smart_wait(d)
78
-
79
- print('✅ 测试完成')
80
-
81
-
82
- if __name__ == '__main__':
83
- test_main()
@@ -1,77 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- 测试用例: Mind云文档我的空间_优化版
5
- 生成时间: 2025-12-17 11:04:53
6
- """
7
- import time
8
- import uiautomator2 as u2
9
-
10
- PACKAGE_NAME = "com.im30.mind"
11
-
12
- # 广告关闭按钮关键词(可自定义)
13
- AD_CLOSE_KEYWORDS = ['关闭', '跳过', 'Skip', 'Close', '×', 'X', '我知道了', '稍后再说']
14
-
15
-
16
- def smart_wait(d, seconds=1):
17
- """等待页面稳定"""
18
- time.sleep(seconds)
19
-
20
-
21
- def close_ad_if_exists(d, quick=False):
22
- """尝试关闭广告弹窗(quick=True 时只检查常见的)"""
23
- keywords = AD_CLOSE_KEYWORDS[:3] if quick else AD_CLOSE_KEYWORDS
24
- for keyword in keywords:
25
- elem = d(textContains=keyword)
26
- if elem.exists(timeout=0.3): # 缩短超时
27
- try:
28
- elem.click()
29
- print(f' 📢 关闭广告: {keyword}')
30
- time.sleep(0.3)
31
- return True
32
- except:
33
- pass
34
- return False
35
-
36
-
37
- def safe_click(d, selector, timeout=3):
38
- """安全点击(带等待)"""
39
- try:
40
- if selector.exists(timeout=timeout):
41
- selector.click()
42
- return True
43
- return False
44
- except Exception as e:
45
- print(f' ⚠️ 点击失败: {e}')
46
- return False
47
-
48
-
49
- def test_main():
50
- # 连接设备
51
- d = u2.connect()
52
- d.implicitly_wait(10) # 设置全局等待
53
-
54
- # 启动应用
55
- d.app_start(PACKAGE_NAME)
56
- smart_wait(d)
57
-
58
- # 尝试关闭启动广告
59
- close_ad_if_exists(d)
60
-
61
- # 步骤1: 点击文本 'Mind'
62
- safe_click(d, d(text='Mind'))
63
- time.sleep(0.5) # 等待响应
64
-
65
- # 步骤2: 点击坐标 (756, 2277)
66
- d.click(756, 2277)
67
- time.sleep(0.5) # 等待响应
68
-
69
- # 步骤3: 点击坐标 (815, 285)
70
- d.click(815, 285)
71
- time.sleep(0.5) # 等待响应
72
-
73
- print('✅ 测试完成')
74
-
75
-
76
- if __name__ == '__main__':
77
- test_main()