Files
httprunner/docs/uixt/devices.md
2025-06-11 14:57:08 +08:00

24 KiB
Raw Blame History

设备管理文档

概述

HttpRunner UIXT 提供统一的设备管理接口,支持 Android、iOS、HarmonyOS 和 Web 浏览器等多种平台的设备发现、连接和管理。

设备接口

IDevice 核心接口

所有设备都实现统一的 IDevice 接口:

type IDevice interface {
    UUID() string                    // 设备唯一标识
    NewDriver(driverType DriverType) (IDriver, error) // 创建驱动
}

Android 设备

环境准备

Android SDK 安装

# 下载并安装 Android SDK
export ANDROID_HOME=/path/to/android-sdk
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/tools

# 验证安装
adb version

真机配置

  1. 开启开发者选项

    • 进入设置 → 关于手机
    • 连续点击版本号 7 次
  2. 启用 USB 调试

    • 进入设置 → 开发者选项
    • 开启 USB 调试
  3. 连接设备

    # 连接设备并授权
    adb devices
    
    # 如果显示 unauthorized在设备上点击允许
    

模拟器配置

# 创建 AVD
avdmanager create avd -n test_device -k "system-images;android-30;google_apis;x86_64"

# 启动模拟器
emulator -avd test_device

# 验证连接
adb devices

设备创建

import "github.com/httprunner/httprunner/v5/uixt/option"

// 基础创建
device, err := uixt.NewAndroidDevice(
    option.WithSerialNumber("device_serial"),
)

// 高级配置
device, err := uixt.NewAndroidDevice(
    option.WithSerialNumber("emulator-5554"),
    option.WithAdbLogOn(true),                    // 启用 ADB 日志
    option.WithReset(true),                       // 重置设备状态
    option.WithSystemPort(8200),                  // 系统端口
    option.WithDevicePort(6790),                  // 设备端口
    option.WithForwardPort(8080),                 // 端口转发
    option.WithInstallApp("/path/to/app.apk"),    // 安装应用
    option.WithGrantPermissions(true),            // 授予权限
    option.WithSkipServerInstallation(false),     // 跳过服务器安装
    option.WithUiAutomator2Timeout(60),          // UiAutomator2 超时
)

设备发现

// 发现所有连接的 Android 设备
devices, err := uixt.DiscoverAndroidDevices()
for _, device := range devices {
    fmt.Printf("Found device: %s\n", device.UUID())
}

// 发现模拟器
emulators, err := uixt.DiscoverAndroidEmulators()

配置选项

选项 类型 说明 默认值
WithSerialNumber string 设备序列号 必需
WithAdbLogOn bool 启用 ADB 日志 false
WithReset bool 重置设备状态 false
WithSystemPort int UiAutomator2 系统端口 8200
WithDevicePort int 设备端口 6790
WithForwardPort int 端口转发 0
WithInstallApp string 安装应用路径 ""
WithGrantPermissions bool 自动授予权限 false
WithSkipServerInstallation bool 跳过服务器安装 false
WithUiAutomator2Timeout int UiAutomator2 超时(秒) 60

Android 特有功能

应用管理

// 应用安装
err = driver.InstallApp("/path/to/app.apk")
err = driver.InstallApp("/path/to/app.apk", option.WithForceInstall(true))

// 应用卸载
err = driver.UninstallApp("com.example.app")
err = driver.UninstallApp("com.example.app", option.WithKeepData(true))

// 应用信息
appInfo, err := driver.GetAppInfo("com.example.app")
installed, err := driver.IsAppInstalled("com.example.app")
permissions, err := driver.GetAppPermissions("com.example.app")

权限管理

// 授予权限
err = driver.GrantPermission("com.example.app", "android.permission.CAMERA")

// 撤销权限
err = driver.RevokePermission("com.example.app", "android.permission.CAMERA")

// 批量授予权限
permissions := []string{
    "android.permission.CAMERA",
    "android.permission.RECORD_AUDIO",
    "android.permission.ACCESS_FINE_LOCATION",
}
err = driver.GrantPermissions("com.example.app", permissions)

系统设置

