1. 触屏操作 === touchaction + 九宫格
2. h5:混合应用 === 原生控制 + html
3. toast信息
1. appium-模拟触屏
TouchAction类:将一系列的动作放在一个链条中,然后将该链条传递给服务器,服务器接受到该链条后,解析各个动作,逐个执行;
短按(press)
长按(lognPress)
点击(tap)
移动到(move_to) x,y为相对上一个坐标的移动距离
等待(wait)
释放(relase)
执行(perform)
取消(cancel)
2. 手机的手势密码(九宫格)因为整个九宫格是一个图片元素,而不是每个点就是一个元素,故在定位九宫格时只能通过坐标位置定位所画的图是从哪个点移移动到哪个点了;
3. 获取元素的坐标起点:ele.location;获取元素的大小:ele.size
```python
import time
from appium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.common.touch_action import TouchAction
desired_caps = {}
desired_caps["platformName"] = "Android"
desired_caps["platformVersion"] = "6.0"
desired_caps["deviceName"] = "Android Emulator" #该参数无实际作用意义,但是仍需配置
desired_caps["noReset"] = True
desired_caps["appPackage"] = "com.xxzb.fenwoo" #前途贷app
desired_caps["appActivity"] = "com.xxzb.fenwoo.activity.addition.WelcomeActivity"
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
time.sleep(5)
#1. 点击我,为什么我不能用id定位 'com.xxzb.fenwoo:id/iv_tab'
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.XPATH, '//android.widget.TextView[@text="我"]')))
driver.find_element_by_xpath('//android.widget.TextView[@text="我"]').click()
#2.登录 -- 输入手机号,点击下一步
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.ID,'com.xxzb.fenwoo:id/et_phone')))
driver.find_element_by_id('com.xxzb.fenwoo:id/et_phone').send_keys('18684720553')
driver.find_element_by_id('com.xxzb.fenwoo:id/btn_next_step').click()
#3.登录 -- 输入密码,点击确定
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.ID,'com.xxzb.fenwoo:id/et_pwd')))
driver.find_element_by_id('com.xxzb.fenwoo:id/et_pwd').send_keys('python')
driver.find_element_by_id('com.xxzb.fenwoo:id/btn_next_step').click()
#4.点击安全中心
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.ID,'com.xxzb.fenwoo:id/textView11')))
driver.find_element_by_id('com.xxzb.fenwoo:id/textView11').click()
#5.点击手势密码 -- 未启用
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.ID,'com.xxzb.fenwoo:id/tv_gesture_result')))
driver.find_element_by_id('com.xxzb.fenwoo:id/tv_gesture_result').click()
#6.开启手势密码
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.ID,'com.xxzb.fenwoo:id/switch_gesture')))
driver.find_element_by_id('com.xxzb.fenwoo:id/switch_gesture').click()
#7.创建手势密码
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.ID,'com.xxzb.fenwoo:id/btn_gesturepwd_guide')))
driver.find_element_by_id('com.xxzb.fenwoo:id/btn_gesturepwd_guide').click()
#8.如何绘制手势密码 -- 确定
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.ID,'com.xxzb.fenwoo:id/right_btn')))
driver.find_element_by_id('com.xxzb.fenwoo:id/right_btn').click()
#9.绘制手势手势密码
#定位九宫格
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.ID,'com.xxzb.fenwoo:id/gesturepwd_create_lockview')))
ele = driver.find_element_by_id('com.xxzb.fenwoo:id/gesturepwd_create_lockview')
#获取元素的坐标起点:ele.location
start_point = ele.location
#获取元素的大小:ele.size
ele_size = ele.size
#appium server的1.7.2以后版本,move_to()方法的x,y是绝对坐标,即相对于整个屏幕的坐标位置
#获取九宫格第一个点的坐标
# point_1 = (start_point['x'] + 1/6 * ele_size['width'],start_point['y'] +1/6 * ele_size['height'])
# point_2 = (start_point['x'] + 1/2 * ele_size['width'],start_point['y'] + 1/6 * ele_size['height'])
# point_3 = (start_point['x'] + 5/6 * ele_size['width'],start_point['y'] + 1/6 * ele_size['height'])
# point_4 = (start_point['x'] + 1/2 * ele_size['width'],start_point['y'] + 1/2 * ele_size['height'])
# point_5 = (start_point['x'] + 1/2 * ele_size['width'],start_point['y'] + 5/6 * ele_size['height'])
#appium server1.7.2版本以下,move_to()方法的x,y是相对于前一点移动的相对距离
##第一点的位置是绝对位置,相对整个屏幕的坐标,因为第一个点是通过press()方法执行的,这个方法的x,y是绝对坐标
point_1 = (start_point['x'] + 1/6 * ele_size['width'],start_point['y'] +1/6 * ele_size['height'])
point_2 = (2/6 * ele_size['width'],0) #从第2点开始传相对前一个点的距离
point_3 = (2/6 * ele_size['width'],0)
point_4 = (-2/6 * ele_size['width'],2/6 * ele_size['height'])
point_5 = (0,2/6 * ele_size['width'])
#从第1点移动到第2个点,移动到第3个点,移动到第5个点,移动到8个点,之后释放以完成画图
TouchAction(driver).press(x=point_1[0],y=point_1[1]).wait(300).
move_to(x=point_2[0],y=point_2[1]).wait(300).
move_to(x=point_3[0],y=point_3[1]).wait(300).
move_to(x=point_4[0],y=point_4[1]).wait(300).
move_to(x=point_5[0],y=point_5[1]).wait(300).
release().perform()
```
4.appium server的1.7.2以后版本,move_to()方法的x,y是绝对坐标,即与元素起点位置的坐标加上移动的距离,之前的版本x,y是相对移动的距离;
5. **Toast提示信息获取:**
1> appium server版本1.6.3+才支持toast获取;
2> 代码中必须指定automationName为UIAutomator2,即desired_caps["automationName"] = "UiAutomator2";
3> UIAutomator2只支持安卓版本5.0+,因此夜神模拟器,海马王都用不了,因为他们最高支持安卓版本为4.4.2,可以使用genymotion模拟器;
4> 要求安装jdk1.8 64位及以上,配置其环境变量JAVA_HOME和path
7. toast定位方法只能使用xpath,xpath表达式:xpath='//*[contains(@text,"部分文本内容")]',且driverWait方法中,请用presence_of_element_located,不要用visibility_of_element_located,对toast的可见处理并不支持,会直接报错,命令无法执行;
**注意:这里使用是@text属性,而web是text()函数,如在web中的元素定位://li[text()="南昌"]**
```python
import time
from appium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.common.touch_action import TouchAction
desired_caps = {}
desired_caps["automationName"] = "UiAutomator2"
desired_caps["platformName"] = "Android"
desired_caps["platformVersion"] = "6.0"
desired_caps["deviceName"] = "Android Emulator" #该参数无实际作用意义,但是仍需配置
desired_caps["noReset"] = True
desired_caps["appPackage"] = "com.xxzb.fenwoo" #前途贷app
desired_caps["appActivity"] = "com.xxzb.fenwoo.activity.addition.WelcomeActivity"
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
time.sleep(5)
#点击注册登录
WebDriverWait(driver,30).until(EC.visibility_of_element_located((MobileBy.ID,'com.xxzb.fenwoo:id/btn_login')))
driver.find_element_by_id('com.xxzb.fenwoo:id/btn_login').click()
#输入手机号
WebDriverWait(driver,30).until(EC.visibility_of_element_located((MobileBy.ID,'com.xxzb.fenwoo:id/et_phone')))
driver.find_element_by_id('com.xxzb.fenwoo:id/et_phone').send_keys('18600001100')
#点击下一步
driver.find_element_by_id('com.xxzb.fenwoo:id/btn_next_step').click()
toast_part = "验证码已经发送到"
toast_xpath = '//*[contains(@text,"{0}")]'.format(toast_part)
try:
#等待toast存在,因为toast不支持可见
WebDriverWait(driver,20,0.2).until(EC.presence_of_element_located((MobileBy.XPATH,toast_xpath)))
#获取toast的文本内容
toast_text = driver.find_element_by_xpath(toast_xpath).text
print("找到了toast,内容为:{0}".format(toast_text))
except:
print("我错过了toast....")
raise
```
###混合应用自动化解决方案
2018.11.8学习
1. 安卓的原生控制native,可以通过UiAutomatorViewer定位到;app应用中能查看到html页面即为混合应用app,如豆瓣,微信的公共号,淘宝,小程序不一定是混合应用
2. 通过UiAutomatorViewer定位到的元素class为android.webview,或是content-desc为网页视图,H5等,就是html页面
3. hybird混合应用自动化方案:
1> 基于UiAutomator + Chromedriver:native部分则UiAutomator,webview部分则chromedriver,二者结合起来
2> 要求:android4.4+,webview必须为debug版本
4. 获取webview页面的四种方式:
1> chrome://inspect,但是需要能FQ(翻墙)
2> 使用driver.page_sourcea获取html页面到本地,再找开用F12定位
3> 找开发人员要源html文件
4> uc-devtools工具,不需要FQ (常用)
5. 上下文切换:即app应用打开后是在native原先组件中,当需要进入html页面功能时,就会进入webview,即上下文
6. 常见问题:
contexts只能获取NATIVE_APP,无法获取WEBVIEW?
使用UiAutomatorView定位元素,显示class值为:android.webkit.WebView,但是driver.contexts只打印出了“NATIVE_APP”
解决方法:
1> app打包的时候需要开启webview的debug属性setWebContentDebuggingEnabled(true),这个直接让开发加上就好;
2> 模拟器的contexts中有webview,但有些手机没有,官方的答案是;需要将手机root,然后再去获取;
7. 若想操作webview,就必须先从native切换到webview,再通过chromedriver来定位html中的元素,从而操作html元素;
1> 获取所有可用的上文:driver.contexts
2> 获取当前上下文:driver.current_context
3> 切换至默认的上下文:driver.switch_to.context(None),一般就是原生的上下文“NATIVE_APP”
4> 获取当前的Activity(仅支持android):driver.current_activity
5> 获取当前包名(仅支持android):driver.current_package
9. app中的hybird页面元素定位工具:uc-devtools,将app进入到h5页面,再开启uc-devtools工具即可定位html页面中的任何元素;
**uc-devtools打开后,能看到一条信息:com.lemon.lemonban (40.0.0.0),40.0.0.0代表anroid手机中的webview版本(相当于chrome浏览器的版本),此时需要去下载对应的chromedriver版本,查看网面http://npm.taobao.org/mirrors/chromedriver/2.12/notes.txt,知道需要下载的chromedriver版本为2.11或2.12或2.13**
10. 放下载的chromedriver放到目录:C:UsersqiucaixiaAppDataLocalProgramsappium-desktop
esourcesapp
ode_modulesappium
ode_modulesappium-chromedriverchromedriverwin (即appium desktop的目录下)
11. 总结app要操作h5页面上的元素过程:
1> 先确认页面当中是否有webview元素
2> 有webview元素时,开启app的webview debug模式,且android要4.4+以上
3> 模拟器/真机进入到有webview的页面
4> 使用driver.contexts获取所有的上正文
5> 用driver.switch_to.context(webview名称)切换到html页面中
6> 查找html的元素工具:uc-devtools 找到要操作的元素 确认定位表达式
7> chromdriver要与安卓的webview版本匹配,才可以驱动html页面定位元素,操作元素
8> 去chromdriver下载对应的驱动版本
9> 更换appium当中的chromdriver程序,目录为C:UsersqiucaixiaAppDataLocalProgramsappium-desktop
esourcesapp
ode_modulesappium
ode_modulesappium-chromedriverchromedriverwin
```python
import time
from appium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.common.touch_action import TouchAction
desired_caps = {}
desired_caps["platformName"] = "Android"
desired_caps["platformVersion"] = "6.0"
desired_caps["deviceName"] = "Android Emulator" #该参数无实际作用意义,但是仍需配置
desired_caps["noReset"] = True
desired_caps["appPackage"] = "com.lemon.lemonban" #柠檬班app
desired_caps["appActivity"] = "com.lemon.lemonban.activity.WelcomeActivity"
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
time.sleep(5)
#1.先确认页面当中是否有webview元素
#2.有webview元素时,开启app的webview debug模式,且android要4.4+以上
#3.模拟器/真机进入到有webview的页面
#4.使用driver.contexts获取所有的上正文
#5.用driver.switch_to.context(webview名称)切换到html页面中
#6.查找html的元素工具:uc-devtools 找到要操作的元素 确认定位表达式
#7.chromdriver要与安卓的webview版本匹配,才可以驱动html页面定位元素,操作元素
#8.去chromdriver下载对应的驱动版本
#9.更换appium当中的chromdriver程序,目录为C:UsersqiucaixiaAppDataLocalProgramsappium-desktop
esourcesapp
ode_modulesappium
ode_modulesappium-chromedriverchromedriverwin
#点击全程班
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.ANDROID_UIAUTOMATOR,'new UiSelector().text("全程班")')))
driver.find_element_by_android_uiautomator('new UiSelector().text("全程班")').click()
#等待webview页面可见
WebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.CLASS_NAME,'android.webkit.WebView')))
#等待html页面的元素加载一下
time.sleep(5)
#page = driver.page_source
#获取当前的context
print("当前的context:",driver.current_context)
#获取所有的上下文,以列表形式返回
all_contexts = driver.contexts
print(all_contexts)
#切换到html页面上 (WEBVIEW_com.lemon.lemonban)
#driver.switch_to.context("WEBVIEW_com.lemon.lemonban")
driver.switch_to.context(all_contexts[-1])
#收藏按键
WebDriverWait(driver).until(EC.visibility_of_element_located((MobileBy.ID,'js-bottom-fav')))
driver.find_element_by_id('js-bottom-fav').click()
```