From c670a4cef9fe57fdd1ed345726a87af98d9fc8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Wed, 12 Jun 2024 11:36:30 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=E5=85=BC=E5=AE=B9iproxy=202.1.0=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=AD=A5=E9=AA=A4=E5=BC=B9=E7=AA=97=E5=BF=BD?= =?UTF-8?q?=E7=95=A5=E5=92=8C=E5=85=A8=E5=B1=80=E5=BC=B9=E7=AA=97=E5=BF=BD?= =?UTF-8?q?=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hrp/pkg/uixt/android_device.go | 1 + hrp/pkg/uixt/ios_device.go | 3 ++- hrp/runner.go | 10 ++++++++++ hrp/step.go | 1 + hrp/step_mobile_ui.go | 6 ++++-- 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/hrp/pkg/uixt/android_device.go b/hrp/pkg/uixt/android_device.go index ffbfb4c2..64fb030a 100644 --- a/hrp/pkg/uixt/android_device.go +++ b/hrp/pkg/uixt/android_device.go @@ -154,6 +154,7 @@ type AndroidDevice struct { 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"` + IgnorePopup bool `json:"ignore_popup,omitempty" yaml:"ignore_popup,omitempty"` } func (dev *AndroidDevice) UUID() string { diff --git a/hrp/pkg/uixt/ios_device.go b/hrp/pkg/uixt/ios_device.go index fea9f0f2..8057f8a1 100644 --- a/hrp/pkg/uixt/ios_device.go +++ b/hrp/pkg/uixt/ios_device.go @@ -276,6 +276,7 @@ type IOSDevice struct { MjpegPort int `json:"mjpeg_port,omitempty" yaml:"mjpeg_port,omitempty"` // WDA remote MJPEG port LogOn bool `json:"log_on,omitempty" yaml:"log_on,omitempty"` XCTestBundleID string `json:"xctest_bundle_id,omitempty" yaml:"xctest_bundle_id,omitempty"` + IgnorePopup bool `json:"ignore_popup,omitempty" yaml:"ignore_popup,omitempty"` // switch to iOS springboard before init WDA session ResetHomeOnStartup bool `json:"reset_home_on_startup,omitempty" yaml:"reset_home_on_startup,omitempty"` @@ -631,7 +632,7 @@ func (dev *IOSDevice) NewHTTPDriver(capabilities Capabilities) (driver WebDriver wd := new(wdaDriver) wd.client = http.DefaultClient - host := "127.0.0.1" + host := "localhost" if wd.urlPrefix, err = url.Parse(fmt.Sprintf("http://%s:%d", host, localPort)); err != nil { return nil, errors.Wrap(code.IOSDeviceHTTPDriverError, err.Error()) } diff --git a/hrp/runner.go b/hrp/runner.go index 986dc931..86f32885 100644 --- a/hrp/runner.go +++ b/hrp/runner.go @@ -711,6 +711,16 @@ func (r *SessionRunner) GetSummary() (*TestCaseSummary, error) { return caseSummary, nil } +func (r *SessionRunner) IgnorePopup() bool { + if r.caseRunner.testCase.Config.Android != nil { + return r.caseRunner.testCase.Config.Android[0].IgnorePopup + } + if r.caseRunner.testCase.Config.IOS != nil { + return r.caseRunner.testCase.Config.IOS[0].IgnorePopup + } + return false +} + // updateSummary updates summary of StepResult. func (r *SessionRunner) updateSummary(stepResult *StepResult) { switch stepResult.StepType { diff --git a/hrp/step.go b/hrp/step.go index 04a21211..083b0698 100644 --- a/hrp/step.go +++ b/hrp/step.go @@ -48,6 +48,7 @@ type TStep struct { Validators []interface{} `json:"validate,omitempty" yaml:"validate,omitempty"` Export []string `json:"export,omitempty" yaml:"export,omitempty"` Loops int `json:"loops,omitempty" yaml:"loops,omitempty"` + IgnorePopup bool `json:"ignore_popup,omitempty" yaml:"ignore_popup,omitempty"` } // IStep represents interface for all types for teststeps, includes: diff --git a/hrp/step_mobile_ui.go b/hrp/step_mobile_ui.go index 12b49ee7..e0babf2c 100644 --- a/hrp/step_mobile_ui.go +++ b/hrp/step_mobile_ui.go @@ -647,8 +647,10 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err } // automatic handling of pop-up windows on each step finished - if err2 := uiDriver.ClosePopups(); err2 != nil { - log.Error().Err(err2).Str("step", step.Name).Msg("auto handle popup failed") + if !step.IgnorePopup && !s.IgnorePopup() { + if err2 := uiDriver.ClosePopups(); err2 != nil { + log.Error().Err(err2).Str("step", step.Name).Msg("auto handle popup failed") + } } // save attachments From c5712b1a6682b6cedb80d897e62ade5764b17ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Wed, 12 Jun 2024 11:37:29 +0800 Subject: [PATCH 2/6] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dduration=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E4=B8=8D=E5=87=86=E7=A1=AE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hrp/internal/version/VERSION | 2 +- hrp/pkg/uixt/android_test.go | 21 ++++++++++----------- hrp/pkg/uixt/android_uia2_driver.go | 12 +++++++++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/hrp/internal/version/VERSION b/hrp/internal/version/VERSION index dfe33e04..baabcd7d 100644 --- a/hrp/internal/version/VERSION +++ b/hrp/internal/version/VERSION @@ -1 +1 @@ -v4.5.1 \ No newline at end of file +v4.5.6 \ No newline at end of file diff --git a/hrp/pkg/uixt/android_test.go b/hrp/pkg/uixt/android_test.go index 3c20f741..591893d0 100644 --- a/hrp/pkg/uixt/android_test.go +++ b/hrp/pkg/uixt/android_test.go @@ -216,17 +216,8 @@ func TestDriver_Tap(t *testing.T) { } func TestDriver_Swipe(t *testing.T) { - driver, err := NewUIADriver(nil, uiaServerURL) - if err != nil { - t.Fatal(err) - } - - err = driver.Swipe(400, 1000, 400, 500, WithPressDuration(2000)) - if err != nil { - t.Fatal(err) - } - - err = driver.SwipeFloat(400, 555.5, 400, 1255.5) + setupAndroid(t) + err := driverExt.Driver.Swipe(400, 1000, 400, 500, WithPressDuration(0.5)) if err != nil { t.Fatal(err) } @@ -307,6 +298,14 @@ func TestDriver_SetRotation(t *testing.T) { } } +func TestDriver_GetOrientation(t *testing.T) { + setupAndroid(t) + _, _ = driverExt.Driver.AppTerminate("com.quark.browser") + _ = driverExt.Driver.AppLaunch("com.quark.browser") + time.Sleep(2 * time.Second) + _ = driverExt.Driver.Homescreen() +} + func TestUiSelectorHelper_NewUiSelectorHelper(t *testing.T) { uiSelector := NewUiSelectorHelper().Text("a").String() if uiSelector != `new UiSelector().text("a");` { diff --git a/hrp/pkg/uixt/android_uia2_driver.go b/hrp/pkg/uixt/android_uia2_driver.go index 6606cd78..8e962d29 100644 --- a/hrp/pkg/uixt/android_uia2_driver.go +++ b/hrp/pkg/uixt/android_uia2_driver.go @@ -29,6 +29,7 @@ func NewUIADriver(capabilities Capabilities, urlPrefix string) (driver *uiaDrive log.Info().Msg("init uiautomator2 driver") if capabilities == nil { capabilities = NewCapabilities() + capabilities.WithWaitForIdleTimeout(0) } driver = new(uiaDriver) if driver.urlPrefix, err = url.Parse(urlPrefix); err != nil { @@ -141,7 +142,12 @@ func (ud *uiaDriver) httpDELETE(pathElem ...string) (rawResp rawResponse, err er func (ud *uiaDriver) NewSession(capabilities Capabilities) (sessionInfo SessionInfo, err error) { // register(postHandler, new NewSession("/wd/hub/session")) var rawResp rawResponse - data := map[string]interface{}{"capabilities": capabilities} + data := make(map[string]interface{}) + if len(capabilities) == 0 { + data["capabilities"] = make(map[string]interface{}) + } else { + data["capabilities"] = map[string]interface{}{"alwaysMatch": capabilities} + } if rawResp, err = ud.Driver.httpPOST(data, "/session"); err != nil { return SessionInfo{SessionId: ""}, err } @@ -293,7 +299,7 @@ func (ud *uiaDriver) TapFloat(x, y float64, options ...ActionOption) (err error) duration := 100.0 if actionOptions.PressDuration > 0 { - duration = actionOptions.PressDuration + duration = actionOptions.PressDuration * 1000 } data := map[string]interface{}{ "actions": []interface{}{ @@ -399,7 +405,7 @@ func (ud *uiaDriver) SwipeFloat(fromX, fromY, toX, toY float64, options ...Actio duration := 200.0 if actionOptions.PressDuration > 0 { - duration = actionOptions.PressDuration + duration = actionOptions.PressDuration * 1000 } data := map[string]interface{}{ "actions": []interface{}{ From 30d4dcbaa2230cdef885d5d0aea44045df72f185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Thu, 13 Jun 2024 15:09:30 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=B2=98=E8=B4=B4=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hrp/internal/version/VERSION | 2 +- hrp/pkg/uixt/action.go | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hrp/internal/version/VERSION b/hrp/internal/version/VERSION index baabcd7d..f4d009b8 100644 --- a/hrp/internal/version/VERSION +++ b/hrp/internal/version/VERSION @@ -1 +1 @@ -v4.5.6 \ No newline at end of file +v4.5.7 \ No newline at end of file diff --git a/hrp/pkg/uixt/action.go b/hrp/pkg/uixt/action.go index 1a555f91..3ec9a3cd 100644 --- a/hrp/pkg/uixt/action.go +++ b/hrp/pkg/uixt/action.go @@ -26,6 +26,8 @@ const ( ACTION_SleepRandom ActionMethod = "sleep_random" ACTION_StartCamera ActionMethod = "camera_start" // alias for app_launch camera ACTION_StopCamera ActionMethod = "camera_stop" // alias for app_terminate camera + ACTION_SetClipboard ActionMethod = "set_clipboard" + ACTION_GetClipboard ActionMethod = "get_clipboard" // UI validation // selectors @@ -594,6 +596,15 @@ func (dExt *DriverExt) DoAction(action MobileAction) (err error) { return nil } return fmt.Errorf("app_terminate params should be bundleId(string), got %v", action.Params) + case ACTION_SetClipboard: + if text, ok := action.Params.(string); ok { + err := dExt.Driver.SetPasteboard(PasteboardTypePlaintext, text) + if err != nil { + return errors.Wrap(err, "failed to set clipboard") + } + return nil + } + return fmt.Errorf("set_clioboard params should be text(string), got %v", action.Params) case ACTION_Home: return dExt.Driver.Homescreen() case ACTION_TapXY: From 3094c3369bc6917620b389178bbc96357e1cb75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Fri, 21 Jun 2024 11:57:36 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Eoppo=E6=89=8B?= =?UTF-8?q?=E5=8A=A8=E5=90=AF=E5=8A=A8=E4=B8=80=E6=AC=A1settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hrp/pkg/uixt/android_device.go | 15 +++++++++++++++ hrp/pkg/uixt/interface.go | 1 + hrp/pkg/uixt/ios_device.go | 4 ++++ hrp/runner.go | 15 ++++++++------- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/hrp/pkg/uixt/android_device.go b/hrp/pkg/uixt/android_device.go index 64fb030a..4d1ca432 100644 --- a/hrp/pkg/uixt/android_device.go +++ b/hrp/pkg/uixt/android_device.go @@ -13,6 +13,7 @@ import ( "github.com/rs/zerolog/log" "github.com/httprunner/httprunner/v4/hrp/internal/code" + "github.com/httprunner/httprunner/v4/hrp/internal/env" "github.com/httprunner/httprunner/v4/hrp/internal/json" "github.com/httprunner/httprunner/v4/hrp/pkg/gadb" ) @@ -157,6 +158,20 @@ type AndroidDevice struct { IgnorePopup bool `json:"ignore_popup,omitempty" yaml:"ignore_popup,omitempty"` } +func (dev *AndroidDevice) Init() error { + brand, err := dev.d.Brand() + if err != nil { + return fmt.Errorf("failed to init android device. brand is null %v", err) + } + if strings.ToLower(brand) == "huawei" { + // 启动一次io.appium.settings。防止oppo设备上切换输入法失败 + myexec.RunCommand("adb", "-s", dev.SerialNumber, "shell", + "monkey", "-p", "io.appium.settings", "-c", "android.intent.category.LAUNCHER", "1") + } + myexec.RunCommand("adb", "-s", dev.SerialNumber, "shell", "rm", "-r", env.DeviceActionLogFilePath) + return nil +} + func (dev *AndroidDevice) UUID() string { return dev.SerialNumber } diff --git a/hrp/pkg/uixt/interface.go b/hrp/pkg/uixt/interface.go index 3fccf5ba..5a93b5bf 100644 --- a/hrp/pkg/uixt/interface.go +++ b/hrp/pkg/uixt/interface.go @@ -468,6 +468,7 @@ func WithDriverPlugin(plugin funplugin.IPlugin) DriverOption { // current implemeted device: IOSDevice, AndroidDevice type Device interface { + Init() error // init android device UUID() string // ios udid or android serial LogEnabled() bool NewDriver(...DriverOption) (driverExt *DriverExt, err error) diff --git a/hrp/pkg/uixt/ios_device.go b/hrp/pkg/uixt/ios_device.go index 8057f8a1..6a0f1fbb 100644 --- a/hrp/pkg/uixt/ios_device.go +++ b/hrp/pkg/uixt/ios_device.go @@ -295,6 +295,10 @@ type IOSDevice struct { pcapFile string // saved pcap file path } +func (dev *IOSDevice) Init() error { + return nil +} + func (dev *IOSDevice) UUID() string { return dev.UDID } diff --git a/hrp/runner.go b/hrp/runner.go index 86f32885..3fe6d4bb 100644 --- a/hrp/runner.go +++ b/hrp/runner.go @@ -18,7 +18,6 @@ import ( "github.com/gorilla/websocket" "github.com/httprunner/funplugin" - "github.com/httprunner/funplugin/myexec" "github.com/jinzhu/copier" "github.com/pkg/errors" "github.com/rs/zerolog/log" @@ -26,7 +25,6 @@ import ( "github.com/httprunner/httprunner/v4/hrp/internal/builtin" "github.com/httprunner/httprunner/v4/hrp/internal/code" - "github.com/httprunner/httprunner/v4/hrp/internal/env" "github.com/httprunner/httprunner/v4/hrp/internal/sdk" "github.com/httprunner/httprunner/v4/hrp/internal/version" "github.com/httprunner/httprunner/v4/hrp/pkg/uixt" @@ -437,11 +435,15 @@ func (r *CaseRunner) parseConfig() error { if err != nil { return errors.Wrap(err, "init iOS device failed") } + if err := device.Init(); err != nil { + return err + } client, err := device.NewDriver(uixt.WithDriverPlugin(r.parser.plugin)) if err != nil { return errors.Wrap(err, "init iOS WDA client failed") } r.uiClients[device.UDID] = client + } for _, androidDeviceConfig := range r.parsedConfig.Android { if androidDeviceConfig.SerialNumber != "" { @@ -456,11 +458,15 @@ func (r *CaseRunner) parseConfig() error { if err != nil { return errors.Wrap(err, "init Android device failed") } + if err := device.Init(); err != nil { + return err + } client, err := device.NewDriver(uixt.WithDriverPlugin(r.parser.plugin)) if err != nil { return errors.Wrap(err, "init Android client failed") } r.uiClients[device.SerialNumber] = client + } return nil @@ -525,11 +531,6 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error { config := r.caseRunner.testCase.Config log.Info().Str("testcase", config.Name).Msg("run testcase start") - // 安卓系统删除打点日志文件 - if r.caseRunner.testCase.Config.Android != nil { - myexec.RunCommand("adb", "-s", r.caseRunner.testCase.Config.Android[0].SerialNumber, "shell", "rm", "-r", env.DeviceActionLogFilePath) - } - // update config variables with given variables r.InitWithParameters(givenVars) From 02a878322325cb5dbdfba43744d5eab338e742d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Fri, 21 Jun 2024 15:07:35 +0800 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Eoppo=E6=89=8B?= =?UTF-8?q?=E5=8A=A8=E5=90=AF=E5=8A=A8=E4=B8=80=E6=AC=A1settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hrp/pkg/uixt/android_device.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrp/pkg/uixt/android_device.go b/hrp/pkg/uixt/android_device.go index 4d1ca432..c754c52a 100644 --- a/hrp/pkg/uixt/android_device.go +++ b/hrp/pkg/uixt/android_device.go @@ -163,7 +163,7 @@ func (dev *AndroidDevice) Init() error { if err != nil { return fmt.Errorf("failed to init android device. brand is null %v", err) } - if strings.ToLower(brand) == "huawei" { + if strings.ToLower(brand) == "oppo" { // 启动一次io.appium.settings。防止oppo设备上切换输入法失败 myexec.RunCommand("adb", "-s", dev.SerialNumber, "shell", "monkey", "-p", "io.appium.settings", "-c", "android.intent.category.LAUNCHER", "1") From d08406635404b45315d1450a094377f3a3f8cda3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Mon, 24 Jun 2024 16:42:26 +0800 Subject: [PATCH 6/6] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=89=8D=E5=8F=B0=E5=BA=94=E7=94=A8=EF=BC=8Coppo?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=B3=95=E5=88=87=E6=8D=A2=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=80=A7=E9=80=82=E9=85=8D=E3=80=82=E6=96=B0=E5=A2=9E=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E8=BE=93=E5=85=A5=E6=B3=95=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hrp/internal/version/VERSION | 2 +- hrp/pkg/uixt/action.go | 9 +++++ hrp/pkg/uixt/android_adb_driver.go | 62 +++++++++++++++++++++++++++++- hrp/pkg/uixt/android_device.go | 11 +----- hrp/pkg/uixt/interface.go | 2 + hrp/pkg/uixt/ios_driver.go | 4 ++ 6 files changed, 78 insertions(+), 12 deletions(-) diff --git a/hrp/internal/version/VERSION b/hrp/internal/version/VERSION index f4d009b8..488312ea 100644 --- a/hrp/internal/version/VERSION +++ b/hrp/internal/version/VERSION @@ -1 +1 @@ -v4.5.7 \ No newline at end of file +v4.5.8 \ No newline at end of file diff --git a/hrp/pkg/uixt/action.go b/hrp/pkg/uixt/action.go index 3ec9a3cd..12541954 100644 --- a/hrp/pkg/uixt/action.go +++ b/hrp/pkg/uixt/action.go @@ -28,6 +28,7 @@ const ( ACTION_StopCamera ActionMethod = "camera_stop" // alias for app_terminate camera ACTION_SetClipboard ActionMethod = "set_clipboard" ACTION_GetClipboard ActionMethod = "get_clipboard" + ACTION_SetIme ActionMethod = "set_ime" // UI validation // selectors @@ -607,6 +608,14 @@ func (dExt *DriverExt) DoAction(action MobileAction) (err error) { return fmt.Errorf("set_clioboard params should be text(string), got %v", action.Params) case ACTION_Home: return dExt.Driver.Homescreen() + case ACTION_SetIme: + if ime, ok := action.Params.(string); ok { + err = dExt.Driver.SetIme(ime) + if err != nil { + return errors.Wrap(err, "failed to set ime") + } + return nil + } case ACTION_TapXY: if location, ok := action.Params.([]interface{}); ok { // relative x,y of window size: [0.5, 0.5] diff --git a/hrp/pkg/uixt/android_adb_driver.go b/hrp/pkg/uixt/android_adb_driver.go index c642a245..43d756eb 100644 --- a/hrp/pkg/uixt/android_adb_driver.go +++ b/hrp/pkg/uixt/android_adb_driver.go @@ -421,6 +421,14 @@ func (ad *adbDriver) IsUnicodeIMEInstalled() bool { return strings.Contains(output, UnicodeImePackageName) } +func (ad *adbDriver) ListIme() []string { + output, err := ad.adbClient.RunShellCommand("ime", "list", "-s") + if err != nil { + return []string{} + } + return strings.Split(output, "\n") +} + func (ad *adbDriver) SendKeysByAdbKeyBoard(text string) (err error) { defer func() { // Reset to default, don't care which keyboard was chosen before switch: @@ -715,11 +723,61 @@ func (ad *adbDriver) GetForegroundApp() (app AppInfo, err error) { return AppInfo{}, errors.Wrap(code.MobileUIAssertForegroundAppError, "get foreground app failed") } -func (ad *adbDriver) SetIme(ime string) error { - _, err := ad.adbClient.RunShellCommand("ime", "set", ime) +func (ad *adbDriver) GetFocusedPackage() (packageName string, err error) { + res, err := ad.adbClient.RunShellCommand("dumpsys", "window", "windows", "|", "grep", "-E", "'mCurrentFocus|mFocusedApp'") + if err != nil { + return "", err + } + match := regexp.MustCompile("mCurrentFocus.+\\s([^\\s/}]+)/[^\\s/}]+(\\.[^\\s/}]+)}").FindStringSubmatch(res) + if len(match) > 1 { + packageName = match[1] + return + } + match = regexp.MustCompile("mFocusedApp.+Record\\{.*\\s([^\\s/}]+)/([^\\s/}]+)(\\s[^\\s/}]+)*}").FindStringSubmatch(res) + if len(match) > 1 { + packageName = match[1] + return + } + log.Error().Str("dumpsys", res).Msg("failed to get focused package") + return "", fmt.Errorf("failed to get focused package") +} + +func (ad *adbDriver) SetIme(imeRegx string) error { + imeList := ad.ListIme() + ime := "" + for _, imeName := range imeList { + if regexp.MustCompile(imeRegx).MatchString(imeName) { + ime = imeName + break + } + } + if ime == "" { + return fmt.Errorf("failed to set ime by %s, ime list: %v", imeRegx, imeList) + } + brand, _ := ad.adbClient.Brand() + packageName := strings.Split(ime, "/")[0] + res, err := ad.adbClient.RunShellCommand("ime", "set", ime) + log.Info().Str("funcName", "SetIme").Interface("ime", ime). + Interface("output", res).Msg("set ime") if err != nil { return err } + + if strings.ToLower(brand) == "oppo" { + pid, _ := ad.adbClient.RunShellCommand("pidof", packageName) + if strings.TrimSpace(pid) == "" { + focusedPackage, err := ad.GetFocusedPackage() + _ = ad.AppLaunch(packageName) + if err == nil && packageName != UnicodeImePackageName { + time.Sleep(10 * time.Second) + currentPackage, err := ad.GetFocusedPackage() + log.Info().Str("beforeFocusedPackage", focusedPackage).Str("afterFocusedPackage", currentPackage).Msg("") + if err == nil && currentPackage != focusedPackage { + _ = ad.PressKeyCode(KCBack, KMEmpty) + } + } + } + } // even if the shell command has returned, // as there might be a situation where the input method has not been completely switched yet // Listen to the following message. diff --git a/hrp/pkg/uixt/android_device.go b/hrp/pkg/uixt/android_device.go index c754c52a..20e8ffa0 100644 --- a/hrp/pkg/uixt/android_device.go +++ b/hrp/pkg/uixt/android_device.go @@ -159,15 +159,8 @@ type AndroidDevice struct { } func (dev *AndroidDevice) Init() error { - brand, err := dev.d.Brand() - if err != nil { - return fmt.Errorf("failed to init android device. brand is null %v", err) - } - if strings.ToLower(brand) == "oppo" { - // 启动一次io.appium.settings。防止oppo设备上切换输入法失败 - myexec.RunCommand("adb", "-s", dev.SerialNumber, "shell", - "monkey", "-p", "io.appium.settings", "-c", "android.intent.category.LAUNCHER", "1") - } + myexec.RunCommand("adb", "-s", dev.SerialNumber, "shell", + "ime", "enable", "io.appium.settings/.UnicodeIME") myexec.RunCommand("adb", "-s", dev.SerialNumber, "shell", "rm", "-r", env.DeviceActionLogFilePath) return nil } diff --git a/hrp/pkg/uixt/interface.go b/hrp/pkg/uixt/interface.go index 5a93b5bf..1df9dbca 100644 --- a/hrp/pkg/uixt/interface.go +++ b/hrp/pkg/uixt/interface.go @@ -572,6 +572,8 @@ type WebDriver interface { // It worked when `WDA` was foreground. https://github.com/appium/WebDriverAgent/issues/330 GetPasteboard(contentType PasteboardType) (raw *bytes.Buffer, err error) + SetIme(ime string) error + // SendKeys Types a string into active element. There must be element with keyboard focus, // otherwise an error is raised. // WithFrequency option can be used to set frequency of typing (letters per sec). The default value is 60 diff --git a/hrp/pkg/uixt/ios_driver.go b/hrp/pkg/uixt/ios_driver.go index 9acc164c..80e80a46 100644 --- a/hrp/pkg/uixt/ios_driver.go +++ b/hrp/pkg/uixt/ios_driver.go @@ -591,6 +591,10 @@ func (wd *wdaDriver) GetPasteboard(contentType PasteboardType) (raw *bytes.Buffe return } +func (wd *wdaDriver) SetIme(ime string) error { + return errDriverNotImplemented +} + func (wd *wdaDriver) SendKeys(text string, options ...ActionOption) (err error) { // [[FBRoute POST:@"/wda/keys"] respondWithTarget:self action:@selector(handleKeys:)] actionOptions := NewActionOptions(options...)