// WiFi 操作
err = driver.EnableWiFi()
err = driver.DisableWiFi()
err = driver.ConnectWiFi("SSID", "password")

// 移动数据操作
err = driver.EnableMobileData()
err = driver.DisableMobileData()

// 飞行模式
err = driver.EnableAirplaneMode()
err = driver.DisableAirplaneMode()

设备信息

// 获取设备信息
info, err := device.DeviceInfo()
fmt.Printf("Device: %s %s\n", info.Brand, info.Model)
fmt.Printf("Android: %s\n", info.Version)

// 获取电池信息
battery, err := device.BatteryInfo()
fmt.Printf("Battery: %d%%\n", battery.Level)

// 获取屏幕尺寸
size, err := device.WindowSize()
fmt.Printf("Screen: %dx%d\n", size.Width, size.Height)

iOS 设备

环境准备

Xcode 和开发者工具

# 安装 Xcode从 App Store
# 安装命令行工具
xcode-select --install

# 安装 ios-deploy
npm install -g ios-deploy

# 验证安装
ios-deploy --version

WebDriverAgent 配置

# 克隆 WebDriverAgent
git clone https://github.com/appium/WebDriverAgent.git
cd WebDriverAgent

# 配置开发者证书
# 在 Xcode 中打开 WebDriverAgent.xcodeproj
# 设置开发团队和签名证书

# 构建并安装到设备
xcodebuild -project WebDriverAgent.xcodeproj -scheme WebDriverAgentRunner -destination 'id=device_udid' test

真机配置

  1. 启用开发者模式

    • 连接设备到 Mac
    • 在设备上信任开发者证书
  2. 设备信任

    • 设置 → 通用 → VPN与设备管理
    • 信任开发者应用
  3. 获取设备 UDID

    # 使用 Xcode
    xcrun simctl list devices
    
    # 使用 idevice_id
    idevice_id -l
    

模拟器配置

# 列出可用的模拟器
xcrun simctl list devices

# 创建新模拟器
xcrun simctl create "iPhone 14" "iPhone 14" "iOS 16.0"

# 启动模拟器
xcrun simctl boot "iPhone 14"

# 安装应用到模拟器
xcrun simctl install booted /path/to/app.app

设备创建

// 基础创建
device, err := uixt.NewIOSDevice(
    option.WithUDID("device_udid"),
)

// 高级配置
device, err := uixt.NewIOSDevice(
    option.WithUDID("00008030-001234567890123A"),
    option.WithWDAPort(8700),                     // WDA 端口
    option.WithWDAMjpegPort(8800),               // MJPEG 端口
    option.WithResetHomeOnStartup(false),        // 启动时不回到主屏
    option.WithPreventWDAAttachments(true),      // 防止 WDA 附件
    option.WithWDAStartupTimeout(120),           // WDA 启动超时
    option.WithWDAConnectionTimeout(60),         // WDA 连接超时
    option.WithWDACommandTimeout(30),            // WDA 命令超时
    option.WithAcceptAlerts(true),               // 自动接受弹窗
    option.WithDismissAlerts(false),             // 自动关闭弹窗
)

设备发现

// 发现所有连接的 iOS 设备
devices, err := uixt.DiscoverIOSDevices()
for _, device := range devices {
    fmt.Printf("Found device: %s\n", device.UUID())
}

// 发现模拟器
simulators, err := uixt.DiscoverIOSSimulators()

// 按条件筛选设备
realDevices, err := uixt.DiscoverIOSDevices(uixt.DeviceFilter{
    DeviceType: "real",
    IOSVersion: "16.0+",
})

配置选项

选项 类型 说明 默认值
WithUDID string 设备 UDID 必需
WithWDAPort int WebDriverAgent 端口 8700
WithWDAMjpegPort int MJPEG 流端口 8800
WithResetHomeOnStartup bool 启动时回到主屏 true
WithPreventWDAAttachments bool 防止 WDA 附件 false
WithWDAStartupTimeout int WDA 启动超时(秒) 120
WithWDAConnectionTimeout int WDA 连接超时(秒) 60
WithWDACommandTimeout int WDA 命令超时(秒) 30
WithAcceptAlerts bool 自动接受弹窗 false
WithDismissAlerts bool 自动关闭弹窗 false

