一、滑屏操作
不需要看到歡迎頁(yè)面,直接做里面的后續(xù)操作就好了。也就是我想記住一些用戶的習(xí)慣, 不要像第一次訪問(wèn)一樣,有一個(gè)重置與否,給它關(guān)閉了。
# 重置與否
desired_caps["noReset"]=True
1.訪問(wèn)之后,馬上就滑屏可以嗎?
不可以。先等待首頁(yè)有個(gè)元素出現(xiàn),再去滑屏。滑屏操作需要時(shí)間,模擬器或者真機(jī)執(zhí)行操作更需要時(shí)間。如果直接滑動(dòng) 2 次,第一次滑動(dòng)效果還沒(méi)展示出來(lái)就直接滑動(dòng)第二次了,就會(huì)看到看不懂得現(xiàn)象。所以這種情況下就要加上time。
2.連續(xù)實(shí)現(xiàn) 2 次滑屏
#從右向左滑
driver.swipe(start_x,start_y,end_x,end_y,200)
time.sleep(1)
driver.swipe(start_x,start_y,end_x,end_y,200)
3.代碼
# 微信 App Android/ target=_blank class=infotextkey>安卓
from appium import webdriver
import time
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from appium.webdriver.common.mobileby import MobileBy
desired_caps={}
# 平臺(tái)類型
desired_caps["platformName"]="Android"
# 平臺(tái)版本號(hào)
desired_caps["platformVersion"]="7.0"
# 設(shè)備名稱
desired_caps["deviceName"]="XPUDU17713003790"
# app 包名
desired_caps["appPackage"]="com.tencent.mm"
# app 入口 acitivity
desired_caps["appActivity"]="com.tencent.mm.ui.LauncherUI"
# 重置與否
desired_caps["noReset"]=True
# aapt dump badging 包名
# 連接 Appium server。前提:appium desktop 要啟動(dòng)。有監(jiān)聽端口。
# 將 desired_caps 發(fā)送給 appium server。打開 app
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
# ANDROID_UIAUTOMATOR 這個(gè)是一種定位表達(dá)式,用其它的表達(dá)式也是可以的。
loc=(MobileBy.ANDROID_UIAUTOMATOR,'new UiSelector().text("通訊錄")')
WebDriverWait(driver,30).until(EC.visibility_of_element_located(loc))
#height、width
size= driver.get_window_size()
start_x=size['width']*0.9
start_y=size['height']*0.5
end_x=size["width"]*0.1
end_y=size['height']*0.5
#從右向左滑
# 時(shí)間長(zhǎng)短需要根據(jù)實(shí)際情況自己來(lái)調(diào)試,避免沒(méi)滑過(guò)去,代碼就執(zhí)行完畢了。
driver.swipe(start_x,start_y,end_x,end_y,300)
time.sleep(2)
driver.swipe(start_x,start_y,end_x,end_y,300)
二、模擬觸屏
滑屏也是觸屏實(shí)現(xiàn)的。手指在屏幕上點(diǎn)點(diǎn)點(diǎn),在 Appium 中提供了專門的TouchAction類來(lái)做這件事。
Press、longPress和release組合起來(lái)使用的。長(zhǎng)按和短按的時(shí)間長(zhǎng)度不同。
move_to手按住別松開,一直滑動(dòng)到另外一個(gè)點(diǎn)。在每一個(gè)操作之間都調(diào)用下wait,暫緩下它們的操作間隙,不然太快了,看起來(lái)就是一團(tuán)亂麻。
1.短按和點(diǎn)擊的區(qū)別?
短按是按住不松開,但是時(shí)間比較短。tap是點(diǎn)完就松開,不需要組合別的一起用。有Press就必須有release,不然就一直按著上面動(dòng)都不動(dòng)了。
發(fā)送命令后,只有調(diào)用perform才能真的去執(zhí)行些操作命令,否則是不行的。
將所有的行為按要求放在列表中,可以將列表中所有的東西取消cancel。
滑屏操作是在屏幕上按住一個(gè)點(diǎn),然后滑動(dòng)到另外一個(gè)點(diǎn),最后把它松掉。
九宮格就是個(gè)典型的觸屏應(yīng)用。
2.用坐標(biāo)還是元素?
元素方便簡(jiǎn)單,但是不是你想選就一定是哪一種。一種情況,9 個(gè)點(diǎn)都是獨(dú)立的元素,那么用元素就可以了;第二種情況,9 個(gè)點(diǎn)都在一個(gè)元素里面怎么辦?就沒(méi)有辦法實(shí)現(xiàn)元素的移動(dòng),因?yàn)榫鸵粋€(gè)元素。這個(gè)時(shí)候就必須要用坐標(biāo)。
坐標(biāo)需要精確定位。需要思考每個(gè)坐標(biāo)之間的關(guān)系。
3.引入 TouchAction
from appium.webdriver.common.touch_action import TouchAction
TouchAction 的源碼:
4.每個(gè)行為函數(shù)都有 3 個(gè)參數(shù)
swipe滑屏操作是沒(méi)有元素的,針對(duì)的是整個(gè)屏幕。屏幕的話就只能通過(guò)坐標(biāo)點(diǎn)。所以你看swipe的源碼就可以看到。
看下 swipe 的實(shí)現(xiàn)-源碼:
action = TouchAction(self) #首先實(shí)例化 TouchAction
action
.press(x=start_x, y=start_y)
.wait(ms=duration)
.move_to(x=end_x, y=end_y)
.release()
action.perform()
return self
現(xiàn)在是它幫你封裝好了。實(shí)際上不用swipe,就用TouchAction自己去寫都可以。
x=end_x, y=end_y,沒(méi)有用 el。
5.首先確定每一個(gè)點(diǎn)的位置
選擇一個(gè)元素上的坐標(biāo),大概會(huì)選哪個(gè)位置的?
中心。
坐標(biāo)軸寫錯(cuò)了一點(diǎn),偏移了點(diǎn),好歹也是在范圍之內(nèi)。如果選擇邊緣的點(diǎn),偏了點(diǎn)可能就出不去了。所以,一般選一個(gè)元素的坐標(biāo),盡量選擇中心。 每個(gè)點(diǎn)之間的間隔是一樣的。從一個(gè)點(diǎn)挪到另外一個(gè)點(diǎn),y 軸不用動(dòng),x 軸只要有個(gè)固定的距離就好了。
例如 3 個(gè)點(diǎn)的值是:147.376、359.378、571.378
能把這 3 個(gè)值直接這樣寫出來(lái)嗎?
不能。換臺(tái)設(shè)備就不行了,這樣絕對(duì)的數(shù)據(jù)是不能放在這里的。采用和滑屏操作一樣的思想,用百分比和相對(duì)距離。如果能獲取到元素的大小以及起點(diǎn)坐標(biāo)就可以了。
距離是 59。147-59=88
可以估算一下:
如果是長(zhǎng)方形那就需要另外再算,但是圖中是正方形,這 9 個(gè)格子的間距是沒(méi)有什么區(qū)別的,重點(diǎn)是它與邊界值的差距。
邊界值的差距是多少?
把它分成 6 份。第一個(gè)點(diǎn)的坐標(biāo):能夠得到 view 的起點(diǎn)坐標(biāo)是 45,272。有專門的函數(shù)可以獲取元素的大小以及它的起點(diǎn)坐標(biāo)。
假設(shè)起點(diǎn)坐標(biāo)是 x、y,我現(xiàn)在已經(jīng)知道將它分成了 6 份。
那么,第一個(gè)點(diǎn)的坐標(biāo)怎么寫?
x+width*1/6 + height*1/6
看 size 源碼:
看 location 源碼:
#元素的大小
size=ele.size
# 均分的步長(zhǎng) 高和寬一樣(因?yàn)槭钦叫危?step=size["width"]/6#py3 中除是取整數(shù)的,會(huì)缺點(diǎn)小數(shù)點(diǎn)沒(méi)關(guān)系。取得是終點(diǎn),問(wèn)題不大,還是可以滑動(dòng)到的。
# 元素的起點(diǎn)坐標(biāo)-左上角
ori=ele.location
point1=(ori["x"]+step,ori["y"]+step)
TouchAction(driver)
等于橫向走了這么遠(yuǎn),縱向也走了這么遠(yuǎn),剛好對(duì)著這個(gè)點(diǎn)了。
第二個(gè)點(diǎn)的坐標(biāo)怎么算?
基于第一個(gè)點(diǎn)的基礎(chǔ)上做調(diào)整就行了。y 軸不變,x 軸往前走了 2 份。
第 3 個(gè)點(diǎn)也是在第 2 個(gè)點(diǎn)的基礎(chǔ)上往前挪動(dòng)了 2 個(gè)。
#元素的大小
size=ele.size
# 均分的步長(zhǎng) 高和寬一樣(因?yàn)槭钦叫危?step=size["width"]/6#py3 中除是取整數(shù)的,會(huì)缺點(diǎn)小數(shù)點(diǎn)沒(méi)關(guān)系。取得是終點(diǎn),問(wèn)題不大,還是可以滑動(dòng)到的。
# 元素的起點(diǎn)坐標(biāo)-左上角
ori=ele.location
point1=(ori["x"]+step,ori["y"]+step)
point2=(point1[0]+step*2,point1[1]) #x 軸增加了 2*step
point3=(point2[0]+step*2,point2[1]) #x 軸增加了 2*step
TouchAction(driver)
第 4 個(gè)點(diǎn)的坐標(biāo):
它是倒著往回走。
第 5 個(gè)點(diǎn)的坐標(biāo)。
#元素的大小
size=ele.size
# 均分的步長(zhǎng) 高和寬一樣(因?yàn)槭钦叫危?step=size["width"]/6#py3 中除是取整數(shù)的,會(huì)缺點(diǎn)小數(shù)點(diǎn)沒(méi)關(guān)系。取得是終點(diǎn),問(wèn)題不大,還是可以滑動(dòng)到的。
# 元素的起點(diǎn)坐標(biāo)-左上角
ori=ele.location
point1=(ori["x"]+step,ori["y"]+step)
point2=(point1[0]+step*2,point1[1]) #相對(duì)于 point1,x 軸增加了 2*step
point3=(point2[0]+step*2,point2[1]) #相對(duì)于 point2,x 軸增加了 2*step
point4=(point3[0]-step*2,point3[1]+step*2)#相對(duì)于 point3,x 軸減少了 2*step,y 軸增加了 2*step
point5=(point4[0],point4[1]+step*2)#相對(duì)于 point4,x 軸不變,y 軸增加了 2*step
TouchAction(driver).press(x=point1[0],y=point1[1]).wait(200).
move_to(x=point2[0],y=point2[1]).wait(200).
move_to(x=point3[0],y=point3[1]).wait(200).
move_to(x=point4[0],y=point4[1]).wait(200).
move_to(x=point5[0],y=point5[1]).wait(200).
release().
perform()
#.是換行用的。
以 1 個(gè)點(diǎn)做基準(zhǔn),針對(duì)不同的點(diǎn)做基準(zhǔn),容易把自己繞暈了。所以,都以前一個(gè)點(diǎn)做基準(zhǔn)。也可以以起點(diǎn)作為基準(zhǔn)。
6.代碼
from appium import webdriver
import time
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from appium.webdriver.common.mobileby import MobileBy
import time
from appium.webdriver.common.touch_action import TouchAction
desired_caps={}
# 平臺(tái)類型
desired_caps["platformName"]="Android"
# 平臺(tái)版本號(hào)
desired_caps["platformVersion"]="7.0"
# 設(shè)備名稱
desired_caps["deviceName"]="XPUDU17713003790"
# app 包名
desired_caps["appPackage"]="填上 appPackage"
# app 入口 acitivity
desired_caps["appActivity"]="填上 appActivity"
# 重置與否
desired_caps["noReset"]=True
# 連接 Appium server。前提:appium desktop 要啟動(dòng)。有監(jiān)聽端口。
# 將 desired_caps 發(fā)送給 appium server。打開 app
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
ele=driver.find_element_by_id("填上元素定位下吧,如果你 app 這里的元素定位不了,那就只能用坐標(biāo)了,需要另外學(xué)習(xí)這塊的坐標(biāo)怎么寫,嗚嗚")
# 元素的大小
size=ele.size
# 均分的步長(zhǎng) 高和寬一樣(因?yàn)槭钦叫危?step=size["width"]/6#py3 中除是取整數(shù)的,會(huì)缺點(diǎn)小數(shù)點(diǎn)沒(méi)關(guān)系。取得是終點(diǎn),問(wèn)題不大,還是可以滑動(dòng)到的。
# 元素的起點(diǎn)坐標(biāo)-左上角
ori=ele.location
point1=(ori["x"]+step,ori["y"]+step)
point2=(point1[0]+step*2,point1[1]) #相對(duì)于 point1,x 軸增加了 2*step
point3=(point2[0]+step*2,point2[1]) #相對(duì)于 point2,x 軸增加了 2*step
point4=(point3[0]-step*2,point3[1]+step*2)#相對(duì)于 point3,x 軸減少了 2*step,y 軸增加了 2*step
point5=(point4[0],point4[1]+step*2)#相對(duì)于 point4,x 軸不變,y 軸增加了 2*step
TouchAction(driver).press(x=point1[0],y=point1[1]).wait(100).
move_to(x=point2[0],y=point2[1]).wait(100).
move_to(x=point3[0],y=point3[1]).wait(100).
move_to(x=point4[0],y=point4[1]).wait(100).
move_to(x=point5[0],y=point5[1]).wait(100).
release().
perform()
#.是換行用的。
三、注意
這里是 V1.6.幾的或 V1.7.1,V1.7 以前的,如果按上面代碼的方式寫坐標(biāo)的話,會(huì)報(bào)錯(cuò)“提示越界了”。這個(gè)是版本差異引起的。 需要看日志,日志中會(huì)告訴你,當(dāng)前滑動(dòng)的點(diǎn)是什么。
多看 Appium 中的日志,它會(huì)問(wèn)你是 el 滑動(dòng)還是坐標(biāo)滑動(dòng)?
坐標(biāo)滑動(dòng)會(huì)直接打印坐標(biāo)值,看下坐標(biāo)值超了就說(shuō)明是有問(wèn)題的。版本比較晚的應(yīng)該都是絕對(duì)坐標(biāo)。
實(shí)際上是不會(huì)“越界”的,那只因?yàn)?strong>用的相對(duì)距離來(lái)滑動(dòng)的。move_to的每一個(gè)坐標(biāo)點(diǎn)都是真實(shí)的絕對(duì)坐標(biāo)。
用的當(dāng)前元素的原坐標(biāo)點(diǎn)加上移動(dòng)的距離得到的是當(dāng)前相對(duì)于整個(gè)屏幕左上角這個(gè) 00 的真實(shí)坐標(biāo)值。
我現(xiàn)在用的坐標(biāo),但是有的版本的問(wèn)題是:
它的move_to參數(shù)不是絕對(duì)坐標(biāo)。而是相對(duì)于上一個(gè)點(diǎn)的移動(dòng)距離。
比如第一個(gè)點(diǎn),press 是沒(méi)有錯(cuò)的。用 move_to 的時(shí)候 y 沒(méi)有動(dòng),x 軸移動(dòng)了 2 倍 step。
如果是這種相對(duì)距離移動(dòng)的話,要求x=2*step,沒(méi)有坐標(biāo),y=0。如果不是按這種風(fēng)格寫的,會(huì)報(bào)“越界”。
它拿著上一個(gè)點(diǎn)的坐標(biāo)值加上 x,y,得出來(lái)肯定超界了。因?yàn)榇a里寫的真實(shí)坐標(biāo),再加上 x,第二個(gè)點(diǎn)可能沒(méi)有越界,第三個(gè)點(diǎn)就越界了。
如果報(bào)“越界”錯(cuò)誤,那么就改成相對(duì)坐標(biāo)滑動(dòng)一下,看看有沒(méi)有報(bào)錯(cuò)。
Appium 在不同的版本修復(fù)了不同的問(wèn)題,但是修復(fù)的同時(shí)也可能出現(xiàn)不同的問(wèn)題。






