重新梳理一下adb操作app(golang版)
主要参考我之前整理的内容https://www.cnblogs.com/pu369/p/10490668.html,梳理简化一下思路,以便于用最简单的代码来应对无聊人士的要求。
需求主要是:打开手机、切换到主页面、找页面关键字、点击、滑动、返回、杀死APP;当然,延时是必须的。
另外我的手机特点是:取消了密码开机,用电源键开机后有广告、但点按home键后会显示主页面
步骤:
1、新建main.go (有些引用的包可能不需要,具体的一些函数定义在后面)如下:
- package main
- import (
- "crypto/md5"
- "fmt"
- "image/png"
- "io/ioutil"
- "log"
- "os"
- "regexp"
- "strings"
- "bytes"
- "os/exec"
- "strconv"
- "time"
- "github.com/robfig/cron"
- )
- func main() {
- dowork()
- c := cron.New()
- c.AddFunc("0 0 12 * * ?", dowork)
- c.Start()
- select {}
- }
- func dowork(){
- ...
- }
- ...
说明:main函数主要是用select{}让程序永远执行下去;同时,引用github.com/robfig/cron (可参考:https://www.cnblogs.com/liuzhongchao/p/9521897.html) 使程序每天12点定时执行。(当然,也可参考这里自己实现定时功能:https://www.jianshu.com/p/4955e5d652ae)
2、dowork()函数仅用于调用后面的函数
- func dowork() {
- //点击
- AdbShellInputTap()
- //延时
- TimeSleepDuration()
- ...
- }
3、延时函数(等待页面加载、或APP要求用户查看多长时间,时间单位为秒)
- func TimeSleepDuration(x int) {
- time.Sleep(time.Duration(x) * time.Second)
- }
4、打开(关闭)手机电源(为简化就不判断手机是否休眠了,其实是模拟按键,我会找些键值附在本文最后面)
- AdbShellInputKeyEvent("") //power
- func AdbShellInputKeyEvent(s string) {
- exec.Command("adb", "shell", "input", "keyevent", s).Run()
- }
5、切换到手机主页面
由我的手机没密码,打开电源后有广告,按home会回到主页面,
就用步骤4的AdbShellInputKeyEvent函数模拟home键,在代码中可以多按两次。
- AdbShellInputKeyEvent("") //home
常的还有: 4表示back返回键
6、打开某个APP-直接用下面的AdbShellInputTap(X坐标、Y坐标)函数模拟点击
打开手机 设置-通用-开发者选项-指针位置。将APP放在手机主页面,然后点按APP图标的中心位置查看坐标 X,Y
- func AdbShellInputTap(x, y int) {
- x2 := strconv.Itoa(x)
- y2 := strconv.Itoa(y)
- exec.Command("adb", "shell", "input", "tap", x2, y2).Run()
- }
7、想点击页面包含某个“关键字”的区域
7.1 首先要将手机屏幕显示页面的源码截取到电脑上,用AdbShellUiautomatorDump()得到window_dump.xml并复制到了当前go程序所在的目录(由于从手机复制到电脑需要时间,所以在这个代码中加了延时2秒,以等待复制完成。实际使用中有可能要根据你的设备速度调整这里的延时时间)
- func AdbShellUiautomatorDump() {
- //删除当前目录下的window_dump.xml
- exec.Command("cmd", "/c", "del", "-y", "window_dump.xml").Run()
- //重新dump
- exec.Command("adb", "shell", "uiautomator", "dump", "/sdcard/window_dump.xml").Run()
- exec.Command("adb", "pull", "/sdcard/window_dump.xml", ".").Run()
- exec.Command("adb", "shell", "rm", "/sdcard/window_dump.xml").Run()
- TimeSleepDuration(2)
}
7.2 点击“关键字”,需要指明点击找到的第几个(用正则表达式匹配),用0表示第一个。通常是Tap("关键字",0)
- func Tap(s string, ix int) {
- //先执行AdbShellUiautomatorDump函数。
- AdbShellUiautomatorDump()
file, _ := os.Open("window_dump.xml")- defer file.Close()
- doc, _ := ioutil.ReadAll(file)
- doc1 := string(doc)
- ss := fmt.Sprintf("%s%s%s", `<node.[^>]+?`, s, `.[^>]+?\[(\d+),(\d+)\]\[(\d+),(\d+)\].+?>`)
- r := regexp.MustCompile(ss)
- match := r.FindAllStringSubmatch(doc1, -)
- le := len(match)
- //匹配到1个或多个,ixx表示匹配到的第几个
- ixx := ix
- if le == {
- log.Println("未匹配到:", s)
- return
- }
- if ix < {
- ixx = le + ix
- }
- if ixx < {
- ixx =
- }
- if ixx >le {
- ixx = le
- }
- x1, _ := strconv.Atoi(fmt.Sprint(match[ixx][]))
- y1, _ := strconv.Atoi(fmt.Sprint(match[ixx][]))
- x2, _ := strconv.Atoi(fmt.Sprint(match[ixx][]))
- y2, _ := strconv.Atoi(fmt.Sprint(match[ixx][]))
- xx := (x2-x1)/ + x1
- yy := (y2-y1)/ + y1
- //log.Println(s)
- AdbShellInputTap(xx, yy)
- }
8、更复杂的需求,如:
主页面上有N个链接(每个链接的特点是:包括年-月-,类似2019-1-),点第1个,打开一篇文章,看几分钟后,返回;类似的,点第2个链接.......最后,点开第N个链接,查看几分钟后,返回主页面,再向下翻页4次。
实现:开始以为要用递归,后来发现在golang中用for循环即可。为了层次清晰,分成以下几个函数
8.1在步骤2的dowork函数中,写以下循环,表示主页面要向下翻4次(页)
- //学习文章
- for i := ; i < ; i++ {
- fmt.Println("article", i)
- getArticles()
- }
8.2 getArticles中,首先findxxbydate(我用xx表示链接的意思:-)用正则查找当前页中,所有包含包括年-月-,即类似2019-1-的链接,存入二维切片[][]string中。
然后用for循环打开每个链接指向的文章,并停留350秒,然后按返回键。当页面所有链接循环操作完毕后,将主页面向上滚动1000px(这个值根据手机页面的实际滚动区域高度来确定。getArticles执行完毕后,进入下一个主循环。
getArticles代码:
- func getArticles() {
- //找当前UI中“年-月-”,写入[][]string
- xx := findxxbydate()
- for _, v := range xx {
- //循环打开
- TapRegion4xx(v, )
- }
- //向上滚动1000
- AdbShellInputSwipe(, , , )
- TimeSleepDuration()
- }
8.3 上面的findxxbydate用于查找当前手机页面上所有匹配正则表达式的位置,存入二维切片(要根据需要修改ss正则表达式)
- func findxxbydate() [][]string {
- //先执行AdbShellUiautomatorDump函数。
- AdbShellUiautomatorDump()
- file, _ := os.Open("window_dump.xml")
- defer file.Close()
- doc, _ := ioutil.ReadAll(file)
- doc1 := string(doc)
- ss := `<node.[^>]+?\d{}-\d{}-.[^>]+?\[(\d+),(\d+)\]\[(\d+),(\d+)\].[^>]+?>`
- r := regexp.MustCompile(ss)
- match := r.FindAllStringSubmatch(doc1, -)
- return match
- }
8.4 TapRegion4xx(v, 350)用在步骤8.2的for range循环中,用于点击“年-月-”数组中的每一个链接,并在点开后,停留350秒,后返回
- func TapRegion4xx(match []string, t int) {
- x1, _ := strconv.Atoi(fmt.Sprint(match[]))
- y1, _ := strconv.Atoi(fmt.Sprint(match[]))
- x2, _ := strconv.Atoi(fmt.Sprint(match[]))
- y2, _ := strconv.Atoi(fmt.Sprint(match[]))
- xx := (x2-x1)/ + x1
- yy := (y2-y1)/ + y1
- AdbShellInputTap(xx, yy)
- TimeSleepDuration(t)
- AdbShellInputKeyEvent("") //back
- TimeSleepDuration()
- }
8.6 模拟滑动手机页面 AdbShellInputSwipe
- //模拟滑动
- //adb shell input swipe 0 0 600 600
- func AdbShellInputSwipe(x1, y1, x2, y2 int) {
- xx1 := strconv.Itoa(x1)
- yy1 := strconv.Itoa(y1)
- xx2 := strconv.Itoa(x2)
- yy2 := strconv.Itoa(y2)
- exec.Command("adb", "shell", "input", "swipe", xx1, yy1, xx2, yy2).Run()
- }
注意:之前曾误以为手机页面对应的源码像电脑上的html5一样包括不可见部分。后来才发现每次获取的手机页面源码只包含可见部分。也就是说只要滑动手机屏幕就必须重新用AdbShellUiautomatorDump获取。
另外,关于判断设备是否休眠、查看手机上应用的packageName、查看最上层activity名字等功能,可参考我之前的文章https://www.cnblogs.com/pu369/p/10490668.html
重新梳理一下adb操作app(golang版)的更多相关文章
- adb常用命令(golang版)及输入中文
package main import ( "crypto/md5" "fmt" "image/png" "io/ioutil&q ...
- 【项目记录】-液化气配送app android版
15年底参与过甲方呼叫中心平台开发.液化气配送app android版要求1个月开发完成.开发此项目以前我只有过一周android的开发经验.(与甲方签署过保密协议,遵循职业道德有些敏感信息不能写.) ...
- adb 卸载APP命令和杀死APP命令
使用adb 卸载APP命令 在cmd命令行下,直接 输入 adb uninstall 包名 比如 adb uninstall com.ghstudio.BootStartDemo 杀死APP命令 先用 ...
- Golang版protobuf编译
官方网址: https://developers.google.com/protocol-buffers/ (需要FQ) 代码仓库: https://github.com/google/protobu ...
- 分享我开发的网络电话Android手机APP正式版,图文详解及下载
分享我开发的网络电话Android手机APP正式版,图文详解及下载 分享我开发的网络电话Android手机APP正式版 实时语音通讯,可广域网实时通讯,音质清晰流畅! 安装之后的运行效果: 第一次安装 ...
- 重新想象 Windows 8 Store Apps (70) - 其它: 文件压缩和解压缩, 与 Windows 商店相关的操作, app 与 web, 几个 Core 的应用, 页面的生命周期和程序的生命周期
[源码下载] 重新想象 Windows 8 Store Apps (70) - 其它: 文件压缩和解压缩, 与 Windows 商店相关的操作, app 与 web, 几个 Core 的应用, 页面的 ...
- python appium 操作app
下面是一些Python脚本中操作app的用法: 检查app安装情况(返回true/false), driver.is_app_installed(package_name) 安装app driver. ...
- [Golang] kafka集群搭建和golang版生产者和消费者
一.kafka集群搭建 至于kafka是什么我都不多做介绍了,网上写的已经非常详尽了. 1. 下载zookeeper https://zookeeper.apache.org/releases.ht ...
- 第三百七十六节,Django+Xadmin打造上线标准的在线教育平台—创建用户操作app,在models.py文件生成5张表,用户咨询表、课程评论表、用户收藏表、用户消息表、用户学习表
第三百七十六节,Django+Xadmin打造上线标准的在线教育平台—创建用户操作app,在models.py文件生成5张表,用户咨询表.课程评论表.用户收藏表.用户消息表.用户学习表 创建名称为ap ...
随机推荐
- 跳转语句 break;continue; return; goto 区别用法
C语言是按顺序执行语句的语言——一个接一个.即使它有条件语句或循环语句,程序的流程也是自上而下的.没有顺序流的随机跳转或跳转.但我们的程序是为了满足任何现实世界的需求,一个接一个地执行永远不会很直接. ...
- go 常量定义和使用
常量的定义与变量类似,只不过使用 const 关键字. 常量可以是字符.字符串.布尔或数字类型的值. 常量不能使用 := 语法定义. 常量必须定义时赋值,不能多次赋值 package main imp ...
- 《CAP定理》
分布式系统的最大难点,就是各个节点的状态如何同步.CAP 定理是这方面的基本定理,也是理解分布式系统的起点. 分布式系统的三个指标 这三个指标不可能同时做到——这个结论就叫做 CAP 定理. Part ...
- Nginx server配置
项目一般都需要前后端的配置,用二级域名把它区分开:首先在nginx.conf:里面加一句话: http{ #这里面有很多其他的配置 如:gzip FastCGI等等 include vhosts/*. ...
- JDBC 学习复习9 配置Tomcat数据源
在实际开发中,我们有时候还会使用服务器提供给我们的数据库连接池,比如我们希望Tomcat服务器在启动的时候可以帮我们创建一个数据库连接池,那么我们在应用程序中就不需要手动去创建数据库连接池,直接使用T ...
- Ubuntu 14.04 用户如何安装深度音乐播放器和百度音乐插件
播放本地音乐或者收听国外的音乐电台,Ubuntu 14.04 自带的音乐播放器 Rhythmbox 完全能够满足,但是如果你想有像酷狗那样的国内播放器就需要折腾一下,还好有深度音乐播放器,这是一款完全 ...
- Java 18套JAVA企业级大型项目实战分布式架构高并发高可用微服务电商项目实战架构
Java 开发环境:idea https://www.jianshu.com/p/7a824fea1ce7 从无到有构建大型电商微服务架构三个阶段SpringBoot+SpringCloud+Solr ...
- MySql Host is blocked because of many connection errors 问题的解决方法
错误日志: message from server: "Host '10.250.112.141' is blocked because of many connection errors; ...
- 还在用ABAP进行SAP产品的二次开发?来了解下这种全新的二次开发理念吧
Jerry从2018年底至今,已经写了一系列关于SAP Kyma的文章,您可以移步到本文末尾获得这些文章的列表.Kyma是SAP开源的一个基于Kubernetes的云原生应用开发平台,能够允许SAP的 ...
- CentOS linux7 设置开机启动服务
常用命令 描述 旧命令 新命令 使服务自动启动 chkconfig --level 3 http on syste ...