iOS 特有功能

WebDriverAgent 管理

// 启动 WDA
err = device.StartWDA()

// 停止 WDA
err = device.StopWDA()

// 检查 WDA 状态
isRunning := device.IsWDARunning()

// 重启 WDA
err = device.RestartWDA()

// 获取 WDA 状态
status, err := device.GetWDAStatus()

应用管理

// 应用安装(需要开发者证书)
err = driver.InstallApp("/path/to/app.ipa")

// 应用卸载
err = driver.UninstallApp("com.example.app")

// 应用信息
appInfo, err := driver.GetAppInfo("com.example.app")
installed, err := driver.IsAppInstalled("com.example.app")

// 应用状态
state, err := driver.GetAppState("com.example.app")
// 0: not installed, 1: not running, 2: running in background, 4: running in foreground

系统操作

// Siri 操作
err = driver.ActivateSiri("打开设置")

// 锁定/解锁
err = driver.Lock()
err = driver.Unlock()

// 摇晃设备
err = driver.Shake()

// 音量控制
err = driver.VolumeUp()
err = driver.VolumeDown()

// 截图和录制
screenshot, err := driver.ScreenShot()
err = driver.StartScreenRecord()
videoPath, err := driver.StopScreenRecord()

设备信息

// 获取设备信息
info, err := device.DeviceInfo()
fmt.Printf("Device: %s %s\n", info.Model, info.Name)
fmt.Printf("iOS: %s\n", info.Version)

// 获取电池信息
battery, err := device.BatteryInfo()
fmt.Printf("Battery: %d%%, State: %s\n", battery.Level, battery.State)

// 获取屏幕信息
size, err := device.WindowSize()
scale, err := device.GetScreenScale()

HarmonyOS 设备

环境准备

HarmonyOS SDK 安装

# 下载并安装 HarmonyOS SDK
export HARMONY_HOME=/path/to/harmony-sdk
export PATH=$PATH:$HARMONY_HOME/toolchains

# 验证安装
hdc version

设备配置

  1. 开启开发者模式

    • 进入设置 → 关于手机
    • 连续点击版本号 7 次
  2. 启用 USB 调试

    • 进入设置 → 系统和更新 → 开发人员选项
    • 开启 USB 调试
  3. 连接设备

    # 连接设备并授权
    hdc list targets
    
    # 如果显示 unauthorized在设备上点击允许
    

设备创建

// 基础创建
device, err := uixt.NewHarmonyDevice(
    option.WithConnectKey("device_connect_key"),
)

// 高级配置
device, err := uixt.NewHarmonyDevice(
    option.WithConnectKey("192.168.1.100:5555"),
    option.WithHDCLogOn(true),                    // 启用 HDC 日志
    option.WithSystemPort(9200),                  // 系统端口
    option.WithDevicePort(6790),                  // 设备端口
    option.WithHDCTimeout(60),                    // HDC 超时
)

设备发现

// 发现所有连接的 HarmonyOS 设备
devices, err := uixt.DiscoverHarmonyDevices()
for _, device := range devices {
    fmt.Printf("Found device: %s\n", device.UUID())
}

// 网络设备发现
networkDevices, err := uixt.DiscoverHarmonyNetworkDevices()

配置选项

选项 类型 说明 默认值
WithConnectKey string 设备连接密钥 必需
WithHDCLogOn bool 启用 HDC 日志 false
WithSystemPort int 系统端口 9200
WithDevicePort int 设备端口 6790
WithHDCTimeout int HDC 超时(秒) 60

HarmonyOS 特有功能

应用管理

// 应用安装
err = driver.InstallApp("/path/to/app.hap")

// 应用卸载
err = driver.UninstallApp("com.example.harmony.app")

// 应用信息
appInfo, err := driver.GetAppInfo("com.example.harmony.app")
installed, err := driver.IsAppInstalled("com.example.harmony.app")

分布式操作

// 设备协同
err = driver.ConnectDistributedDevice("target_device_id")
err = driver.DisconnectDistributedDevice("target_device_id")

