第二十九章 U2的基本操作
1. U2的基本操作
这节我们介绍一些用uiautomator2操作手机app的一些命令。
1.1 启动app
先启动夜神模拟器,然后在本地创建新的py文件,命名为“U2的基本操作”。
import uiautomator2 as u2
d = u2.connect_usb('127.0.0.1:62001')
d.app_start('包名')
1.2 针对谋app获取包名
下面我们再介绍一种获取包名的方法,在命令行中输入:
C:\Users\MI>aapt dump badging C:\Users\MI\Downloads\106_6f2363ad3441f2f56894becfa7a999be.apk
其中aapt dump badging 后面跟的是安装包的路径,就是我们要操作的那个app的apk文件包,拖进来就可以了。aapt也是一个exe文件,跟adb文件一样在bin文件夹里,也是可以直接操作的。我们回车运行:
C:\Users\MI>aapt dump badging C:\Users\MI\Downloads\106_6f2363ad3441f2f56894becfa7a999be.apk
package: name='com.tal.kaoyan' versionCode='132' versionName='3.8.2beta'
sdkVersion:'21'
targetSdkVersion:'29'
uses-permission:'android.permission.SYSTEM_ALERT_WINDOW'
uses-permission:'android.permission.INTERNET'
uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'
uses-permission:'android.permission.ACCESS_NETWORK_STATE'
uses-permission:'android.permission.ACCESS_WIFI_STATE'
uses-permission:'android.permission.BLUETOOTH'
uses-permission:'android.permission.READ_EXTERNAL_STORAGE'
uses-permission:'android.permission.MOUNT_UNMOUNT_FILESYSTEMS'
uses-permission:'android.permission.GET_TASKS'
uses-permission:'android.permission.CHANGE_WIFI_STATE'
uses-permission:'android.permission.READ_PHONE_STATE'
uses-permission:'android.permission.INTERACT_ACROSS_USERS_FULL'
uses-permission:'android.permission.WAKE_LOCK'
uses-permission:'android.permission.RECEIVE_BOOT_COMPLETED'
uses-permission:'android.permission.VIBRATE'
uses-permission:'android.permission.READ_LOGS'
uses-permission:'android.permission.RECEIVE_USER_PRESENT'
uses-permission:'android.permission.RECORD_AUDIO'
uses-permission:'android.permission.CAMERA'
uses-permission:'android.permission.WAKE_LOCK'
uses-permission:'android.permission.DISABLE_KEYGUARD'
uses-permission:'android.permission.USE_FINGERPRINT'
uses-permission:'android.permission.FOREGROUND_SERVICE'
uses-permission:'android.permission.WAKE_LOCK'
uses-permission:'android.permission.REQUEST_INSTALL_PACKAGES'
uses-permission:'android.permission.MODIFY_AUDIO_SETTINGS'
uses-feature:'android.hardware.camera'
uses-feature:'android.hardware.camera.autofocus'
uses-feature:'android.hardware.camera.flash'
uses-permission:'android.permission.RECORD_VIDEO'
uses-permission:'android.permission.CHANGE_CONFIGURATION'
uses-permission:'com.asus.msa.SupplementaryDID.ACCESS'
uses-permission:'com.tal.kaoyan.permission.MIPUSH_RECEIVE'
uses-permission:'com.coloros.mcs.permission.RECIEVE_MCS_MESSAGE'
uses-permission:'com.heytap.mcs.permission.RECIEVE_MCS_MESSAGE'
uses-permission:'getui.permission.GetuiService.com.tal.kaoyan'
uses-permission:'android.permission.WRITE_SETTINGS'
uses-permission:'android.permission.WRITE_CONTACTS'
uses-permission:'com.tal.kaoyan.permission.PROCESS_PUSH_MSG'
uses-permission:'com.tal.kaoyan.permission.PUSH_PROVIDER'
uses-permission:'android.permission.CHANGE_NETWORK_STATE'
uses-permission:'android.permission.READ_SETTINGS'
uses-permission:'com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA'
application: label='鑰冪爺甯? icon='res/drawable-mdpi-v4/ic_launcher.png'
uses-library-not-required:'org.apache.http.legacy'
launchable activity name='com.tal.kaoyan.ui.activity.SplashActivity'label='' icon=''
uses-feature:'android.hardware.bluetooth'
uses-feature:'android.hardware.microphone'
uses-feature:'android.hardware.wifi'
uses-feature:'android.hardware.touchscreen'
main
app-widget
other-activities
other-receivers
other-services
supports-screens: 'small' 'normal' 'large' 'xlarge'
supports-any-density: 'true'
locales: '--_--' 'zh' 'zh_CN'
densities: '120' '160' '240' '320' '480' '640' '65534'
native-code: 'armeabi-v7a'
C:\Users\MI>
name='com.tal.kaoyan’就是他的包名。
我们把包名传递进去:
import uiautomator2 as u2
d = u2.connect_usb('127.0.0.1:62001')
d.app_start('com.tal.kaoyan')
可能跟这个app有关系,不能启动。我们换一个:
import uiautomator2 as u2
d = u2.connect_usb('127.0.0.1:62001')
d.app_start('com.wandoujia.phoenix2')
豌豆荚顺利启动了。
1.3 关闭app
那么我们连续操作,先打开,十秒后关闭:
import uiautomator2 as u2
import time
d = u2.connect_usb('127.0.0.1:62001')
d.app_start('com.wandoujia.phoenix2')
time.sleep(10)
d.app_stop('com.wandoujia.phoenix2')
运行后,那么这个app在我的终端开启十秒后又自动关闭。
1.4 打印设备信息
可以打印一下设备的信息:
print(d.device_info)
结果
{'udid': 'android-08:00:27:4a:c9:6f-Nexus', 'version': '4.4.2', 'serial': 'android', 'brand': 'samsung', 'model': 'Nexus', 'hwaddr': '08:00:27:4a:c9:6f', 'sdk': 19, 'agentVersion': '0.10.0', 'display': {'width': 900, 'height': 1440}, 'battery': {'acPowered': False, 'usbPowered': True, 'wirelessPowered': False, 'status': 5, 'health': 2, 'present': True, 'level': 90, 'scale': 100, 'voltage': 10000, 'temperature': 353, 'technology': 'Li-ion'}, 'memory': {'total': 1551104, 'around': '1 GB'}, 'arch': '', 'owner': None, 'presenceChangedAt': '0001-01-01T00:00:00Z', 'usingBeganAt': '0001-01-01T00:00:00Z', 'product': None, 'provider': None}
这个信息能够打印出来,说明我们连接成功了。里面又设备的各种信息,用时可以查看。
1.5 验证ui工作状态
我们可以验证ui的工作状态
print(d.service('uiautomator').running())
返回的是False,说明没有启动。那么我们启动一下再验证
d.uiautomator.start()
time.sleep(1)
print(d.service('uiautomator').running())
这时返回的是True。当然也可以暂停
d.uiautomator.start() # 开启服务
time.sleep(1)
print(d.service('uiautomator').running())
d.uiautomator.stop() # 服务暂停
time.sleep(1)
print(d.service('uiautomator').running())
打印结果是先True后False。
1.6 获取屏幕分辨率
下面我们操作获取屏幕的分辨率,获取分辨率可以获取某点的坐标定位,模拟一些行为动作。
print(d.window_size())
结果
(900, 1440)
1.7 获取手机IP
获取IP
print(d.wlan_ip)
运行后得到一个ip,但是不是一个真实的ip,是经过转换后的。如果是真机,这个IP是正确的,如果是模拟机,则不是正确的。
安装高德地图,电脑上下载好了高德地图的apk文件写好adb install将apk文件拖进来
C:\Users\MI>adb install C:\Users\MI\Downloads\9687c573432b9626936bc66afdb5cbc2.apk
回车
C:\Users\MI>adb install C:\Users\MI\Downloads\9687c573432b9626936bc66afdb5cbc2.apk
[100%] /data/local/tmp/9687c573432b9626936bc66afdb5cbc2.apk
pkg: /data/local/tmp/9687c573432b9626936bc66afdb5cbc2.apk
Success
C:\Users\MI>
安装成功。
高德地图有了。
1.8 用下载链接安装app
那么还有一种安装方法,是用下载连接安装的,比如我们在电脑段搜索“微读圣经”,然后再窗口点下载,然后在浏览器中点右上方的三个点,查看下载,复制下载链接
这里我已经复制好了
http://p.gdown.baidu.com/fc4118f547bec8764f23a12ffcab4062ad8686275c3f1056e9df2ed6dcb961ec241410100faed3db8f0a77d3d98794e2ad5935806c3ab1b0c4805095ed66b695e8753d1784aa63f7a40f4a3be3920c11bf68c4f2d573e246ea511bca47193b0f4dd4e14dc8d79310de78944f3903f3ea9f7a18374e4d61f91e0ab2ab7948efcf43317f25b5e60ec3186a5cb762a021ff70552863ca95964d477d3989961fec90ecbd2dca3bf30d4ca2b5b5dbe69993223c854dcee36197c82edfd1637ce8647e
写代码:
d.app_install(data='http://p.gdown.baidu.com/fc4118f547bec8764f23a12ffcab4062ad8686275c3f1056e9df2ed6dcb961ec241410100faed3db8f0a77d3d98794e2ad5935806c3ab1b0c4805095ed66b695e8753d1784aa63f7a40f4a3be3920c11bf68c4f2d573e246ea511bca47193b0f4dd4e14dc8d79310de78944f3903f3ea9f7a18374e4d61f91e0ab2ab7948efcf43317f25b5e60ec3186a5cb762a021ff70552863ca95964d477d3989961fec90ecbd2dca3bf30d4ca2b5b5dbe69993223c854dcee36197c82edfd1637ce8647e')
运行,需要稍等一会儿
D:\Python38\python.exe D:/work/爬虫/Day31/u2的基本操作.py
[D 210420 16:18:59 __init__:1303] pm install -rt /data/local/tmp/_tmp.apk
再看模拟器上已经安装好了微读圣经软件。
这是另一种安装方式。
也可以卸载,这里需要得到这个包的包名,用我们以前的方法:
adb shell pm list package
好像是这个:cc.vcjxiv.dsfcvowedshgnj
1.9 卸载app
我们编辑卸载的代码:
d.app_uninstall('cc.vcjxiv.dsfcvowedshgnj')
运行,程序结束后,模拟器上的app不见了。
1.10 获取当前活动app信息
获取当前app的信息,我先手动把豌豆荚打开,下面写代码获取这个app信息
print(d.app_current())
然后运行文件
{'package': 'com.wandoujia.phoenix2', 'activity': 'com.pp.assistant.activity.PPMainActivity'}
第一个是包名,第二个是目前属于主页的一个活动页面
获取app详细信息
print(d.app_info('com.wandoujia.phoenix2'))
运行
{'packageName': 'com.wandoujia.phoenix2', 'mainActivity': 'com.pp.assistant.activity.PPMainActivity', 'label': '豌豆荚', 'versionName': '7.10.32', 'versionCode': 21002, 'size': 17534509}
我们可以得到这个app更详细的信息。
清除app缓存
d.app_clear('com.wandoujia.phoenix2')
里面传入的参数仍然是包名。
1.11 卸载所有app
卸载所有第三方app
d.app_uninstall_all()
运行之后,发现高德地图,豌豆荚,微信所有非系统自带的app都被卸载了。
2. 开发一个简单app
下面我们看Activity和控件的操作。安卓的四大组件之一。当我们在一个地方安装好了app,会点击和使用。做一些基本操作。这些操作就在activity里,作用是显示view。是与用户交互的系统模块。如获取用户的账户名和密码。Activity 的控件TextView显示文字,EditText输入框,ImageView显示图片,Button按钮,CheckBox复选框,RadioButton单选按钮。我们通过一个案例来熟悉这些控件的用法。
需求:开发一个app,输入账号和密码,登录后会跳转到另一个页面,把我们输入的账号和密码显示出来。
这是一个简单的项目,一共是两个activity。
2.1 Android开发环境配置
需要安装安卓开发工具Android Studio,可以到官网去下载。安装步骤可以参考一个帖子。在安装Android Studio之前要先安装一个Java包,是Java的开发工具。
需要将javac.exe所在的路径添加到环境变量里面。
然后打开命令行窗口输入:javac回车
出现这个窗口说明安装成功。并且成功的配置了环境变量了。
2.2 Android Studio的使用
现在打开Android Studio
选第一个,创建一个新的安卓项目。
然后点next
我们选择默认的设置就可以了,选择next。完成后再点Next。
到了这一步就要选择一个activity,我们可以选择最基本的。默认是选择了一个空的activity,我们直接就用默认的,选择next
这两个名字都使用默认的就可以了。然后选finish,稍等一会儿
到了这一步直接点击close就可以了。
这个界面很像pycharm。我们在开始项目之前先运行一下,看看能不能用。点run下面的那个三角运行:
显示没有设备连接。我们打开命令行窗口输入以下命令来连接夜神模拟器设备:
nox_adb.exe connect 127.0.0.1:62001
回车
C:\Users\MI>nox_adb.exe connect 127.0.0.1:62001
adb server version (39) doesn't match this client (36); killing...
* daemon started successfully *
connected to 127.0.0.1:62001
C:\Users\MI>
连接成功。
这里已经出现了设备。我们先点ok一下,然后运行一下这个项目,运行后点一下模拟器看看打开了什么
由于我们什么还没有写,所以第一个activity出现的是hello world。已经有一个apk文件了,如果我们在手机上一安装,那么点开后就会出现这个界面。
2.3 设置视图
下面我们开始设置视图。
setContentView(R.layout.activity_main);
这个是设置视图的,我们按住Ctrl键点一下activity_main,点进去后我们可以看见:
我们点一下左下角的text就可以看见它的代码:
我们先把布局改成LinearLayout线性分布,因为我们的四个内容都是线性分布的。然后在第五行插入 android:orientation="vertical"垂直:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.lgedu.logicdemo6.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
我们可以看到helloworld跑到左上角了。
由于我们第一个是登录界面,我们把底部的四行代码去掉,文本改成“登录界面”,字体可以调大一点,并且居中:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登录界面"
android:textSize="30dp"
android:gravity="center"
/>
但是发现并没有居中,我们需要包第一句改成匹配封装体: android:layout_width=“match_parent”
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="登录界面"
android:textSize="30dp"
android:gravity="center"
/>
这次居中了
2.4 输入框设置
距离第一个窗口25dp我们放下一个输入框:
android:layout_marginTop="25dp"
完整的
<TextView
android:id="@+id/et_username" // 用来接受数据
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入名子"
android:textSize="30dp"
android:gravity="center"
android:layout_marginTop="25dp"
/>
hint是显示要输入的内容,当你输入内容时会取代之前显示在表面的文字。第一句是id值,需要这个值来传递输入内容。
下面是密码:
<TextView
android:id="@+id/et_userpwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入密码"
android:textSize="30dp"
android:gravity="center"
android:layout_marginTop="25dp"
/>
下面是登录按钮
<Button
android:id="@+id/bt_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登录"
android:textSize="30dp"
android:gravity="center"
android:layout_marginLeft="245dp"
android:layout_marginTop="25dp"
/>
android:layout_marginLeft="245dp"是向右移动245dp,也就是左边里边缘245dp。
我们先运行一下,看看效果。发现不能输入姓名和密码进行编辑,这是因为这里需要修改
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入名子"
android:textSize="30dp"
android:gravity="center"
android:layout_marginTop="25dp"
/>
<EditText
android:id="@+id/et_userpwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入密码"
android:textSize="30dp"
android:gravity="center"
android:layout_marginTop="25dp"
/>
变成<EditText后才能编辑。再次运行后就可以输入了。
3. 实现活动界面
下面我们来实现loginactivity,需要新创建一个acitivity,具体方法是右键我们的项目:
然后点击New>Activity>Empty Activity
我们命名为LoginActivity
点Finish创建。
3.1 实现Activity_login.xml中的逻辑
我们进入了第二个界面,点击Activity_login.xml来编辑
做和前面类似的修改:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.lgedu.logicdemo6.LoginActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="你好"
android:textSize="30dp"
android:gravity="center"
android:layout_marginTop="25dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="哈哈"
android:textSize="30dp"
android:gravity="center"
android:layout_marginTop="25dp"
/>
</LinearLayout>
因为后面我们要操作,后面要加上id
<TextView
android:id="@+id/u_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="你好"
android:textSize="30dp"
android:gravity="center"
android:layout_marginTop="25dp"
/>
<TextView
android:id="@+id/u_pwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="哈哈"
android:textSize="30dp"
android:gravity="center"
android:layout_marginTop="25dp"
/>
3.2 写mainactivity.java里面的逻辑
到mainactivity.java里面实现逻辑共分三步:
- 找控件:初始化控件
- 操作控件
- 设置控件
代码是这样写的:
package com.example.lgedu.logicdemo6;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化控件
final EditText et_username = (EditText) findViewById(R.id.et_username);
final EditText et_pwd = (EditText) findViewById(R.id.et_pwd);
Button bt_login = (Button) findViewById(R.id.bt_login);
// 点击事件
bt_login.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String name = et_username.getText().toString();
String pwd = et_pwd.getText().toString();
// 跳转页面
Intent intent = new Intent(MainActivity.this,LoginActivity.class);
// 携带数据
intent.putExtra("name",name);
intent.putExtra("pwd",pwd);
startActivity(intent);
}
});
}
}
3.3 写LoginActivity.java里的逻辑
再来到LoginActivity.java里写一下逻辑如下:
package com.example.lgedu.logicdemo6;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// 初始化控件
TextView u_name = (TextView) findViewById(R.id.u_name);
TextView u_pwd = (TextView) findViewById(R.id.u_pwd);
// 获取数据
Intent intent = getIntent();
String name = intent.getStringExtra("name");
String pwd = intent.getStringExtra("pwd");
// 设置数据
u_name.setText(name);
u_pwd.setText(pwd);
}
}
3.4 运行查看结果
我们运行一下看看怎么样,运行程序结束后,点开模拟器,在界面里输入名字和密码:
点登录
结果获取了数据。
以上是简单的开发一个app,让大家了解一下安卓开发。
4. weditor
U2给我们提供了一个图形界面的可视化操作工具weditor。
4.1 weditor的安装
需要先安装:
pip install weditor -i https://pypi.tuna.tsinghua.edu.cn/simple/
# 采用了换源安装,后面是清华源
在命令行窗口输入以上命令回车
... ...
Requirement already satisfied: py<2.0.0,>=1.4.26 in d:\python38\lib\site-packages (from retry->facebook-wda>=1.0.5->weditor) (1.10.0)
Installing collected packages: tornado, facebook-wda, weditor
Successfully installed facebook-wda-1.4.0 tornado-6.1 weditor-0.6.3
说明安装成功。
4.2 weditor的开启
启动weditor,先确定有没有设备连接
C:\Users\MI>adb devices
List of devices attached
127.0.0.1:62001 device
有这么个设备,输入weditor回车,启动。
4.3 weditor的工作界面介绍
出现了这样的界面。我重新打开一个谷歌浏览器,把地址复制进去,效果更好的
- 最左边的是移动设备选取区域。
- 中间是控件属性区域。
- 右边是代码展示区域。
- 右下方是层级关系及结果展示区域。
点击connect连接,如果后面显示绿色树叶证明连接成功。后面的Dump Hierarchy点击刷新。刷新后的页面是和我们的移动设备显示的相同的。通过weditor我们就可以操作移动设备里面的app了。今天先掌握这么多。