设备管理
连接设备
adb connect/disconnect
Android日志
Android 系统的日志分为两部分,底层的 Linux 内核日志输出到 /proc/kmsg,Android 的日志输出到 /dev/log。使用adb logcat,可以将logcat日志信息输出到屏幕
手机teriminal
adb shell
查询已连接设备/模拟器
$ adb devices
List of devices attached
cf264b8f device
emulator-5554 device
10.129.164.6:5555 device
端口转发
adb forword,可以设置将对特定主机端口的请求转发到模拟器/设备实例上的其他端口
查看设备信息
d.info
{'currentPackageName': 'com.ss.android.ugc.aweme', 'displayHeight': 1280, 'displayRotation': 0, 'displaySizeDpX': 411, 'displaySizeDpY': 731, 'displayWidth': 720, 'productName': 'cancro', 'screenOn': True, 'sdkInt': 23, 'naturalOrientation': True}
查看WLAN ip
d.wlan_ip
查看设备详细信息
d.device_info
{'udid': 'ZX1G42CPJD-08:00:27:81:24:f1-MIX_2', 'version': '6.0.1', 'serial': 'ZX1G42CPJD', 'brand': 'Xiaomi', 'model': 'MIX 2', 'hwaddr': '08:00:27:81:24:f1', 'port': 7912, 'sdk': 23, 'agentVersion': '0.9.5', 'display': {'width': 720, 'height': 1280}, 'battery': {'acPowered': True, 'usbPowered': False, 'wirelessPowered': False, 'status': 2, 'health': 2, 'present': True, 'level': 47, 'scale': 100, 'voltage': 3836, 'temperature': 251, 'technology': 'Li-poly'}, 'memory': {'total': 3628052, 'around': '3 GB'}, 'arch': '', 'owner': None, 'presenceChangedAt': '0001-01-01T00:00:00Z', 'usingBeganAt': '0001-01-01T00:00:00Z', 'product': None, 'provider': None}
将文件推送到设备
d.push("foo.txt", "/sdcard/")
从设备中拉出文件
d.pull("/sdcard/tmp.txt", "tmp.txt")
在设备中执行命令
output, exit_code = d.shell("pm list packages", timeout=60) # timeout 60s (Default)
{"error":null,"exitCode":0,"output":"package:com.github.uiautomator\npackage:com.hpbr.bosszhipin\npackage:com.android.providers.telephony\npackage:io.appium.settings\npackage:com.android.providers.calendar\npackage:com.android.providers.media\npackage:com.sohu.inputmethod.sogou\npackage:com.android.wallpapercropper\npackage:com.minhui.networkcapture\npackage:com.android.documentsui\npackage:com.android.galaxy4\npackage:com.android.externalstorage\npackage:com.android.htmlviewer\npackage:cn.com.open.mooc\npackage:com.android.quicksearchbox\npackage:com.android.mms.service\npackage:com.android.providers.downloads\npackage:com.github.uiautomator.test\npackage:com.android.browser\npackage:com.tal.kaoyan\npackage:io.appium.uiautomator2.server\npackage:com.android.defcontainer\npackage:de.robv.android.xposed.installer\npackage:com.droider.crackme0201\npackage:com.android.providers.downloads.ui\npackage:com.android.pacprocessor\npackage:com.xingin.xhs\npackage:com.tencent.mm\npackage:com.android.certinstaller\npackage:com.cxdosx.gowifisetting\npackage:com.cubic.choosecar\npackage:android\npackage:com.tencent.android.qqdownloader\npackage:com.android.camera2\npackage:com.baidu.searchbox\npackage:com.android.backupconfirm\npackage:com.yoho\npackage:com.android.provision\npackage:com.android.statementservice\npackage:bin.mt.plus\npackage:com.android.wallpaper.holospiral\npackage:com.android.phasebeam\npackage:com.android.providers.settings\npackage:just.trust.me\npackage:com.android.sharedstoragebackup\npackage:com.android.printspooler\npackage:com.tencent.qqlite\npackage:com.android.webview\npackage:com.android.inputdevices\npackage:com.xunmeng.pinduoduo\npackage:com.google.android.apps.maps\npackage:com.android.server.telecom\npackage:com.android.keychain\npackage:com.android.chrome\npackage:com.buscode.whatsinput\npackage:com.android.gallery3d\npackage:com.ss.android.ugc.aweme\npackage:com.android.calllogbackup\npackage:com.tencent.mobileqq\npackage:com.android.packageinstaller\npackage:com.android.proxyhandler\npackage:com.cyanogenmod.filemanager\npackage:io.dcloud.H5EA954BB\npackage:app.greyshirts.sslcapture\npackage:io.appium.uiautomator2.server.test\npackage:com.android.wallpaper.livepicker\npackage:com.zhuanzhuan.check\npackage:jackpal.androidterm\npackage:com.android.settings\npackage:com.nice.main\npackage:com.android.wallpaper\npackage:com.android.vpndialogs\npackage:com.sina.weibo\npackage:com.android.phone\npackage:com.android.shell\npackage:com.android.providers.userdictionary\npackage:com.hupan.app\npackage:com.android.location.fused\npackage:com.android.systemui\npackage:com.android.bluetoothmidiservice\npackage:io.kkzs\npackage:tv.danmaku.bili\npackage:com.android.captiveportallogin\npackage:org.geekbang.geekTime\n"}
应用管理
安装apk
adb install [-lrtsdg] <path_to_apk>
卸载apk
adb uninstall com.ss.android.ugc.aweme
启动app
d.app_start("com.ss.android.ugc.aweme")
停止app
d.app_stop("com.ss.android.ugc.aweme")
清除app数据
d.app_clear('com.ss.android.ugc.aweme')
获取当前的应用信息
d.app_current()
{'package': 'com.ss.android.ugc.aweme', 'activity': 'com.ss.android.ugc.aweme.splash.SplashActivity'}
停止所有的app
d.app_stop_all()
获得app信息
d.app_info("com.examples.demo")
{"data":{"packageName":"com.ss.android.ugc.aweme","mainActivity":"com.ss.android.ugc.aweme.main.MainActivity","label":"抖音短视频","versionName":"10.6.0","versionCode":100601,"size":82302370},"success":true}
获得所有正在运行的app
d.app_list_running()
['com.android.gallery3d', 'com.android.defcontainer', 'com.android.keychain', 'com.android.statementservice', 'com.android.shell', 'com.android.documentsui', 'com.ss.android.ugc.aweme', 'com.android.externalstorage', 'com.android.phone', 'com.tencent.mm', 'com.android.systemui']
查看应用列表
d.app_list()
支持的参数
支持的过滤参数如下:
参数 | 显示列表 |
---|---|
无 | 所有应用 |
-f | 显示应用关联的 apk 文件 |
-d | 只显示 disabled 的应用 |
-e | 只显示 enabled 的应用 |
-s | 只显示系统应用 |
-3 | 只显示第三方应用 |
-i | 显示应用的 installer |
-u | 包含已卸载应用 |
| 包名包含 |
与应用的交互
打印UI
xml = d.dump_hierarchy()
元素定位
resourceId
d(resourceId=)这种方法是最方便的,但是一个APP很多地方都不会有这种特定的标识
className
d(className=)这个方法也很方便,但是弊端也是同个界面多个元素使用同一个className
xpath
d.xpath()在以上方法都不行时就需要xpath定位了,弊端是APP当中的元素id跟classname的影响代码很冗长,同样的如果在APP爬虫中,xpath的优势就变得明显了
text
d(text=)使用文本去确定操作的区域,好处是方便进行定位,在没有文本的就不能进行此项操作,具有局限性
坐标
d.click(坐标)使用cilck方法通过坐标定位需要点击的元素,通过这个方法可以点击的操作都可以进行完成
元素操作
点击系统按键
d.press("back")
滑动
d.swipe(sx, sy, ex, ey)
点击
d.click(x, y)
元素监控
注册监控
d.watcher("ANR").when(xpath="ANR").when("Force Close").click()
开启监控
d.watcher.start(2.0) # 默认监控间隔2.0s
停止监控
d.watcher.stop()
截图
im = d(text="Settings").screenshot()
im.save("settings.jpg")
视频录制
d.screenrecord('output.mp4')
time.sleep(10)
# or do something else
d.screenrecord.stop() # 停止录制后,output.mp4文件才能打开
图像匹配
imdata = "target.png" # 也可以是URL, PIL.Image或OpenCV打开的图像
d.image.match(imdata)
# 匹配待查找的图片,立刻返回一个结果
# 返回一个dict, eg: {"similarity": 0.9, "point": [200, 300]}
d.image.click(imdata, timeout=20.0)
# 在20s的时间内调用match轮询查找图片,当similarity>0.9时,执行点击操作
多设备管理
atxserver2是一个可以远程控制Android和IOS设备的管理平台,技术栈为:Python3+NodeJS+RethinkDB
包括四部分:
1.RethinkDB : 是一个开源的轻量级的数据库,主要用于存储用于多设备管理的用户、设备数据等
2.atxserver2 :主要负责处理数据,显示与用户的前端交互等等,所以单独运行atxserver2也可以看到效果,当运行起来以候访问: IP:4000 就可以看到效果
3.atxserver2-android-provider: 这一部分是接入Android设备必须启动的项目,主要用于发现Android设备和负责Android设备和平台的交互工作,要想接入Android设备必须启动此项目
4.atxserver2-ios-provider: 这一部分是接入IOS设备必须启动的项目,主要负责IOS设备和平台的交互工作,同样的要想接入IOS设备必须启动此项目(注意需要MAC电脑)
基于 minicap+minitouch+atx-agent实现了Android的远程控制
Minicap提供了一个套接字接口,通过ndk的截屏接口不停的截屏并通过socket接口实时发送,这样客户端便可以得到一序列的图片流,图片流合成后就成为视频
minitouch提供了一个套接字接口,用于在Android设备上触发多点触控事件和手势
除了界面控制外,也提供了API接口控制
adb
Android 调试桥 (adb) 是一种功能多样的命令行工具,可让您与设备进行通信。adb 命令可用于执行各种设备操作(例如安装和调试应用),并提供对 Unix shell(可用来在设备上运行各种命令)的访问权限。它是一种客户端-服务器程序,包括以下三个组件:
-
客户端:用于发送命令。客户端在开发计算机上运行。您可以通过发出 adb 命令从命令行终端调用客户端
-
守护程序 (adbd):用于在设备上运行命令。守护程序在每个设备上作为后台进程运行
-
服务器:用于管理客户端与守护程序之间的通信。服务器在开发机器上作为后台进程运行
adb 的工作原理
当启动某个 adb 客户端时,该客户端会先检查是否有 adb 服务器进程正在运行。如果没有,它会启动服务器进程。服务器在启动后会与本地 TCP 端口 5037 绑定,并监听 adb 客户端发出的命令 - 所有 adb 客户端均通过端口 5037 与 adb 服务器通信
然后,服务器会与所有正在运行的设备建立连接。它通过扫描 5555 到 5585 之间(该范围供前 16 个模拟器使用)的奇数号端口查找模拟器。服务器一旦发现 adb 守护程序 (adbd),便会与相应的端口建立连接。每个模拟器都使用一对按顺序排列的端口 - 用于控制台连接的偶数号端口和用于 adb 连接的奇数号端口。例如:
模拟器 1,控制台:5554
模拟器 1,adb:5555
模拟器 2,控制台:5556
模拟器 2,adb:5557
依此类推
如上所示,在端口 5555 处与 adb 连接的模拟器与控制台监听端口为 5554 的模拟器是同一个
服务器与所有设备均建立连接后,您便可以使用 adb 命令访问这些设备。由于服务器管理与设备的连接,并处理来自多个 adb 客户端的命令,因此您可以从任意客户端(或从某个脚本)控制任意设备
uiautomator2
uiautomator2是基于uiAutomator的,uiAutomator是Google提供的用来做安卓自动化测试的一个Java库,基于Accessibility服务。可以获取屏幕上任意一个APP的任意一个控件属性,并对其进行任意操作。uiautomator2将uiAutomator的功能封装成了http接口的Python库,并在在手机上运行了一个http rpc服务,实现了在电脑上运行的python脚本控制手机的目的
![](https://img-blog.csdnimg.cn/img_convert/6253a321ebfa0963464ad1ecf8d27fcb.png)
uiautomator2工作流程源码追踪
1.本地
命令>http>_AgentRequestSession>_prepare_atx_agent>_setup_atx_agent>start_atx_agent>_get_atx_agent_url>forward_port
每个uiautomator2命令都会经过http方法也就是_AgentRequestSession,_AgentRequestSession在发送请求前都会先对atx-agent的版本检查一下_prepare_atx_agent,如果版本不符则进行安装操作并启动atx-agent,之后_AgentRequestSession开始获得atx_agent_url,其中host是localhost,端口是从forward_list获得的,如果没有则新forward一个,这样在本地运行的命令请求现在到了本地的forward端口上了,forward是一个socket连接,根据协议其将本地指定端口的数据转发到远端指定端口上,也就是手机设备7912端口,atx-agent服务运行在这个端口上
2.atx-agent
uiautomatorProxy>android-uiautomator-server
atx-agent收到请求后,根据路由如果是"/jsonrpc/0"或"/ping"将交给uiautomatorProxy处理,源码
![atx-agent转发处理](https://img-blog.csdnimg.cn/20201124172844359.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xvbmdqdWFuZmVuZ3pj,size_16,color_FFFFFF,t_70)
uiautomatorProxy收到调用后,负责将数据携带好后,进而去请求9008端口的服务,起到的是代理的作用,源码
![](https://img-blog.csdnimg.cn/20201124183821401.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xvbmdqdWFuZmVuZ3pj,size_16,color_FFFFFF,t_70)
这个占用9008端口的服务也是atx-agent触发的,源码
![](https://img-blog.csdnimg.cn/20201124175441279.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xvbmdqdWFuZmVuZ3pj,size_16,color_FFFFFF,t_70)
3.android-uiautomator-server
AutomatorHttpServer>JsonRpcServer>UiAutomator
这里是真正包裹原生uiautomator的那个服务AutomatorHttpServer,可以看到是在这里启动的9008端口,源码
![启动9008服务](https://img-blog.csdnimg.cn/20201124180047267.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xvbmdqdWFuZmVuZ3pj,size_16,color_FFFFFF,t_70)
AutomatorHttpServer是基于NanoHTTPD的,NanoHTTPD是一个轻量级的java服务器,源码
![](https://img-blog.csdnimg.cn/20201124181133426.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xvbmdqdWFuZmVuZ3pj,size_16,color_FFFFFF,t_70)
随后,setUp中,又做了一次路由,将jsonrpc/0这种请求丢给了JsonRpcServer处理,进而调用AutomatorService中的方法,源码
![](https://img-blog.csdnimg.cn/img_convert/eadec94cb32869c405521b8cb1e35a71.png)
总结
1.基本操作:本次主要对手机先以设备管理、应用管理、与应用的交互、多设备管理的维度,介绍了在不接触的情况下,通过代码的方式来获得手机信息并控制其运行,其实它还能帮我们做更多的事情,只要人可以做的它也可以做,在工作或生活中如果有需要对APP进行有规律的操作,交给它就可以了
2.监控:为了方面随时查看手机的运行状况,增加监控,在远程也可以直观的查看操控手机
3.原理:在最后介绍了一下代码是如何控制手机运行的,了解了它的运行原理后希望能够对大家有些启发,因为我们也可以写一些库发送到手机上作一些工具,比如说做后门,做监控,做很多很多
相关资料: