diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 95f7bc5c..cdf53f67 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,14 @@ # Release History +## v4.3.2 (2022-12-26) + +**go version** + +- feat: run Android UI automation with adb by default, add `uixt.WithUIA2(true)` option to use uiautomator2 +- refactor: remove unused APIs in UI automation +- refactor: convert cases by specifying from/to format +- change: remove traceroute/curl sub commands + ## v4.3.1 (2022-12-22) **go version** diff --git a/examples/uitest/demo_android_douyin_test.go b/examples/uitest/demo_android_douyin_test.go index 8ef5d2c4..7d7c94f4 100644 --- a/examples/uitest/demo_android_douyin_test.go +++ b/examples/uitest/demo_android_douyin_test.go @@ -12,7 +12,7 @@ import ( func TestAndroidDouYinLive(t *testing.T) { testCase := &hrp.TestCase{ Config: hrp.NewConfig("通过 feed 头像进入抖音直播间"). - SetAndroid(uixt.WithAdbLogOn(true)), + SetAndroid(uixt.WithUIA2(false), uixt.WithAdbLogOn(true)), TestSteps: []hrp.IStep{ hrp.NewStep("启动抖音"). Android(). diff --git a/hrp/internal/version/VERSION b/hrp/internal/version/VERSION index 9198ad67..b0136b0c 100644 --- a/hrp/internal/version/VERSION +++ b/hrp/internal/version/VERSION @@ -1 +1 @@ -v4.3.1 \ No newline at end of file +v4.3.2 \ No newline at end of file diff --git a/hrp/pkg/uixt/android_adb_driver.go b/hrp/pkg/uixt/android_adb_driver.go new file mode 100644 index 00000000..7aba3126 --- /dev/null +++ b/hrp/pkg/uixt/android_adb_driver.go @@ -0,0 +1,337 @@ +package uixt + +import ( + "bytes" + "fmt" + "strconv" + "strings" + "time" + + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + + "github.com/httprunner/httprunner/v4/hrp/internal/code" + "github.com/httprunner/httprunner/v4/hrp/pkg/gadb" +) + +type adbDriver struct { + Driver + + adbClient gadb.Device + logcat *AdbLogcat +} + +func NewAdbDriver() *adbDriver { + log.Info().Msg("init adb driver") + return &adbDriver{} +} + +func (ad *adbDriver) NewSession(capabilities Capabilities) (sessionInfo SessionInfo, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) DeleteSession() (err error) { + return errDriverNotImplemented +} + +func (ad *adbDriver) Status() (deviceStatus DeviceStatus, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) DeviceInfo() (deviceInfo DeviceInfo, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) Location() (location Location, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) BatteryInfo() (batteryInfo BatteryInfo, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) WindowSize() (size Size, err error) { + // adb shell wm size + resp, err := ad.adbClient.RunShellCommand("wm", "size") + if err != nil { + return + } + + // Physical size: 1080x2340 + s := strings.Trim(strings.Split(resp, ": ")[1], "\n") + ss := strings.Split(s, "x") + width, _ := strconv.Atoi(ss[0]) + height, _ := strconv.Atoi(ss[1]) + size = Size{Width: width, Height: height} + return +} + +func (ad *adbDriver) Screen() (screen Screen, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) Scale() (scale float64, err error) { + return 1, nil +} + +// PressBack simulates a short press on the BACK button. +func (ad *adbDriver) PressBack(options ...DataOption) (err error) { + // adb shell input keyevent 4 + _, err = ad.adbClient.RunShellCommand("input", "keyevent", fmt.Sprintf("%d", KCBack)) + return +} + +func (ad *adbDriver) StartCamera() (err error) { + if _, err = ad.adbClient.RunShellCommand("rm", "-r", "/sdcard/DCIM/Camera"); err != nil { + return err + } + time.Sleep(5 * time.Second) + var version string + if version, err = ad.adbClient.RunShellCommand("getprop", "ro.build.version.release"); err != nil { + return err + } + if version == "11" || version == "12" { + if _, err = ad.adbClient.RunShellCommand("am", "start", "-a", "android.media.action.STILL_IMAGE_CAMERA"); err != nil { + return err + } + time.Sleep(5 * time.Second) + if _, err = ad.adbClient.RunShellCommand("input", "swipe", "750", "1000", "250", "1000"); err != nil { + return err + } + time.Sleep(5 * time.Second) + if _, err = ad.adbClient.RunShellCommand("input", "keyevent", fmt.Sprintf("%d", KCCamera)); err != nil { + return err + } + return + } else { + if _, err = ad.adbClient.RunShellCommand("am", "start", "-a", "android.media.action.VIDEO_CAPTURE"); err != nil { + return err + } + time.Sleep(5 * time.Second) + if _, err = ad.adbClient.RunShellCommand("input", "keyevent", fmt.Sprintf("%d", KCCamera)); err != nil { + return err + } + return + } +} + +func (ad *adbDriver) StopCamera() (err error) { + err = ad.PressBack() + if err != nil { + return err + } + err = ad.Homescreen() + if err != nil { + return err + } + + // kill samsung shell command + if _, err = ad.adbClient.RunShellCommand("am", "force-stop", "com.sec.android.app.camera"); err != nil { + return err + } + + // kill other camera (huawei mi) + if _, err = ad.adbClient.RunShellCommand("am", "force-stop", "com.android.camera2"); err != nil { + return err + } + return +} + +func (ad *adbDriver) Homescreen() (err error) { + return ad.PressKeyCode(KCHome, KMEmpty) +} + +func (ad *adbDriver) PressKeyCode(keyCode KeyCode, metaState KeyMeta) (err error) { + // adb shell input keyevent + _, err = ad.adbClient.RunShellCommand( + "input", "keyevent", fmt.Sprintf("%d", keyCode)) + return +} + +func (ad *adbDriver) AppLaunch(bundleId string) (err error) { + // 不指定 Activity 名称启动(启动主 Activity) + // adb shell monkey -p -c android.intent.category.LAUNCHER 1 + sOutput, err := ad.adbClient.RunShellCommand( + "monkey", "-p", bundleId, "-c", "android.intent.category.LAUNCHER", "1", + ) + if err != nil { + return err + } + if strings.Contains(sOutput, "monkey aborted") { + return fmt.Errorf("app launch: %s", strings.TrimSpace(sOutput)) + } + return nil +} + +func (ad *adbDriver) AppTerminate(bundleId string) (successful bool, err error) { + // 强制停止应用,停止 相关的进程 + // adb shell am force-stop + _, err = ad.adbClient.RunShellCommand("am", "force-stop", bundleId) + return err == nil, err +} + +func (ad *adbDriver) Tap(x, y int, options ...DataOption) error { + return ad.TapFloat(float64(x), float64(y), options...) +} + +func (ad *adbDriver) TapFloat(x, y float64, options ...DataOption) (err error) { + // adb shell input tap x y + _, err = ad.adbClient.RunShellCommand( + "input", "tap", fmt.Sprintf("%.1f", x), fmt.Sprintf("%.1f", y)) + return +} + +func (ad *adbDriver) DoubleTap(x, y int) error { + return ad.DoubleTapFloat(float64(x), float64(y)) +} + +func (ad *adbDriver) DoubleTapFloat(x, y float64) (err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) TouchAndHold(x, y int, second ...float64) (err error) { + return ad.TouchAndHoldFloat(float64(x), float64(y), second...) +} + +func (ad *adbDriver) TouchAndHoldFloat(x, y float64, second ...float64) (err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) Drag(fromX, fromY, toX, toY int, options ...DataOption) error { + return ad.DragFloat(float64(fromX), float64(fromY), float64(toX), float64(toY), options...) +} + +func (ad *adbDriver) DragFloat(fromX, fromY, toX, toY float64, options ...DataOption) (err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) Swipe(fromX, fromY, toX, toY int, options ...DataOption) error { + return ad.SwipeFloat(float64(fromX), float64(fromY), float64(toX), float64(toY), options...) +} + +func (ad *adbDriver) SwipeFloat(fromX, fromY, toX, toY float64, options ...DataOption) error { + // adb shell input swipe fromX fromY toX toY + _, err := ad.adbClient.RunShellCommand( + "input", "swipe", + fmt.Sprintf("%.1f", fromX), fmt.Sprintf("%.1f", fromY), + fmt.Sprintf("%.1f", toX), fmt.Sprintf("%.1f", toY), + ) + return err +} + +func (ad *adbDriver) ForceTouch(x, y int, pressure float64, second ...float64) error { + return ad.ForceTouchFloat(float64(x), float64(y), pressure, second...) +} + +func (ad *adbDriver) ForceTouchFloat(x, y, pressure float64, second ...float64) (err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) SetPasteboard(contentType PasteboardType, content string) (err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) GetPasteboard(contentType PasteboardType) (raw *bytes.Buffer, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) SendKeys(text string, options ...DataOption) (err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) Input(text string, options ...DataOption) (err error) { + return ad.SendKeys(text, options...) +} + +func (ad *adbDriver) PressButton(devBtn DeviceButton) (err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) Rotation() (rotation Rotation, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) SetRotation(rotation Rotation) (err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) Screenshot() (raw *bytes.Buffer, err error) { + // adb shell screencap -p + resp, err := ad.adbClient.RunShellCommandWithBytes( + "screencap", "-p", + ) + if err == nil { + return bytes.NewBuffer(resp), nil + } + return nil, err +} + +func (ad *adbDriver) Source(srcOpt ...SourceOption) (source string, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) AccessibleSource() (source string, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) HealthCheck() (err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) GetAppiumSettings() (settings map[string]interface{}, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) SetAppiumSettings(settings map[string]interface{}) (ret map[string]interface{}, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) IsHealthy() (healthy bool, err error) { + err = errDriverNotImplemented + return +} + +func (ad *adbDriver) StartCaptureLog(identifier ...string) (err error) { + log.Info().Msg("start adb log recording") + err = ad.logcat.CatchLogcat() + if err != nil { + err = errors.Wrap(code.AndroidCaptureLogError, + fmt.Sprintf("start adb log recording failed: %v", err)) + return err + } + return nil +} + +func (ad *adbDriver) StopCaptureLog() (result interface{}, err error) { + log.Info().Msg("stop adb log recording") + err = ad.logcat.Stop() + if err != nil { + log.Error().Err(err).Msg("failed to get adb log recording") + err = errors.Wrap(code.AndroidCaptureLogError, + fmt.Sprintf("get adb log recording failed: %v", err)) + return "", err + } + content := ad.logcat.logBuffer.String() + return ConvertPoints(content), nil +} diff --git a/hrp/pkg/uixt/android_device.go b/hrp/pkg/uixt/android_device.go index f5380edf..0df9162d 100644 --- a/hrp/pkg/uixt/android_device.go +++ b/hrp/pkg/uixt/android_device.go @@ -35,6 +35,12 @@ func WithSerialNumber(serial string) AndroidDeviceOption { } } +func WithUIA2(uia2On bool) AndroidDeviceOption { + return func(device *AndroidDevice) { + device.UIA2 = uia2On + } +} + func WithUIA2IP(ip string) AndroidDeviceOption { return func(device *AndroidDevice) { device.UIA2IP = ip @@ -57,6 +63,9 @@ func GetAndroidDeviceOptions(dev *AndroidDevice) (deviceOptions []AndroidDeviceO if dev.SerialNumber != "" { deviceOptions = append(deviceOptions, WithSerialNumber(dev.SerialNumber)) } + if dev.UIA2 { + deviceOptions = append(deviceOptions, WithUIA2(true)) + } if dev.UIA2IP != "" { deviceOptions = append(deviceOptions, WithUIA2IP(dev.UIA2IP)) } @@ -119,6 +128,7 @@ type AndroidDevice struct { d gadb.Device logcat *AdbLogcat SerialNumber string `json:"serial,omitempty" yaml:"serial,omitempty"` + UIA2 bool `json:"uia2,omitempty" yaml:"uia2,omitempty"` // use uiautomator2 UIA2IP string `json:"uia2_ip,omitempty" yaml:"uia2_ip,omitempty"` // uiautomator2 server ip UIA2Port int `json:"uia2_port,omitempty" yaml:"uia2_port,omitempty"` // uiautomator2 server port LogOn bool `json:"log_on,omitempty" yaml:"log_on,omitempty"` @@ -129,7 +139,12 @@ func (dev *AndroidDevice) UUID() string { } func (dev *AndroidDevice) NewDriver(capabilities Capabilities) (driverExt *DriverExt, err error) { - driver, err := dev.NewUSBDriver(capabilities) + var driver WebDriver + if dev.UIA2 { + driver, err = dev.NewUSBDriver(capabilities) + } else { + driver, err = dev.NewAdbDriver() + } if err != nil { return nil, errors.Wrap(err, "failed to init UIA driver") } @@ -155,8 +170,7 @@ func (dev *AndroidDevice) NewDriver(capabilities Capabilities) (driverExt *Drive } // NewUSBDriver creates new client via USB connected device, this will also start a new session. -// TODO: replace uiaDriver with WebDriver -func (dev *AndroidDevice) NewUSBDriver(capabilities Capabilities) (driver *uiaDriver, err error) { +func (dev *AndroidDevice) NewUSBDriver(capabilities Capabilities) (driver WebDriver, err error) { var localPort int if localPort, err = getFreePort(); err != nil { return nil, errors.Wrap(code.AndroidDeviceUSBDriverError, @@ -168,27 +182,37 @@ func (dev *AndroidDevice) NewUSBDriver(capabilities Capabilities) (driver *uiaDr localPort, UIA2ServerPort, err)) } - rawURL := fmt.Sprintf("http://%s%d:6790/wd/hub", forwardToPrefix, localPort) - driver, err = NewUIADriver(capabilities, rawURL) + rawURL := fmt.Sprintf("http://%s%d:%d/wd/hub", + forwardToPrefix, localPort, UIA2ServerPort) + uiaDriver, err := NewUIADriver(capabilities, rawURL) if err != nil { _ = dev.d.ForwardKill(localPort) return nil, errors.Wrap(code.AndroidDeviceUSBDriverError, err.Error()) } - driver.adbClient = dev.d - driver.logcat = dev.logcat + uiaDriver.adbClient = dev.d + uiaDriver.logcat = dev.logcat - return driver, nil + return uiaDriver, nil } // NewHTTPDriver creates new remote HTTP client, this will also start a new session. -// TODO: replace uiaDriver with WebDriver -func (dev *AndroidDevice) NewHTTPDriver(capabilities Capabilities) (driver *uiaDriver, err error) { +func (dev *AndroidDevice) NewHTTPDriver(capabilities Capabilities) (driver WebDriver, err error) { rawURL := fmt.Sprintf("http://%s:%d/wd/hub", dev.UIA2IP, dev.UIA2Port) - if driver, err = NewUIADriver(capabilities, rawURL); err != nil { + uiaDriver, err := NewUIADriver(capabilities, rawURL) + if err != nil { return nil, err } - driver.adbClient = dev.d - return driver, nil + + uiaDriver.adbClient = dev.d + uiaDriver.logcat = dev.logcat + return uiaDriver, nil +} + +func (dev *AndroidDevice) NewAdbDriver() (driver WebDriver, err error) { + adbDriver := NewAdbDriver() + adbDriver.adbClient = dev.d + adbDriver.logcat = dev.logcat + return adbDriver, nil } func (dev *AndroidDevice) StartPerf() error { diff --git a/hrp/pkg/uixt/android_key.go b/hrp/pkg/uixt/android_key.go index 07f0d5b7..6304de9d 100644 --- a/hrp/pkg/uixt/android_key.go +++ b/hrp/pkg/uixt/android_key.go @@ -1,5 +1,7 @@ package uixt +// See https://developer.android.com/reference/android/view/KeyEvent + type KeyMeta int const ( diff --git a/hrp/pkg/uixt/android_test.go b/hrp/pkg/uixt/android_test.go index 1382ca42..44d8d3ac 100644 --- a/hrp/pkg/uixt/android_test.go +++ b/hrp/pkg/uixt/android_test.go @@ -49,7 +49,7 @@ func TestDriver_Quit(t *testing.T) { t.Fatal(err) } - if err = driver.Close(); err != nil { + if err = driver.DeleteSession(); err != nil { t.Fatal(err) } } @@ -335,17 +335,17 @@ func TestDeviceList(t *testing.T) { func TestDriver_AppLaunch(t *testing.T) { device, _ := NewAndroidDevice() - driver, err := device.NewUSBDriver(nil) + driver, err := device.NewDriver(nil) if err != nil { t.Fatal(err) } - err = driver.AppLaunch("com.android.settings") + err = driver.Driver.AppLaunch("com.android.settings") if err != nil { t.Fatal(err) } - raw, err := driver.Screenshot() + raw, err := driver.Driver.Screenshot() if err != nil { t.Fatal(err) } @@ -355,24 +355,24 @@ func TestDriver_AppLaunch(t *testing.T) { func TestDriver_KeepAlive(t *testing.T) { device, _ := NewAndroidDevice() - driver, err := device.NewUSBDriver(nil) + driver, err := device.NewDriver(nil) if err != nil { t.Fatal(err) } - err = driver.AppLaunch("com.android.settings") + err = driver.Driver.AppLaunch("com.android.settings") if err != nil { t.Fatal(err) } - _, err = driver.Screenshot() + _, err = driver.Driver.Screenshot() if err != nil { t.Fatal(err) } time.Sleep(60 * time.Second) - _, err = driver.Screenshot() + _, err = driver.Driver.Screenshot() if err != nil { t.Fatal(err) } @@ -380,12 +380,12 @@ func TestDriver_KeepAlive(t *testing.T) { func TestDriver_AppTerminate(t *testing.T) { device, _ := NewAndroidDevice() - driver, err := device.NewUSBDriver(nil) + driver, err := device.NewDriver(nil) if err != nil { t.Fatal(err) } - _, err = driver.AppTerminate("tv.danmaku.bili") + _, err = driver.Driver.AppTerminate("tv.danmaku.bili") if err != nil { t.Fatal(err) } diff --git a/hrp/pkg/uixt/android_driver.go b/hrp/pkg/uixt/android_uia2_driver.go similarity index 72% rename from hrp/pkg/uixt/android_driver.go rename to hrp/pkg/uixt/android_uia2_driver.go index 25c5db35..bf451577 100644 --- a/hrp/pkg/uixt/android_driver.go +++ b/hrp/pkg/uixt/android_uia2_driver.go @@ -9,36 +9,21 @@ import ( "net/url" "strconv" "strings" - "time" "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/httprunner/httprunner/v4/hrp/internal/code" - "github.com/httprunner/httprunner/v4/hrp/pkg/gadb" -) - -// See https://developer.android.com/reference/android/view/KeyEvent -const ( - KEYCODE_BACK string = "4" - KEYCODE_CAMERA string = "27" - KEYCODE_ALT_LEFT string = "57" - KEYCODE_ALT_RIGHT string = "58" - KEYCODE_MENU string = "82" - KEYCODE_BREAK string = "121" - KEYCODE_ALL_APPS string = "284" ) var errDriverNotImplemented = errors.New("driver method not implemented") type uiaDriver struct { - Driver - - adbClient gadb.Device - logcat *AdbLogcat + adbDriver } func NewUIADriver(capabilities Capabilities, urlPrefix string) (driver *uiaDriver, err error) { + log.Info().Msg("init uiautomator2 driver") if capabilities == nil { capabilities = NewCapabilities() } @@ -98,17 +83,6 @@ func (bs BatteryStatus) String() string { } } -func (ud *uiaDriver) Close() (err error) { - if ud.sessionId == "" { - return nil - } - if _, err = ud.httpDELETE("/session", ud.sessionId); err == nil { - ud.sessionId = "" - } - - return err -} - func (ud *uiaDriver) NewSession(capabilities Capabilities) (sessionInfo SessionInfo, err error) { // register(postHandler, new NewSession("/wd/hub/session")) var rawResp rawResponse @@ -126,8 +100,14 @@ func (ud *uiaDriver) NewSession(capabilities Capabilities) (sessionInfo SessionI } func (ud *uiaDriver) DeleteSession() (err error) { - // TODO - return errDriverNotImplemented + if ud.sessionId == "" { + return nil + } + if _, err = ud.httpDELETE("/session", ud.sessionId); err == nil { + ud.sessionId = "" + } + + return err } func (ud *uiaDriver) Status() (deviceStatus DeviceStatus, err error) { @@ -185,18 +165,6 @@ func (ud *uiaDriver) BatteryInfo() (batteryInfo BatteryInfo, err error) { } func (ud *uiaDriver) WindowSize() (size Size, err error) { - // adb shell wm size - resp, err := ud.adbClient.RunShellCommand("wm", "size") - if err == nil { - // Physical size: 1080x2340 - s := strings.Trim(strings.Split(resp, ": ")[1], "\n") - ss := strings.Split(s, "x") - width, _ := strconv.Atoi(ss[0]) - height, _ := strconv.Atoi(ss[1]) - size = Size{Width: width, Height: height} - return - } - // register(getHandler, new GetDeviceSize("/wd/hub/session/:sessionId/window/:windowHandle/size")) var rawResp rawResponse if rawResp, err = ud.httpGET("/session", ud.sessionId, "window/:windowHandle/size"); err != nil { @@ -221,84 +189,16 @@ func (ud *uiaDriver) Scale() (scale float64, err error) { // PressBack simulates a short press on the BACK button. func (ud *uiaDriver) PressBack(options ...DataOption) (err error) { - // adb shell input keyevent 4 - _, err = ud.adbClient.RunShellCommand("input", "keyevent", KEYCODE_BACK) - if err == nil { - return nil - } // register(postHandler, new PressBack("/wd/hub/session/:sessionId/back")) _, err = ud.httpPOST(nil, "/session", ud.sessionId, "back") return } -func (ud *uiaDriver) StartCamera() (err error) { - if _, err = ud.adbClient.RunShellCommand("rm", "-r", "/sdcard/DCIM/Camera"); err != nil { - return err - } - time.Sleep(5 * time.Second) - var version string - if version, err = ud.adbClient.RunShellCommand("getprop", "ro.build.version.release"); err != nil { - return err - } - if version == "11" || version == "12" { - if _, err = ud.adbClient.RunShellCommand("am", "start", "-a", "android.media.action.STILL_IMAGE_CAMERA"); err != nil { - return err - } - time.Sleep(5 * time.Second) - if _, err = ud.adbClient.RunShellCommand("input", "swipe", "750", "1000", "250", "1000"); err != nil { - return err - } - time.Sleep(5 * time.Second) - if _, err = ud.adbClient.RunShellCommand("input", "keyevent", KEYCODE_CAMERA); err != nil { - return err - } - return - } else { - if _, err = ud.adbClient.RunShellCommand("am", "start", "-a", "android.media.action.VIDEO_CAPTURE"); err != nil { - return err - } - time.Sleep(5 * time.Second) - if _, err = ud.adbClient.RunShellCommand("input", "keyevent", KEYCODE_CAMERA); err != nil { - return err - } - return - } -} - -func (ud *uiaDriver) StopCamera() (err error) { - err = ud.PressBack() - if err != nil { - return err - } - err = ud.Homescreen() - if err != nil { - return err - } - - // kill samsung shell command - if _, err = ud.adbClient.RunShellCommand("am", "force-stop", "com.sec.android.app.camera"); err != nil { - return err - } - - // kill other camera (huawei mi) - if _, err = ud.adbClient.RunShellCommand("am", "force-stop", "com.android.camera2"); err != nil { - return err - } - return -} - func (ud *uiaDriver) Homescreen() (err error) { return ud.PressKeyCode(KCHome, KMEmpty) } func (ud *uiaDriver) PressKeyCode(keyCode KeyCode, metaState KeyMeta, flags ...KeyFlag) (err error) { - // adb shell input keyevent - _, err = ud.adbClient.RunShellCommand( - "input", "keyevent", fmt.Sprintf("%d", keyCode)) - if err == nil { - return nil - } - // register(postHandler, new PressKeyCodeAsync("/wd/hub/session/:sessionId/appium/device/press_keycode")) data := map[string]interface{}{ "keycode": keyCode, @@ -313,40 +213,11 @@ func (ud *uiaDriver) PressKeyCode(keyCode KeyCode, metaState KeyMeta, flags ...K return } -func (ud *uiaDriver) AppLaunch(bundleId string) (err error) { - // 不指定 Activity 名称启动(启动主 Activity) - // adb shell monkey -p -c android.intent.category.LAUNCHER 1 - sOutput, err := ud.adbClient.RunShellCommand( - "monkey", "-p", bundleId, "-c", "android.intent.category.LAUNCHER", "1", - ) - if err != nil { - return err - } - if strings.Contains(sOutput, "monkey aborted") { - return fmt.Errorf("app launch: %s", strings.TrimSpace(sOutput)) - } - return nil -} - -func (ud *uiaDriver) AppTerminate(bundleId string) (successful bool, err error) { - // 强制停止应用,停止 相关的进程 - // adb shell am force-stop - _, err = ud.adbClient.RunShellCommand("am", "force-stop", bundleId) - return err == nil, err -} - func (ud *uiaDriver) Tap(x, y int, options ...DataOption) error { return ud.TapFloat(float64(x), float64(y), options...) } func (ud *uiaDriver) TapFloat(x, y float64, options ...DataOption) (err error) { - // adb shell input tap x y - _, err = ud.adbClient.RunShellCommand( - "input", "tap", fmt.Sprintf("%.1f", x), fmt.Sprintf("%.1f", y)) - if err == nil { - return nil - } - // register(postHandler, new Tap("/wd/hub/session/:sessionId/appium/tap")) data := map[string]interface{}{ "x": x, @@ -421,16 +292,6 @@ func (ud *uiaDriver) Swipe(fromX, fromY, toX, toY int, options ...DataOption) er } func (ud *uiaDriver) SwipeFloat(fromX, fromY, toX, toY float64, options ...DataOption) error { - // adb shell input swipe fromX fromY toX toY - _, err := ud.adbClient.RunShellCommand( - "input", "swipe", - fmt.Sprintf("%.1f", fromX), fmt.Sprintf("%.1f", fromY), - fmt.Sprintf("%.1f", toX), fmt.Sprintf("%.1f", toY), - ) - if err == nil { - return nil - } - // register(postHandler, new Swipe("/wd/hub/session/:sessionId/touch/perform")) data := map[string]interface{}{ "startX": fromX, @@ -442,7 +303,7 @@ func (ud *uiaDriver) SwipeFloat(fromX, fromY, toX, toY float64, options ...DataO // new data options in post data for extra uiautomator configurations newData := NewData(data, options...) - _, err = ud.httpPOST(newData, "/session", ud.sessionId, "touch/perform") + _, err := ud.httpPOST(newData, "/session", ud.sessionId, "touch/perform") return err } @@ -623,53 +484,3 @@ func (ud *uiaDriver) IsHealthy() (healthy bool, err error) { // TODO return healthy, errDriverNotImplemented } - -func (ud *uiaDriver) WaitWithTimeoutAndInterval(condition Condition, timeout, interval time.Duration) error { - startTime := time.Now() - for { - done, err := condition(ud) - if err != nil { - return err - } - if done { - return nil - } - - if elapsed := time.Since(startTime); elapsed > timeout { - return fmt.Errorf("timeout after %v", elapsed) - } - time.Sleep(interval) - } -} - -func (ud *uiaDriver) WaitWithTimeout(condition Condition, timeout time.Duration) error { - return ud.WaitWithTimeoutAndInterval(condition, timeout, DefaultWaitInterval) -} - -func (ud *uiaDriver) Wait(condition Condition) error { - return ud.WaitWithTimeoutAndInterval(condition, DefaultWaitTimeout, DefaultWaitInterval) -} - -func (ud *uiaDriver) StartCaptureLog(identifier ...string) (err error) { - log.Info().Msg("start adb log recording") - err = ud.logcat.CatchLogcat() - if err != nil { - err = errors.Wrap(code.AndroidCaptureLogError, - fmt.Sprintf("start adb log recording failed: %v", err)) - return err - } - return nil -} - -func (ud *uiaDriver) StopCaptureLog() (result interface{}, err error) { - log.Info().Msg("stop adb log recording") - err = ud.logcat.Stop() - if err != nil { - log.Error().Err(err).Msg("failed to get adb log recording") - err = errors.Wrap(code.AndroidCaptureLogError, - fmt.Sprintf("get adb log recording failed: %v", err)) - return "", err - } - content := ud.logcat.logBuffer.String() - return ConvertPoints(content), nil -} diff --git a/hrp/pkg/uixt/interface.go b/hrp/pkg/uixt/interface.go index 3b2005fb..865ed9fb 100644 --- a/hrp/pkg/uixt/interface.go +++ b/hrp/pkg/uixt/interface.go @@ -695,9 +695,6 @@ type WebDriver interface { IsHealthy() (bool, error) - // Close inner connections properly - Close() error - // triggers the log capture and returns the log entries StartCaptureLog(identifier ...string) (err error) StopCaptureLog() (result interface{}, err error) diff --git a/hrp/pkg/uixt/ios_driver.go b/hrp/pkg/uixt/ios_driver.go index 16aa884c..53339d8c 100644 --- a/hrp/pkg/uixt/ios_driver.go +++ b/hrp/pkg/uixt/ios_driver.go @@ -35,20 +35,6 @@ func (wd *wdaDriver) GetMjpegClient() *http.Client { return wd.mjpegClient } -func (wd *wdaDriver) Close() error { - if wd.defaultConn != nil { - wd.defaultConn.Close() - } - if wd.mjpegUSBConn != nil { - wd.mjpegUSBConn.Close() - } - - if wd.mjpegClient != nil { - wd.mjpegClient.CloseIdleConnections() - } - return wd.mjpegHTTPConn.Close() -} - func (wd *wdaDriver) NewSession(capabilities Capabilities) (sessionInfo SessionInfo, err error) { // [[FBRoute POST:@"/session"].withoutSession respondWithTarget:self action:@selector(handleCreateSession:)] data := make(map[string]interface{}) @@ -70,6 +56,20 @@ func (wd *wdaDriver) NewSession(capabilities Capabilities) (sessionInfo SessionI } func (wd *wdaDriver) DeleteSession() (err error) { + if wd.defaultConn != nil { + wd.defaultConn.Close() + } + if wd.mjpegUSBConn != nil { + wd.mjpegUSBConn.Close() + } + + if wd.mjpegClient != nil { + wd.mjpegClient.CloseIdleConnections() + } + if wd.mjpegHTTPConn != nil { + wd.mjpegHTTPConn.Close() + } + // [[FBRoute DELETE:@""] respondWithTarget:self action:@selector(handleDeleteSession:)] _, err = wd.httpDELETE("/session", wd.sessionId) return diff --git a/hrp/pkg/uixt/ocr_vedem_test.go b/hrp/pkg/uixt/ocr_vedem_test.go index f3fe1d32..fa409fc9 100644 --- a/hrp/pkg/uixt/ocr_vedem_test.go +++ b/hrp/pkg/uixt/ocr_vedem_test.go @@ -24,12 +24,12 @@ func checkOCR(buff *bytes.Buffer) error { func TestOCRWithScreenshot(t *testing.T) { device, _ := NewAndroidDevice() - driver, err := device.NewUSBDriver(nil) + driver, err := device.NewDriver(nil) if err != nil { t.Fatal(err) } - raw, err := driver.Screenshot() + raw, err := driver.Driver.Screenshot() if err != nil { t.Fatal(err) }