Appium 自动测试,读书打卡(日志)
1.准备工作
1.1了解Appium 自动测试
Appium 官方链接:https://appium.io/docs/en/about-appium/intro/。
1.2软件安装
1.JDK
2.Android SDK
下载链接:https://www.androiddevtools.cn/。
在配置环境变量时,遇到以下问题。
(1)在配置Android SDK 环境时,发现没有找到adb.exe文件,后来查找资料,发现是没有platforms-tools。如下图所示。
(2)上网搜索可能原因,有人说可能是platform-tools在安装时被误删,打开 Android SDK Manager看看platform-tools是否被误删,发现果然被误删了。
(3)安装platform-tools。
(4)配置环境变量。
(5)配置系统环境变量。
(6)在命令行测试Android SDK 环境安装成功。
参考博客链接:https://www.csdn.net/tags/MtjaggzsNTc4MjktYmxvZwO0O0OO0O0O.html。
3.Appium
下载完成后操作
(1)双击Appium进行安装,安装完成后,出现以下界面。将Host设置为127.0.0.1,Port设置为4723,如果没有配置JDK或者ANDROID_HOME环境变量,需要点击“Edit Configurations”处。
(2)如果忘记了是否配置了环境,可以点击“Edit Configurations”进行查看,由于我是环境都配置完成了,所以这里会自动填写上。
(3)开启服务,进入到服务界面。看到欢迎你,Appium的客户端就算完成了。
4.夜神模拟器
下载链接:https://www.yeshen.com/。
1.2说明
本项目只用于技术讨论。
2.需求分析
手机上的读书软件,自动完成读书并打卡。这里需要先找到读书软件,然后点击读书软件,在读书软件中找到需要阅读的书籍,点击需要阅读的书籍,每隔固定时间滑动屏幕进行翻页,设置固定阅读总时长,到达总时长后,结束阅读。在当前页面中找到页码和总页码,读出来这两个量。进行读书打卡。
3.技术原型
1.appium读app
2.appium点击屏幕
3.appium滑动屏幕
4.识别固定位置上的数字
4.实验
4.1Appium连接安卓模拟器
4.1.1实验目的
了解Appium是如何和安卓模拟器连接的。
4.1.2实验内容
4.1.2.1准备工作
1.进入模拟器中的设置,找到安卓版本号位置,多次点击。进入开发者模式。
2.多次点击后,会提示进入到开发者模式。
3.查看Android SDK的adb版本。
4.进入模拟器bin目录下,执行nox_adb.exe version,查看adb版本。发现两者的版本不一致。如果版本不一致,需要把Android SDK下的adb版本复制到模拟器bin目录下。并把Android SDK下的adb重新命名为nox_adb。
5.当把Android SDK下的adb重新命名为nox_adb后,复制到模拟器bin目录下后,访问被拒绝。
6.然后我把原来模拟器bin目录下nox_adb.exe删除。就能复制过去。
7.再次查看模拟器下的adb版本,发现和Android SDK下的adb版本版本一致。
8.连接模拟器,发现无法连接。
解决无法连接问题。
参考链接: https://blog.csdn.net/DaisyCold/article/details/111477842 。
(1)查看别人博客显示我少复制了两个文件。把Android SDK安装目录下画红框位置的两个文件也复制到模拟器bin目录下。
(2)在模拟器bin目录下替换复制过来的文件。
(3)再次查看adb版本,发现两个版本一致了。
(4)再次连接,连接成功。
4.1.2.2创建Maven项目
1.点击file下创建新的Maven项目。
2.选择创建一个简单的工程。
3.填写信息。
4点击完成后报错。显示无效的工程描述,信息如下。
5.查找原因,说创建Maven时不能选择新的工作空间,需要选择默认的工作空间。选择默认的工作空间后,创建成功。
4.2.1.3安装Maven
1.下载链接:https://maven.apache.org/download.cgi 。
2.配置环境变量。
参考链接:https://www.runoob.com/maven/maven-setup.html 。
3.测试maven环境是否配置成功,输入mvn -version,显示版本信息,表示配置成功。
4.1.2.4Maven安装Java-client
Java-client连接:https://mvnrepository.com/ 。
1.打开Maven Repository,搜素Appium。找到Java Client。
2.点击Java Client,复制依赖。
3.在项目中的pom.xml文件中复制依赖。
4.eclipase配置Maven。如下图所示。找到eclipse中Windown下的preferences,第一步在Maven下找到Installations并点击,第二步点击Add,第三步选择Maven的安装路径。
5.编写测试代码。
import org.openqa.selenium.remote.DesiredCapabilities; import io.appium.java_client.android.AndroidDriver; public class TestApp1 { public static void main(String[] args) throws MalformedURLException, InterruptedException { DesiredCapabilities capabilities = new DesiredCapabilities(); // 模拟器类型 // capabilities.setCapability("deviceName", "Android Emulator"); capabilities.setCapability("deviceName", "device"); // 自动化测试引擎 capabilities.setCapability("automationName", "Appium"); // 手机操作系统Android capabilities.setCapability("platformName", "Android"); // 手机操作系统版本号 capabilities.setCapability("platformVersion", "7.1.2"); // app包名 capabilities.setCapability("appPackage", "com.android.settings"); // app中启动的Activity名称 capabilities.setCapability("appActivity", ".Settings"); AndroidDriver driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities); driver.quit(); } }
4.1.2.5解决程序错误
使用代码测试能否启动模拟器中的设置,目前报错信息如下。
4.1.2.5.1问题一
1.猜测是代码中的包名或者其他信息填写错误,检查一遍代码,排查了这个可能性。然后又针对报错信息,一条一条的看。先解决第一个问题。
2.查找原因,网上好多说是需要添加依赖,然后就添加了以下的依赖。参考链接:https://blog.csdn.net/zhizhengguan/article/details/103312010 。
4.1.2.5.2问题二
1.解决完问题一后,下面解决问题二。如下图所示。
2.寻找解决办法,跟着添加了一堆依赖,也还是报错。
<!-- 错误依赖--> <!-- <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.141.59</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>22.0</version> </dependency> -->
3.不知道该怎么办了,就查看了Appium,发现这里也有一些信息,而且有以下几个问题,好像是缺少一些东西。
4.我其实并不知道缺少的是什么,我在我电脑上搜索是否真的没有这个文件。然后就发现有这个文件。
5.我以为是目录不对,按照提示的目录找了一下,还是存在缺少的apk。到这里我卡主了,我不知道问题出在了哪里。
6.然后我又看了一下是否还存在其他问题,解决又找到了新的问题。
7.通过查看别人解决方案,发现build-tools/目录下应该有“apksigner.jar”文件但是我电脑上没有。
8.我上网想下个“apksigner.jar”,但是我找了半天不是找不到,就是要花钱,所以我放弃这个想法了。
9.然后我看到一个博客中的解决方法,里面是复制build-tools下的apksigner.jar,我记得昨天android SDK里面缺少东西时,在SDK Manager.exe中安装过platform-tools。
10.然后我想着在SDK Manager.exe中是不是也可以找到build-tools,打开SDK Manager.exe后,真的找到了,然后下载。
4.1.2.5实验结果
运行java程序,打开了设置。
4.2 Appium点击出现的代码问题
1.在调试代码时,这里出现了报错。这里是不支持这两个参数。
2.查找资料,需要把坐标以point对象的形式放到Tap方法中才可以。
参考链接:https://blog.csdn.net/hccgk/article/details/103169057/ 。
4.3 Appium滑动出现的代码问题
1.想使用swipe方法实现互动效果,但是编写以下代码,然后报错,如下图
2.看来swipe已经不能使用了。
4.4 Appium定位元素出现的问题
1.使用Appium Inspector获取设置中WLAN选项的ID时,出现以下问题,没有找到WLAN选项的ID,只能找到WLAN选项的xpath,如下图所示。
2.在查阅了一些资料说resource-id是选择元素的ID,但是经过我的实验,其他的元素也是这个ID。比如蓝牙的ID。
3.又对比了其他元素的其他属性,发现只有Text属性不一样。
4.查找原因,是因为上面是查看的布局ID。需要查看选择中标签的ID。
5.写完正确ID后,编写代码,报没有findElementById()的方法,尝试了其他的定位属性,也没有。
6.上网搜索好久也没有找到解决办法,猜测是不是版本的问题。然后降低版本。降低版本后AndroidDriver又不兼容。
7.把java-client改成7.6.0版本。
8.报以下的错误,不能创建远程会话。
9.查看日志。发现以下三处问题。
10.搜索原因,看到有一个说降低Appium版本。我尝试降低了Appium版本。结果真的好了。
4.5 Appium识别元素出现的问题
1.网上搜索资料,一开始找到的是使用getText()方法,但是我在获取WLAN的值时获取不到。
2.我尝试了其他几种获取属性值的方法,发现只有getAttribute(“className”)方法可以获取到值。
3.又查找资料,看到有一个获取界面资源代码的方法,可以获取到界面的代码。
driver.getPageSource()//获取到界面代码
4.实在找不到啥方法可以获取到属性值的方法,我想了一下界面代码都有了,要是我按照id先找到所需属性所在行,然后再取出所需值就可以。按照以下代码,把界面代码按行分割,然后在每行中匹配所需id。
String resource_origin = driver.getPageSource();//获取到界面代码 String[] resources = resource_origin.split("\n"); for (String str : resources) { int intIndex = str.indexOf(wifi_id); if (intIndex != -1) { System.out.println("找到: " + str); } }
5.先找到所需代码所在行,运行程序看一下效果,才发现,原来这个id不是唯一的,同时也明白了为啥一开始使用getText()获取不到值的。因为ID不唯一,而第一个匹配上的ID中的内容就是空,所以一直获取不到。
6.怀疑其他软件的ID唯一,打开微信读书,查看ID,发现ID是唯一的。
7.后来使用微信读书获取所需ID的文本内容。
5.实现
5.1出现的问题
1.微信读书中没有ID,选用了xpath来找到书籍。
2.微信读书获取不了页码,点击页码时,会全选,不能单独选择页码,也就获取不了ID或者xpath。
3. 获取界面代码,查看页面是以什么形式存在界面中的。
4.查看页面代码,没有发现里面包含页码信息。
5.再找了一圈之后,我发现这可能是一张图片,但是又不像图片。然后我放弃了使用属性获取内容,打算换技术路线,使用图片识别技术。
5.2获取页码思路
使用图片识别图中文字,需要经过以下两个步骤,第一步图片分割。第二步识别图中的文字。
5.2.1识别图片问题
5.2.1.1使用百度API
1.添加以下代码的依赖。
<dependency> <groupId>com.baidu.aip</groupId> <artifactId>java-sdk</artifactId> <version>4.8.0</version> </dependency>
2.注册登录百度智能云,创建一个应用,创建完需要等待三十分钟。
3.复制以下代码。(未完成,因为有的包不能导入,然后放弃了这个方法)
/**
* @describe 识别图片上的文字
* 官方文档:https://ai.baidu.com/ai-doc/OCR/Ikibizxql
*/
public class Word {
// 设置APPID/AK/SK
public static final String appId = "你的 App ID";
public static final String apiKey = "你的 Api Key";
public static final String secretKey = "你的 Api Key";
public static final AipOcr client = new AipOcr(appId, apiKey, secretKey);
/*
* 文字识别方法
*/
public static String imgOcr(String imgpath)
{
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<String, String>();
options.put("language_type", "CHN_ENG");
options.put("detect_direction", "true");
options.put("detect_language", "true");
options.put("probability", "true");
// 参数为本地路径
JSONObject res = client.basicGeneral(imgpath, options);
//解析json
JSONArray wordsResult = (JSONArray)res.get("words_result");
String ocrStr = "\n";
StringBuffer sb=new StringBuffer();
for(Object obj : wordsResult)
{
JSONObject jo = (JSONObject)obj;
sb.append(jo.getString("words") + "\n");
}
return sb.toString();
}
public static void main(String[] args) throws AWTException, IOException {
String s = StartApp.imgOcr("C:\\Users\\Administrator\\Desktop\\sw_image\\a.png");
System.out.println(s);
}
5.2.1.2使用软件包识别图片文字
1.运行程序后,出现以下界面。
2.配置环境变量后,在命令行中输入tesseract后,出现以下信息则代表环境变量配置完成。
3.运行程序后,还是报原来的错误。这里找了好久问题。又重新安装了Tesseract-OCR 。
4.最终发现了问题。这里有两个原因导致的报错,一是安装目录中不能有非法字符(在我第一次安装时,安装路径中多了空格)。二是在安装时,没有安装语言包(第一次安装时没有勾选语言包),导致识别不了。
5.2完善项目问题
5.2.1设定每页读书间隔
1.在确定需要设置两个固定时间后,先设置每页阅读40s,先尝试阅读120s,但是运行程序时,发现没有获取到页码,一开始以为机器没有睡醒,多运行几次还是这样。然后找到截图,发现截图也不正确。如下图所示。后来一直摁撤回,还原到昨晚好使的代码,但是运行程序还是获取不到页码,截图还是下面截图。
2.想着可能是模拟器有问题,重新打开模拟器,再次运行程序,发现读书界面也没有打开(就像网不好,一直显示加载)。后来又运行了几次,可以打开微信读书了,但是截图还是上门的截图。
3.我感觉我代码被猫吃了,吓的我把电脑关机重启,所有软件都关闭重新打开。
4.我猜测是网络不好,换成手机的网络,运行程序后,还是上面截图的效果。
5.我把网络关闭,运行程序,也能打开模拟器,并且截图是上面的截图。
6.我不知道这是什么原因导致的,我又猜测是模拟器坏了,卸载模拟器,重新安装,运行程序,但是不能创建一个新的远程会话。
7.查看是否是两个版本的adb不一致。果然是两个版本不一致,但是我已经把Android SDK下的adb版本复制到模拟器bin目录下啊。
8.我感觉可能是自己脑子坏了,再重新替换一下。再次查看版本,这次版本一致了。
9.运行程序报错。
10.在命令行查看是否连接。
11.启动Appium,运行程序。发现截图还是花的图片。
12.排除了是模拟器的原因,难道是因为微信读书还没有结束就开始截图吗,但是程序执行不应该是从上到下嘛?设定的是先滑动界面,等到一段时间然后再截图啊,而且昨天为啥好好的啊,这里也没有牵扯网络异步啊。
13.我突然又想到是不是真的是等待时间的问题,抛开项目,只打开微信,查看截图是否会改变。
14.发现截图这次真的变了,而且裁剪图片效果也是对的。所以问题可能真的出在等待时间上。
14.上网搜索“appium等待页面渲染完成执行方法”,发现有三种等待方式,都试了一下,发现生成的图片还是错误的图片。而在每次查看截图时,突然发现了以下的效果,从截图中可以看出,当前页面的文字应该是被截到了,但是却多了书架界面,两个界面重合在一起了。
15.修改noReset,本来想修改成false,目的是测试截图是否正确,却发现设置成true时,没有加双引号,加上双引号后,运行程序,程序可以正确截图并获取页码了。
16.然后把滑动代码加上后,截图还是显示的两个图片的混合。所以这里猜测是或许是滑动和截图在时间上冲突了。
17.把等待时间加大,并且添加以下等待渲染需要阅读的内容,运行程序,查看效果。
// 等待元素出现 public static void waitElement(final AndroidDriver driver) { // driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); WebDriverWait web = new WebDriverWait(driver, 10); WebElement webElement = web.until(new ExpectedCondition<WebElement>() { public WebElement apply(WebDriver input) { return driver.findElementByXPath( "/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout\r\n"); } }); // webElement.click(); }
18.在多次运行中,有时截图是正确的,能获取到页码,但是有时就不能获取到正确截图。
19到目前位置,做不下去了。
5.2.2获取正确截图
1.等待足够长的时间后,再截图,但是发现截图后的效果还是花的图片。
2.使用Thread.sleep()来阻塞页面,等滑动完微信读书后才开始截图。但是运行的效果是个1中一样的效果。
3.使用回调函数。运行程序后,还是和1中一样的效果。
public static void waitElement(final AndroidDriver driver) { // driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); WebDriverWait web = new WebDriverWait(driver, 10); WebElement webElement = web.until(new ExpectedCondition<WebElement>() { public WebElement apply(WebDriver input) { return driver.findElementByXPath( "/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout\r\n"); } }); // webElement.click(); }
4.后来,我把滑动页面的方法去掉,查看截图是否正常。运行程序后发现截图是正常的,但是添加上滑动代码,截图就不正确了。我实在搞不明白这是为啥。添加滑动界面代码生成的图如下图左边第一张和第二张所示,去掉滑动界面代码生成的图如下图左边第三张和第四张所示。
5.我猜测这个原因可能已经和时间没有关系,或许是别的原因啥的,但是我也不知道啥原因。
5.2.3微信打卡
1.当获取到页码后,需要把页码发到微信固定的群里,然后自动实现打卡,但是在打卡时,程序一直运行报错。
2.这里发现是因为微信读书和微信的包名还有启动页acitivity 不一样,即微信和微信读书的这两个参数是不一样的。
3.获取微信driver单独写一个方法。
// 获取微信driver public static AndroidDriver getWechatDriver() throws Exception { DesiredCapabilities capabilities = new DesiredCapabilities(); // 模拟器类型 // capabilities.setCapability("deviceName", "Android Emulator"); capabilities.setCapability("deviceName", "device"); // 自动化测试引擎 capabilities.setCapability("automationName", "Appium"); // 手机操作系统Android capabilities.setCapability("platformName", "Android"); // 手机操作系统版本号 capabilities.setCapability("platformVersion", "7.1.2"); // app包名 capabilities.setCapability("appPackage", "com.tencent.mm"); // app中启动的 Activity名称 capabilities.setCapability("appActivity", ".ui.LauncherUI"); capabilities.setCapability("automationName", "uiautomator2"); // noReset设置 capabilities.setCapability("noReset", "true"); // 设置appium可以输入中文 capabilities.setCapability("unicodeKeyboard", "true"); AndroidDriver driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities); return driver; }
6.PSP