// 跨设备应用迁移
err = driver.MigrateApp("com.example.app", "target_device_id")

原子化服务

// 启动原子化服务
err = driver.LaunchAtomicService("service_id", map[string]interface{}{
    "param1": "value1",
    "param2": "value2",
})

// 停止原子化服务
err = driver.StopAtomicService("service_id")

Web 浏览器设备

环境准备

浏览器驱动安装

# Chrome
# 下载 ChromeDriver 并添加到 PATH
wget https://chromedriver.storage.googleapis.com/latest/chromedriver_mac64.zip
unzip chromedriver_mac64.zip
mv chromedriver /usr/local/bin/

# Firefox
# 下载 GeckoDriver
wget https://github.com/mozilla/geckodriver/releases/download/v0.33.0/geckodriver-v0.33.0-macos.tar.gz
tar -xzf geckodriver-v0.33.0-macos.tar.gz
mv geckodriver /usr/local/bin/

# Safari (macOS only)
# 启用开发者菜单
# Safari → 偏好设置 → 高级 → 在菜单栏中显示"开发"菜单
# 开发 → 允许远程自动化

# Edge
# 下载 EdgeDriver
wget https://msedgedriver.azureedge.net/latest/edgedriver_mac64.zip

设备创建

// Chrome 浏览器
device, err := uixt.NewBrowserDevice(
    option.WithBrowserID("chrome"),
)

// 高级配置
device, err := uixt.NewBrowserDevice(
    option.WithBrowserID("chrome"),
    option.WithHeadless(false),                   // 非无头模式
    option.WithWindowSize(1920, 1080),           // 窗口大小
    option.WithUserAgent("custom-agent"),         // 自定义 User-Agent
    option.WithProxy("http://proxy:8080"),        // 代理设置
    option.WithExtensions([]string{"ext1", "ext2"}), // 扩展
    option.WithDownloadDir("/path/to/downloads"), // 下载目录
    option.WithIncognito(true),                   // 隐私模式
)

支持的浏览器

浏览器 ID 驱动 说明
Chrome chrome ChromeDriver Google Chrome
Firefox firefox GeckoDriver Mozilla Firefox
Safari safari SafariDriver Apple Safari (macOS)
Edge edge EdgeDriver Microsoft Edge

配置选项

选项 类型 说明 默认值
WithBrowserID string 浏览器标识 必需
WithHeadless bool 无头模式 true
WithWindowSize int, int 窗口大小 1280x720
WithUserAgent string User-Agent 默认
WithProxy string 代理地址
WithExtensions []string 扩展列表
WithDownloadDir string 下载目录 默认
WithIncognito bool 隐私模式 false

Web 特有功能

页面管理

// 页面导航
err = driver.NavigateTo("https://example.com")
err = driver.Refresh()
err = driver.GoBack()
err = driver.GoForward()

// 页面信息
title, err := driver.GetTitle()
url, err := driver.GetCurrentURL()
source, err := driver.GetPageSource()

标签页管理

// 标签页操作
err = driver.NewTab()
err = driver.CloseTab(1)
err = driver.SwitchToTab(0)

// 获取标签页信息
tabs, err := driver.GetTabs()
currentTab, err := driver.GetCurrentTab()
// Cookie 操作
cookies, err := driver.GetCookies()
err = driver.SetCookie("name", "value", "domain.com")
err = driver.DeleteCookie("name")
err = driver.DeleteAllCookies()

JavaScript 执行

// 执行 JavaScript
result, err := driver.ExecuteScript("return document.title;")
err = driver.ExecuteAsyncScript("callback(arguments[0]);", "test")

// 注入脚本
err = driver.InjectScript("console.log('injected');")

设备管理工具

设备发现工具

// 发现所有平台的设备
allDevices, err := uixt.DiscoverAllDevices()
for platform, devices := range allDevices {
    fmt.Printf("Platform: %s\n", platform)
    for _, device := range devices {
        fmt.Printf("  Device: %s\n", device.UUID())
    }
}

