ADB (Android Debug Bridge) 详解

ADB是Android开发和测试的重要工具,让我们深入了解它的使用。

ADB基础命令

# 连接设备
adb devices                    # 查看连接的设备
adb connect <ip>:<port>        # 连接网络设备
adb kill-server                # 重启ADB服务
adb start-server               # 启动ADB服务

# 设备操作
adb shell                      # 进入设备shell
adb reboot                     # 重启设备
adb root                       # 获取ROOT权限(需支持)
adb remount                    # 重新挂载系统分区

# 文件操作
adb push <local> <remote>      # 推送文件到设备
adb pull <remote> <local>      # 从设备拉取文件
adb sync                       # 同步文件到设备

# 应用管理
adb install <apk_path>         # 安装应用
adb uninstall <package_name>   # 卸载应用
adb shell pm list packages     # 查看已安装包
adb shell dumpsys package      # 查看包信息

# 日志操作
adb logcat                     # 查看实时日志
adb logcat -c                  # 清空日志缓冲区
adb logcat -v time             # 按时间格式显示
adb logcat | grep "keyword"    # 过滤关键词

# 网络操作
adb shell netstat              # 查看网络连接
adb shell iptables -L          # 查看防火墙规则
adb forward tcp:<host_port> tcp:<device_port>  # 端口转发

ADB高级用法

import subprocess
import time
import os
from typing import Optional, Dict, List

class ADBController:
    """ADB控制器类 - 用于自动化设备管理"""
    
    def __init__(self, device_id: Optional[str] = None, timeout: int = 30):
        self.device_id = device_id
        self.timeout = timeout
        self.available_devices = self._get_connected_devices()
        self.current_device = self._select_device()
        print(f"ADB控制器初始化完成,当前设备: {self.current_device}")
    
    def _get_connected_devices(self) -> List[str]:
        """获取所有连接的设备ID"""
        try:
            result = subprocess.run(['adb', 'devices'], 
                                  capture_output=True, text=True, timeout=self.timeout)
            devices = result.stdout.strip().split('\n')[1:]  # 跳过标题行
            available_devices = []
            for device in devices:
                if device.strip() and 'device' in device and 'offline' not in device:
                    device_id = device.split('\t')[0]
                    available_devices.append(device_id)
            return available_devices
        except subprocess.TimeoutExpired:
            print("ADB命令执行超时")
            return []
        except Exception as e:
            print(f"获取设备列表失败: {e}")
            return []
    
    def _select_device(self) -> str:
        """选择当前操作设备"""
        if not self.available_devices:
            raise Exception("没有找到可用的ADB设备")
        
        if self.device_id and self.device_id in self.available_devices:
            return self.device_id
        else:
            # 选择第一个可用设备
            return self.available_devices[0]
    
    def execute_adb_command(self, command: str) -> str:
        """执行ADB命令并返回结果"""
        cmd = ['adb', '-s', self.current_device] + command.split()
        try:
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=self.timeout)
            if result.returncode != 0:
                print(f"ADB命令执行失败: {result.stderr}")
                return ""
            return result.stdout.strip()
        except subprocess.TimeoutExpired:
            print(f"ADB命令执行超时: {command}")
            return ""
        except Exception as e:
            print(f"执行ADB命令异常: {e}")
            return ""
    
    def install_apk(self, apk_path: str) -> bool:
        """安装APK应用"""
        if not os.path.exists(apk_path):
            print(f"APK文件不存在: {apk_path}")
            return False
        
        result = self.execute_adb_command(f'install {apk_path}')
        if "Success" in result:
            print(f"APK安装成功: {apk_path}")
            return True
        else:
            print(f"APK安装失败: {result}")
            return False
    
    def uninstall_app(self, package_name: str) -> bool:
        """卸载应用"""
        result = self.execute_adb_command(f'uninstall {package_name}')
        if "Success" in result:
            print(f"应用卸载成功: {package_name}")
            return True
        else:
            print(f"应用卸载失败: {result}")
            return False
    
    def get_app_info(self, package_name: str) -> Dict:
        """获取应用详细信息"""
        cmd = f'shell dumpsys package {package_name}'
        result = self.execute_adb_command(cmd)
        return {
            'package_name': package_name,
            'info': result[:1000] + "..." if len(result) > 1000 else result  # 限制输出长度
        }
    
    def take_screenshot(self, save_path: str) -> bool:
        """截屏并保存到指定路径"""
        temp_path = '/sdcard/temp_screenshot.png'
        # 在设备上截屏
        self.execute_adb_command(f'shell screencap {temp_path}')
        # 拉取到本地
        pull_result = self.execute_adb_command(f'pull {temp_path} {save_path}')
        # 删除设备上的临时文件
        self.execute_adb_command(f'shell rm {temp_path}')
        return "pulled" in pull_result.lower()
    
    def start_app(self, package_name: str, activity_name: Optional[str] = None) -> bool:
        """启动应用"""
        if activity_name:
            cmd = f'shell am start -n {package_name}/{activity_name}'
        else:
            cmd = f'shell monkey -p {package_name} -c android.intent.category.LAUNCHER 1'
        result = self.execute_adb_command(cmd)
        time.sleep(2)  # 等待应用启动
        return "Error" not in result
    
    def stop_app(self, package_name: str) -> bool:
        """停止应用"""
        result = self.execute_adb_command(f'shell am force-stop {package_name}')
        return True  # force-stop通常不会返回错误信息
    
    def get_running_apps(self) -> List[str]:
        """获取当前运行的应用列表"""
        result = self.execute_adb_command('shell dumpsys activity activities')
        apps = []
        for line in result.split('\n'):
            if 'mResumedActivity' in line or 'mFocusedActivity' in line:
                import re
                matches = re.findall(r'([a-zA-Z0-9._]+?)/', line)
                for match in matches:
                    if match and not match.startswith('com.android') and match not in apps:
                        apps.append(match)
        return apps[:10]  # 返回前10个应用
    
    def get_device_properties(self) -> Dict:
        """获取设备属性信息"""
        properties = {}
        props_to_get = [
            'ro.product.model',      # 设备型号
            'ro.product.brand',      # 品牌
            'ro.build.version.release',  # Android版本
            'ro.build.version.sdk',  # API级别
            'ro.product.cpu.abi',    # CPU架构
            'ro.board.platform',     # 平台
        ]
        
        for prop in props_to_get:
            value = self.execute_adb_command(f'shell getprop {prop}')
            properties[prop] = value.strip()
        return properties

# 使用示例
def adb_demo():
    """ADB操作演示"""
    try:
        controller = ADBController()
        print("✓ ADB控制器初始化成功")
        
        # 获取设备信息
        device_props = controller.get_device_properties()
        print(f"设备信息: {device_props}")
        
        # 获取运行中的应用
        running_apps = controller.get_running_apps()
        print(f"运行中的应用: {running_apps[:5]}")  # 显示前5个
        
        # 截屏示例
        screenshot_path = f"screenshot_{int(time.time())}.png"
        if controller.take_screenshot(screenshot_path):
            print(f"✓ 截屏保存至: {screenshot_path}")
        else:
            print("✗ 截屏失败")
            
    except Exception as e:
        print(f"✗ ADB操作演示失败: {e}")

if __name__ == "__main__":
    adb_demo()