import re
import shlex
import subprocessclass ADBClient:def __init__(self, ip, port):"""初始化ADBClient实例。:param ip: 远程设备的IP地址。:param port: 远程设备的端口号。"""self.ip = ipself.port = portdef is_app_running(self, package_name):"""检查指定的应用是否正在设备上运行。:param package_name: 应用的包名。:return: 如果应用正在运行,返回True;否则返回False。"""try:# 通过ADB命令获取当前运行中的应用列表,并检索目标应用包名result = subprocess.run(["adb", "-s", f"{self.ip}:{self.port}", "shell", "ps"], capture_output=True,text=True)output = result.stdout# 使用正则表达式搜索应用包名if re.search(package_name, output):return Trueelse:return Falseexcept subprocess.CalledProcessError as e:# 打印错误信息并返回False,表示未能成功执行ADB命令print(f"发生错误:{e}")return Falsedef open_app(self, package_name, activity_name):"""在设备上启动指定的应用。:param package_name: 应用的包名。:param activity_name: 应用要启动的Activity名称。:return: 如果应用成功启动,返回True;否则返回False。"""try:# 首先检查应用是否已经在运行if self.is_app_running(package_name):print("@@@应用已经在运行")return True# 如果应用未运行,则通过ADB命令启动应用subprocess.run(["adb", "-s", f"{self.ip}:{self.port}", "shell", "am", "start", "-n",f"{package_name}/{activity_name}"])except subprocess.CalledProcessError as e:# 如果ADB命令执行出错,打印错误信息print(f"发生错误:{e}")return Falsedef execute_adb_command(self, adb_command):"""执行ADB命令,并返回命令的输出和错误信息。参数:- adb_command: 要执行的ADB命令字符串。返回值:- 一个元组,包括命令的输出(stdout)和错误信息(stderr)。如果命令执行失败,返回None和错误信息。"""try:# 使用subprocess运行ADB命令,将命令字符串分割为列表,添加设备IP和端口信息result = subprocess.run(["adb", "-s", f"{self.ip}:{self.port}"] + adb_command.split(), capture_output=True,text=True)# 返回执行结果的输出和错误信息return result.stdout, result.stderrexcept subprocess.CalledProcessError as e:# 如果命令执行出错,返回错误信息return None, f"发生错误:{e}"def get_current_window_info(self):"""获取当前窗口的信息,包括包名和应用名称。该方法通过运行ADB命令,提取当前焦点窗口的包名和应用名称。返回:tuple: 成功时返回一个包含包名和应用名称的元组 (pkg, path);如果无法提取到信息,则返回 (None, None)。"""# 构造获取当前窗口信息的ADB命令cmd = 'shell dumpsys window | grep mCurrentFocus'# 运行ADB命令并获取输出result = subprocess.run(["adb", "-s", f"{self.ip}:{self.port}"] + cmd.split(), capture_output=True, text=True)output = result.stdout.strip()# 使用正则表达式提取包名和应用名称pattern = r"mCurrentFocus=Window\{.+?\s+(\S+)/(.+?)\}"match = re.search(pattern, output)if match:# 如果匹配成功,提取并返回包名和应用名称pkg = match.group(1)path = match.group(2)return pkg, pathelse:# 如果匹配失败,返回Nonereturn None, None# 坐标点击事件def tap_by_coordinates(self, x, y):try:# 构建 adb 命令cmd = ["adb", "-s", f"{self.ip}:{self.port}", "shell", "input", "tap", str(x), str(y)]# 执行点击事件subprocess.run(cmd, check=True)print(f"已点击坐标 ({x}, {y})")except subprocess.CalledProcessError as e:print(f"Error: {e}")# 跳转到path指定页面def toPath(self, action, param=None):"""根据指定的操作动作和参数,向应用发送命令,实现页面跳转或其他操作。参数:action: 字符串,指定要执行的操作,例如"settings"表示设置页面。param: 可选参数,字符串类型,当需要传递额外的参数给操作时使用,比如用户ID或视频ID等。返回值: True表示操作成功,False表示操作失败。"""commands = {# 某页面"settings": "am start -n ..."# 其他页面往这放}# 检查命令是否在映射中if action in commands:# 执行命令full_cmd = ["adb", "-s", f"{self.ip}:{self.port}", "shell"] + shlex.split(commands[action])subprocess.run(full_cmd, check=True)return Trueelse:# 如果命令不在映射中,返回Falsereturn False
食用方法
# 创建ADBClient实例,并尝试打开指定的应用
adb_client = ADBClient('192.168.1.5', '5003')
adb_client.open_app("com.zhiliaoapp.musically", "com.ss.android.ugc.aweme.splash.SplashActivity")
res = adb_client.execute_adb_command("root")
print("执行adb命令返回的结果:" + str(res))# 获取当前活动的应用程序包名称和页面ID
pkg, path = adb_client.get_current_window_info()
print("当前活动的应用程序包名称:", pkg)
print("当前活动的页面ID:", path)# 模拟点击"com.zhiliaoapp.musically:id/c5w"元素
adb_client.tap_by_coordinates(667, 633)# 跳转页面
adb_client.toPath('settings')