介绍 uiautomator2 是一个可以使用Python对Android设备进行UI自动化的库。其底层基于Google uiautomator,Google提供的uiautomator库可以获取屏幕上任意一个APP的任意一个控件属性,并对其进行任意操作。
库地址 GitHub地址:https://github.com/openatx/uiautomator2 文档说明:https://github.com/openatx/uiautomator2/blob/master/README.md
安装 安装uiautomator2 1 2 pip install --pre uiautomator2 pip install pillow (如果需要截图,可安装这个库)
设备安装atx-agent(接收PC端命令,对手机UI进行操作) 首先设备连接到PC,并能够adb devices发现该设备。 执行下面的命令会自动安装本库所需要的设备端程序:uiautomator-server,atx-agent,openstf / minicap,openstf / minitouch
1 2 3 4 5 6 7 8 python -m uiautomator2 init python -m uiautomator2 init --mirror --serial $SERIAL python -m uiautomator2 init --mirror
最后提示success,代表atx-agent初始化成功。
注:如果安装完成后,在手机桌面上没有出现名为ATX的应用,说明没有安装成功。需要手动安装APK,路径为:site-packages\uiautomator2\assets
,安装包名称为app-uiautomator.apk
安装weditor 有了这个,方便我们快速的识别手机上的元素,方便写代码
安装好之后,就可以在命令行运行 weditor --help
确认是否安装成功了。
Windows系统可以使用命令在桌面创建一个快捷方式:
在windows cmd中执行上述命令后,会在桌面上创建一个快捷方式。
启动方法: 方法1. 命令行直接输入 weditor 会自动打开浏览器,输入设备的ip或者序列号,点击Connect即可; 方法2. 桌面上双击WEditor快捷方式即可; 方法3. 命令行中执行 python -m weditor
应用及操作 调用uiautomator2的过程
配置手机设备参数,设置具体操作的是哪一台手机
抓取手机上应用的控件,制定对应的控件来进行操作
对抓取到的控件进行操作,比如点击、填写参数等。
设备连接方法,有两种:
python-uiautomator2连接手机的方式有两种,一种是通过WIFI,另外一种是通过USB。两种方法各有优缺点。 WIFI最便利的地方要数可以不用连接数据线,USB则可以用在PC和手机网络不在一个网段用不了的情况。
(1)通过WiFi,假设设备IP 192.168.0.107和您的PC在同一网络中
1 2 import uiautomator2 as u2d = u2.connect('192.168.0.107' )
(2)通过USB, 假设设备序列是123456789F
1 2 3 import uiautomator2 as u2d = u2.connect('123456789F' )
在没有参数的情况下调用u2.connect(), uiautomator2将从环境变量ANDROID_DEVICE_IP获取设备IP。如果这个环境变量是空的,uiautomator将返回connect_usb,您需要确保只有一个设备连接到计算机。
检查并维持设备端守护进程处于运行状态:
注:该功能从3.0.0开始不可用。
打开调试开关:
安装应用,只能从URL安装:
1 d.app_install('http://some-domain.com/some.apk' )
启动应用:
1 d.app_start('com.eg.android.AlipayGphone' )
停止应用:
1 2 3 4 5 d.app_stop('com.eg.android.AlipayGphone' ) d.app_clear('com.eg.android.AlipayGphone' )
停止所有正在运行的应用程序:
1 2 3 4 5 d.app_stop_all() d.app_stop_all(excludes=['com.examples.demo' ])
跳过弹窗,禁止弹窗:
1 2 d.disable_popups() d.disable_popups(False )
获取设备信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 d.info print (d.window_size())print (d.current_app())print (d.serial)print (d.wlan_ip)print (d.device_info)
获取应用信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 d.app_info("com.eg.android.AlipayGphone" ) ''' { "packageName": "com.eg.android.AlipayGphone", "mainActivity": "com.eg.android.AlipayGphone.AlipayLogin", "label": "支付寶", "versionName": "10.2.13.9020", "versionCode": 360, "size": 108306104 } ''' img = d.app_icon("com.eg.android.AlipayGphone" ) img.save("icon.png" )
推拉文件: (1)将文件推送到设备
1 2 3 4 5 6 7 8 9 10 11 12 d.push("foo.txt" , "/sdcard/" ) d.push("foo.txt" , "/sdcard/bar.txt" ) with open ("foo.txt" , 'rb' ) as f: d.push(f, "/sdcard/" ) d.push("foo.sh" , "/data/local/tmp/" , mode=0o755 )
(2)从设备中拉出一个文件
1 2 3 4 d.pull("/sdcard/tmp.txt" , "tmp.txt" ) d.pull("/sdcard/some-file-not-exists.txt" , "tmp.txt" )
关键事件: (1)打开/关闭屏幕
1 2 d.screen_on()#打开屏幕 d.screen_off() #关闭屏幕
(2)获取当前屏幕状态
(3)硬键盘和软键盘操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 d.press("home" ) d.press("back" ) d.press("left" ) d.press("right" ) d.press("up" ) d.press("down" ) d.press("center" ) d.press("menu" ) d.press("search" ) d.press("enter" ) d.press("delete" ) d.press("recent" ) d.press("volume_up" ) d.press("volume_down" ) d.press("volume_mute" ) d.press("camera" ) d.press("power" )
(4)解锁屏幕
手势与设备的交互:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 d.click(x,y) d.double_click(x,y) d.double_click(x,y,0.1 ) d.long_click(x,y) d.long_click(x,y,0.5 ) d.swipe(sx, sy, ex, ey) d.swipe(sx, sy, ex, ey, 0.5 ) d.drag(sx, sy, ex, ey) d.drag(sx, sy, ex, ey, 0.5 ) d.swipe((x0, y0), (x1, y1), (x2, y2), 0.2 ) d.long_click(0.5 , 0.5 ) 表示长按屏幕中心 XPath: d.orientation d.set_orientation("l" ) d.set_orientation("r" ) d.set_orientation("n" ) d.freeze_rotation() d.freeze_rotation(False ) d.screenshot("home.jpg" ) image = d.screenshot() image.save("home.jpg" ) import cv2image = d.screenshot(format ='opencv' ) cv2.imwrite('home.jpg' , image) imagebin = d.screenshot(format ='raw' ) open ("some.jpg" , "wb" ).write(imagebin)d.dump_hierarchy() d.open_notification() d.open_quick_settings() d(text="Settings" ).exists d.exists(text="Settings" ) d(text="Settings" ).exists(timeout=3 ) d(text="Settings" ).info d(text="Settings" ).get_text() d(text="Settings" ).set_text("My text..." ) d(text="Settings" ).clear_text() d(text="Settings" ).center()
UI对象有五种定位方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 d(text="Settings" ).click() d(text="Settings" , className="android.widget.TextView" ).click() d(resourceId="com.ruguoapp.jike:id/tv_title" , className="android.widget.TextView" ).click() d(description="设置" ).click() d(description="设置" , className="android.widget.TextView" ).click() d(className="android.widget.TextView" ).click() d.xpath("//android.widget.FrameLayout[@index='0']/android.widget.LinearLayout[@index='0']" ).click() d.click(182 , 1264 ) d(text="Settings" ).click(timeout=10 ) d(text='Skip' ).click_exists(timeout=10.0 ) d(text="Skip" ).click_gone(maxretry=10 , interval=1.0 ) d(text="Settings" ).click(offset=(0.5 , 0.5 )) d(text="Settings" ).click(offset=(0 , 0 )) d(text="Settings" ).click(offset=(1 , 1 )) d(text="设置" ).double_click() d.double_click(x, y, 0.1 ) d(text="Settings" ).long_click() d.long_click(x, y, 0.5 ) d(text="Settings" ).drag_to(x, y, duration=0.5 ) d(text="Settings" ).drag_to(text="Clock" , duration=0.25 )
常见用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 d.xpath("//android.widget.TextView" ).wait(10.0 ) d.xpath("//*[@content-desc='分享']" ).click() if d.xpath("//android.widget.TextView[contains(@text, 'Se')]" ).exists: print ("exists" ) for elem in d.xpath("//android.widget.TextView" ).all (): print ("Text:" , elem.text) for elem in d.xpath("//android.widget.TextView" ).all (): print ("Attrib:" , elem.attrib) for elem in d.xpath("//android.widget.TextView" ).all (): print ("Position:" , elem.center()) //* //*[contains(@resource-id , 'login' )] //android.widget.Button[contains(@text, '账号' ) or contains(@text, '帐号' )] (//android.widget.ImageView)[2 ] (//android.widget.ImageView)[last()] //*[contains(name(), "ImageView" )]
中文输入 1、set_text() 只能输入英文
2、输入中文要: 先切换为FastInputIME输入法,然后用 send_keys()
1 2 3 4 d(resourceId="com.lianjia.beike:id/a7r" ).click() d.set_fastinput_ime(True ) d.send_keys("保利学府里" ) d.set_fastinput_ime(False )