简介
有的时候要对手机UI界面进行滑动测试, 手动或许太消耗时间, 理由Android USB调试模式对UI进行上下滑动测试。
adb指令
使用adb --help 可以查看所有的adb支持指令, 但这里我们只需要上下, 使用到的指令:
adb devices #列举所有设备
adb -s 序列号 shell wm size # 获取指定设备的屏幕分辨率
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c650c29d6be44e9d95fae456ee4ffd29.pngadb -s 序列号 shell input swipe startX startY endX endY
通过startX,startY 起点 到 endX,endY 终点, 实现左/右/上/下滑动
代码
action.go
package mainimport ("encoding/json""fmt""io""os""os/exec""path/filepath""strconv""strings""sync""time"
)type Direction intconst (Move_LEFT Direction = iotaMove_RIGHT = 1Move_UP = 2Move_DOWN = 3
)type IJsonUnmarshal interface {FromJsonBytes(src []byte) error
}type ActionConfig struct {BaseConfig CommandConfig `json:"base_config,omitempty"`ActionItems []ActionItem `json:"action_items,omitempty"`
}func (a *ActionConfig) FromJsonBytes(src []byte) (err error) {err = json.Unmarshal(src, a)return
}type ActionItem struct {Direction Direction `json:"direction"`BeforeSleep int64 `json:"before_sleep,omitempty"`AfterSleep int64 `json:"after_sleep,omitempty"`StartX int `json:"start_x"`StartY int `json:"start_y"`EndX int `json:"end_x"`EndY int `json:"end_y"`
}type DeviceInfoItem struct {Width intHeight intSerialNumber string
}func getActionConfig() (actCfgs ActionConfig, err error) {var f *os.Filef, err = os.Open("./cfg.json")if nil != err {return}defer f.Close()var src []bytesrc, err = io.ReadAll(f)if nil != err {return}err = actCfgs.FromJsonBytes(src)if nil != err {return}if actCfgs.BaseConfig.WorkPath == "." {var exePath stringexePath, err = os.Executable()fmt.Println("1111: ", exePath)if err != nil {return}actCfgs.BaseConfig.WorkPath = filepath.Dir(exePath)}return//actCfgs = ActionConfig{// ActionItems: []ActionItem{// {Move_UP, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_UP, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_UP, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_UP, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_UP, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_UP, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_DOWN, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_DOWN, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_DOWN, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_DOWN, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_DOWN, 0, 5 * time.Second, 0, 0, 0, 0},// {Move_DOWN, 0, 5 * time.Second, 0, 0, 0, 0},// },//}//actCfgs.BaseConfig, err = GetBaseCommandConfig()
}func doCommandAction(cmdCfg CommandConfig, callback func(output []byte) error) error {fmt.Println(cmdCfg)// 创建Cmd结构体cmd := exec.Command(cmdCfg.ExePath, cmdCfg.Arguments...)cmd.Dir = cmdCfg.WorkPath// 运行命令并获取输出output, err := cmd.CombinedOutput()if err != nil {fmt.Println("1-Error:", err)return err}err = callback(output)return err
}func getSerialNumberAction(cmdCfg CommandConfig) (serials []string, err error) {cmdCfg.Arguments = []string{"devices"}err = doCommandAction(cmdCfg, func(output []byte) error {lines := strings.Split(string(output), "\n")serials = make([]string, 0)for i, line := range lines {if 0 == i {continue}fields := strings.Fields(line)if len(fields) > 0 {serials = append(serials, fields[0])//fmt.Println(fields[0])}}return nil})return
}func getDeviceInfo(cmdCfg CommandConfig, serialNumber string) (item DeviceInfoItem, err error) {item.SerialNumber = serialNumbercmdCfg.Arguments = []string{"-s", serialNumber, "shell", "wm", "size"}err = doCommandAction(cmdCfg, func(output []byte) error {fields := strings.Fields(string(output))if 3 > len(fields) {return fmt.Errorf("fail to get device info")}strs := strings.Split(fields[2], "x")var temp int64temp, _ = strconv.ParseInt(strs[0], 10, 64)item.Width = int(temp)temp, _ = strconv.ParseInt(strs[1], 10, 64)item.Height = int(temp)return nil})return
}func getActionItem(item DeviceInfoItem, actionItem *ActionItem) error {actionItem.StartX = item.Width / 2actionItem.EndX = item.Width / 2actionItem.StartY = item.Height / 2switch actionItem.Direction {case Move_UP:actionItem.EndY = actionItem.StartY / 2case Move_DOWN:actionItem.EndY = actionItem.StartY + actionItem.StartY/2case Move_LEFT:case Move_RIGHT:default:break}return nil
}func deviceAction(waiter *sync.WaitGroup, actCfgs ActionConfig, serialNumber string) error {defer waiter.Done()item, err := getDeviceInfo(actCfgs.BaseConfig, serialNumber)if nil != err {return err}for i := range actCfgs.ActionItems {err = getActionItem(item, &actCfgs.ActionItems[i])if nil != err {return err}}cfg := actCfgs.BaseConfigcfg.Arguments = []string{"-s", serialNumber, "shell", "input", "swipe", "startX", "startY", "endX", "endY"}for {for i := range actCfgs.ActionItems {fmt.Println(actCfgs.ActionItems[i])time.Sleep(time.Duration(actCfgs.ActionItems[i].BeforeSleep) * time.Millisecond)cfg.Arguments[len(cfg.Arguments)-4] = strconv.Itoa(actCfgs.ActionItems[i].StartX)cfg.Arguments[len(cfg.Arguments)-3] = strconv.Itoa(actCfgs.ActionItems[i].StartY)cfg.Arguments[len(cfg.Arguments)-2] = strconv.Itoa(actCfgs.ActionItems[i].EndX)cfg.Arguments[len(cfg.Arguments)-1] = strconv.Itoa(actCfgs.ActionItems[i].EndY)if err = doCommandAction(cfg, func(output []byte) error {return nil}); nil != err {return err}time.Sleep(time.Duration(actCfgs.ActionItems[i].AfterSleep) * time.Millisecond)}}
}func StartAction() error {var actCfgs, err = getActionConfig()var waiter sync.WaitGroupvar serials []stringserials, err = getSerialNumberAction(actCfgs.BaseConfig)if nil != err {return err}if 0 >= len(serials) {fmt.Println("not devices!!!")return nil}for i := range serials {waiter.Add(1)go deviceAction(&waiter, actCfgs, serials[i])}waiter.Wait()return nil
}
config.go
package mainimport ("fmt""os""path/filepath"
)const (adbDefaultPath = "D:\\Softwares\\Paths\\Android\\android-sdk\\platform-tools"
)type CommandConfig struct {WorkPath string `json:"work_path"`ExePath string `json:"exe_path"`Arguments []string `json:"arguments,omitempty"`
}func GetBaseCommandConfig() (cfg CommandConfig, err error) {var (exePath string)exePath, err = os.Executable()fmt.Println("1111: ", exePath)if err != nil {return}cfg.WorkPath = filepath.Dir(exePath)cfg.ExePath = fmt.Sprintf("%s\\%s", adbDefaultPath, "adb.exe")fmt.Println("11112: ", cfg)return
}
main.go
package mainimport ("fmt"
)func main() {err := StartAction()if nil != err {fmt.Println(err)return}}
配置文件, 放到程序同级目录
cfg.json
{"base_config": {"work_path": ".","exe_path": "D:/Softwares/Paths/Android/android-sdk/platform-tools/adb.exe"},"action_items": [{"direction": 2,"before_sleep": 0,"after_sleep": 2000}]
}
最后
将手机调试模式打开, 连上电脑,执行程序,需要什么动作在配置文件:
- 支持多台设备;
- 支持多个动作, 都可以在配置文件中添加;
- 支持动作前后延时;
其他
ADB指令基本用法&shell指令
ADB指令基本用法(官网)