// 按平台发现
androidDevices, err := uixt.DiscoverDevicesByPlatform("android")
iosDevices, err := uixt.DiscoverDevicesByPlatform("ios")

设备选择工具

// 交互式设备选择
device, err := uixt.SelectDeviceInteractively()

// 按条件选择设备
device, err := uixt.SelectDevice(uixt.DeviceFilter{
    Platform: "android",
    Model:    "Pixel",
    Online:   true,
    Version:  "11+",
})

// 智能选择最佳设备
device, err := uixt.SelectBestDevice(uixt.DevicePreference{
    PreferReal:      true,  // 优先真机
    PreferHighRes:   true,  // 优先高分辨率
    PreferNewVersion: true, // 优先新版本
})

设备健康检查

// 检查设备健康状态
health, err := device.HealthCheck()
if health.IsHealthy {
    fmt.Println("Device is healthy")
} else {
    fmt.Printf("Device issues: %v\n", health.Issues)
}

// 修复设备问题
err = device.Repair()

// 设备诊断
diagnosis, err := device.Diagnose()
fmt.Printf("Diagnosis: %s\n", diagnosis.Report)

设备状态管理

设备状态

// 获取设备状态
status, err := device.Status()
fmt.Printf("Status: %s\n", status.State) // online, offline, unauthorized

// 等待设备就绪
err = device.WaitForReady(30 * time.Second)

// 检查设备连接
isConnected := device.IsConnected()

// 设备可用性检查
isAvailable := device.IsAvailable()

设备重置

// 软重置(重启应用)
err = device.SoftReset()

// 硬重置(重启设备)
err = device.HardReset()

// 恢复出厂设置(仅 Android
err = device.FactoryReset()

// 清理设备缓存
err = device.ClearCache()

多设备管理

设备池

// 创建设备池
pool := uixt.NewDevicePool()

// 添加设备到池
pool.AddDevice(androidDevice)
pool.AddDevice(iosDevice)
pool.AddDevice(harmonyDevice)

// 从池中获取可用设备
device, err := pool.AcquireDevice(uixt.DeviceFilter{
    Platform: "android",
})
defer pool.ReleaseDevice(device)

// 并行执行任务
results := pool.ExecuteParallel(func(device IDevice) interface{} {
    // 在设备上执行任务
    return performTask(device)
})

// 设备池统计
stats := pool.GetStats()
fmt.Printf("Total: %d, Available: %d, InUse: %d\n",
    stats.Total, stats.Available, stats.InUse)

设备同步

// 同步多个设备的操作
sync := uixt.NewDeviceSync()
sync.AddDevice(device1)
sync.AddDevice(device2)
sync.AddDevice(device3)

// 同步执行操作
err = sync.Execute(func(device IDevice) error {
    return device.TapXY(0.5, 0.5)
})

// 等待所有设备完成
err = sync.WaitForAll(30 * time.Second)

设备集群

// 创建设备集群
cluster := uixt.NewDeviceCluster()

// 添加设备组
cluster.AddGroup("android", androidDevices)
cluster.AddGroup("ios", iosDevices)

// 按组执行任务
results, err := cluster.ExecuteByGroup("android", func(device IDevice) interface{} {
    return performAndroidTask(device)
})

// 负载均衡
device, err := cluster.GetLeastBusyDevice()

最佳实践

1. 设备选择策略

// 优先选择真机,其次模拟器
func selectBestDevice() (IDevice, error) {
    // 先尝试真机
    devices, err := uixt.DiscoverAndroidDevices()
    if err == nil && len(devices) > 0 {
        return devices[0], nil
    }

    // 再尝试模拟器
    emulators, err := uixt.DiscoverAndroidEmulators()
    if err == nil && len(emulators) > 0 {
        return emulators[0], nil
    }

    return nil, fmt.Errorf("no available devices")
}

2. 设备资源管理

// 使用 defer 确保资源释放
func useDevice() error {
    device, err := uixt.NewAndroidDevice(option.WithSerialNumber("device_serial"))
    if err != nil {
        return err
    }
    defer device.Cleanup() // 确保清理资源

    // 使用设备...
    return nil
}

3. 错误处理和重试

