Files
workphone-sdk/sdk/agent/skills/app_manager.py

215 lines
6.6 KiB
Python

"""
应用管理技能 - 打开、关闭、切换应用
"""
import re
import logging
import sys
import os
from typing import Dict, Any, List
# 兼容独立运行和包导入
_agent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if _agent_dir not in sys.path:
sys.path.insert(0, _agent_dir)
try:
from skills.base import BaseSkill
except ImportError:
from ..base import BaseSkill
logger = logging.getLogger(__name__)
class AppManagerSkill(BaseSkill):
"""应用管理技能"""
PACKAGE = "" # 通用技能
NAME = "应用管理"
# 常用应用包名
APP_PACKAGES = {
"微信": "com.tencent.mm",
"抖音": "com.ss.android.ugc.aweme",
"支付宝": "com.eg.android.AlipayGphone",
"淘宝": "com.taobao.taobao",
"微博": "com.sina.weibo",
"qq": "com.tencent.mobileqq",
"设置": "com.android.settings",
"相机": "com.android.camera",
"浏览器": "com.android.chrome",
"豆包": "com.bytedance.doubao",
"小红书": "com.xingin.xhs",
"bilibili": "tv.danmaku.bili",
"知乎": "com.zhihu.android",
}
def open_app(self, app_name: str) -> Dict[str, Any]:
"""
打开应用
Args:
app_name: 应用名称(中文或包名)
Returns:
执行结果
"""
try:
# 查找包名
package = self.APP_PACKAGES.get(app_name)
if not package:
# 尝试直接作为包名
package = app_name
# 启动应用
self.d.app_start(package)
self.sleep(2)
# 验证是否启动成功
current = self.d.app_current()
if current.get("package") == package:
return {
"success": True,
"app_name": app_name,
"package": package,
"message": f"已打开{app_name}"
}
else:
return {
"success": False,
"error": f"应用启动失败或包名错误: {app_name}",
"package": package
}
except Exception as e:
logger.error(f"打开应用失败 {app_name}: {e}")
return {
"success": False,
"error": str(e),
"app_name": app_name
}
def close_app(self, app_name: str = None, package: str = None) -> Dict[str, Any]:
"""
关闭应用
Args:
app_name: 应用名称
package: 包名(优先)
Returns:
执行结果
"""
try:
if package:
target_package = package
elif app_name:
target_package = self.APP_PACKAGES.get(app_name, app_name)
else:
# 关闭当前应用
current = self.d.app_current()
target_package = current.get("package")
if target_package:
self.d.app_stop(target_package)
return {
"success": True,
"package": target_package,
"message": "应用已关闭"
}
else:
return {"success": False, "error": "未指定应用"}
except Exception as e:
logger.error(f"关闭应用失败: {e}")
return {"success": False, "error": str(e)}
def get_running_apps(self) -> Dict[str, Any]:
"""获取正在运行的应用列表"""
try:
self.d.press("recent")
self.sleep(1)
ui_tree = self.d.dump_hierarchy()
apps = self._parse_recent_tasks_from_ui(ui_tree)
self.home()
return {"success": True, "apps": apps}
except Exception as e:
return {"success": False, "error": str(e), "apps": []}
@staticmethod
def _parse_recent_tasks_from_ui(xml: str) -> List[Dict[str, Any]]:
"""从最近任务 UI 解析应用标题占位"""
out = []
if not xml:
return out
skip = {"最近", "清除", "关闭", "全部", "清理"}
for i, m in enumerate(re.finditer(r'\b(text|content-desc)="([^"]{1,80})"', xml)):
if i >= 50:
break
text = m.group(2).strip()
if text and text not in skip and not text.startswith("com."):
out.append({"index": len(out) + 1, "title": text})
return out
def get_installed_apps(self, limit: int = 100) -> Dict[str, Any]:
"""获取已安装的应用列表"""
try:
# 通过shell命令获取
result = self.d.shell("pm list packages -3") # 第三方应用
packages = []
for line in result.output.split('\n'):
if line.startswith('package:'):
pkg = line.replace('package:', '').strip()
packages.append(pkg)
return {
"success": True,
"packages": packages[:limit],
"total": len(packages)
}
except Exception as e:
return {"success": False, "error": str(e), "packages": []}
def switch_app(self, app_name: str) -> Dict[str, Any]:
"""
切换应用(如果已打开则切换,否则打开)
Args:
app_name: 应用名称
Returns:
执行结果
"""
try:
package = self.APP_PACKAGES.get(app_name, app_name)
# 检查是否正在运行
current = self.d.app_current()
if current.get("package") == package:
return {
"success": True,
"message": f"{app_name}已是当前应用",
"package": package
}
# 打开或切换
self.d.app_start(package)
self.sleep(2)
return {
"success": True,
"app_name": app_name,
"package": package,
"message": f"已切换到{app_name}"
}
except Exception as e:
logger.error(f"切换应用失败 {app_name}: {e}")
return {
"success": False,
"error": str(e),
"app_name": app_name
}