// 带重试的设备操作
func performWithRetry(device IDevice, operation func() error) error {
    maxRetries := 3
    for i := 0; i < maxRetries; i++ {
        err := operation()
        if err == nil {
            return nil
        }

        // 检查是否是设备连接问题
        if isDeviceConnectionError(err) {
            // 尝试重新连接
            device.Reconnect()
        }

        time.Sleep(time.Duration(i+1) * time.Second)
    }
    return fmt.Errorf("operation failed after %d retries", maxRetries)
}

4. 设备监控

// 设备监控
func monitorDevice(device IDevice) {
    ticker := time.NewTicker(30 * time.Second)
    defer ticker.Stop()

    for range ticker.C {
        status, err := device.Status()
        if err != nil {
            log.Error("Failed to get device status: %v", err)
            continue
        }

        if status.State != "online" {
            log.Warn("Device %s is %s", device.UUID(), status.State)
            // 尝试修复
            device.Repair()
        }
    }
}

故障排除

常见问题

Android 设备

  1. 设备未识别

    # 检查 ADB 连接
    adb devices
    
    # 重启 ADB 服务
    adb kill-server
    adb start-server
    
    # 检查驱动程序
    # Windows: 更新设备驱动
    # macOS: 检查系统偏好设置中的安全性设置
    
  2. UiAutomator2 启动失败

    # 检查端口占用
    netstat -an | grep 8200
    
    # 清理应用数据
    adb shell pm clear io.appium.uiautomator2.server
    adb shell pm clear io.appium.uiautomator2.server.test
    
    # 重新安装服务
    adb uninstall io.appium.uiautomator2.server
    adb uninstall io.appium.uiautomator2.server.test
    
  3. 权限问题

    # 检查 USB 调试权限
    adb shell settings get global development_settings_enabled
    
    # 授予应用权限
    adb shell pm grant com.example.app android.permission.CAMERA
    

iOS 设备

  1. WDA 启动失败

    # 检查开发者证书
    security find-identity -v -p codesigning
    
    # 重新安装 WDA
    xcodebuild -project WebDriverAgent.xcodeproj -scheme WebDriverAgentRunner -destination 'id=device_udid' test
    
    # 检查设备信任
    # 设置 → 通用 → VPN与设备管理 → 信任开发者应用
    
  2. 设备信任问题

    • 在设备上信任开发者证书
    • 检查设备是否已解锁
    • 确保设备已配对
  3. 网络连接问题

    # 检查端口转发
    iproxy 8700 8700 device_udid
    
    # 测试 WDA 连接
    curl http://localhost:8700/status
    

HarmonyOS 设备

  1. HDC 连接失败

    # 检查 HDC 连接
    hdc list targets
    
    # 重启 HDC 服务
    hdc kill
    hdc start
    
    # 检查网络连接(网络调试)
    ping device_ip
    
  2. 应用安装失败

    # 检查应用签名
    hdc shell bm dump -a
    
    # 清理应用数据
    hdc shell bm uninstall -n com.example.app
    

Web 浏览器

  1. 驱动版本不匹配

    # 检查浏览器版本
    google-chrome --version
    firefox --version
    
    # 更新驱动程序
    # 确保驱动版本与浏览器版本匹配
    
  2. 端口冲突

    # 查找占用端口的进程
    lsof -i :4444
    
    # 终止进程
    kill -9 <pid>
    

通用问题

  1. 端口冲突

    # 查找占用端口的进程
    lsof -i :8700
    
    # 终止进程
    kill -9 <pid>
    
    # 使用不同端口
    device, err := uixt.NewIOSDevice(
        option.WithUDID("device_udid"),
        option.WithWDAPort(8701),
    )
    
  2. 权限问题

    # 检查文件权限
    ls -la /path/to/device/files
    
    # 修改权限
    chmod +x /path/to/executable
    
    # macOS 安全设置
    # 系统偏好设置 → 安全性与隐私 → 隐私 → 辅助功能
    
  3. 内存不足

    # 检查系统资源
    top
    free -h
    
    # 清理设备缓存
    device.ClearCache()
    
    # 重启设备
    device.HardReset()
    

参考资料