Appium 切换到 webview 后,无论是获取 element,还是 pagesource 都无响应。

lim · 2015年04月19日 · 最后由 扮猪吃老虎 回复于 2015年05月20日 · 2552 次阅读

多看app做测试。切换到webview后,无论是获取element,还是pagesource 都无响应。
手机4.4.4 的系统。不知道是什么原因。。日志是说,Didn't get a new command in 60 secs, shutting down...

private AppiumDriver driver;

public void setUp() throws Exception {
// set up appium
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("deviceName","af68ec7");
capabilities.setCapability("platformVersion", "4.4.4");
capabilities.setCapability("appPackage", "com.duokan.reader");
capabilities.setCapability("appActivity", ".DkMainActivity");
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
}

public void test() {
System.out.println(driver.getContextHandles());
driver.context("WEBVIEW_com.duokan.reader");
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
System.out.println(driver.getPageSource());
}

info: [debug] Available contexts: NATIVE_APP,WEBVIEW_com.eg.android.AlipayGphone,WEBVIEW_com.sankuai.meituan,WEBVIEW_com.duokan.reader
info: [debug] ["WEBVIEW_com.duokan.reader","WEBVIEW_com.sankuai.meituan","WEBVIEW_com.eg.android.AlipayGphone"]
info: [debug] Available contexts: NATIVE_APP,WEBVIEW_com.duokan.reader,WEBVIEW_com.sankuai.meituan,WEBVIEW_com.eg.android.AlipayGphone
info: [debug] Connecting to chrome-backed webview
info: [debug] Creating Chrome session
info: [debug] Set chromedriver binary as: C:\Program Files (x86)\Appium\node_modules\appium\build\chromedriver\windows\chromedriver.exe
info: [debug] Ensuring Chromedriver exists
info: [debug] Killing any old chromedrivers, running: FOR /F "usebackq tokens=5" %a in (netstat -nao ^| findstr /R /C:"9515 ") do (FOR /F "usebackq" %b in (TASKLIST /FI "PID eq %a" ^| findstr /I chromedriver.exe) do (IF NOT %b=="" TASKKILL /F /PID %b))
info: [debug] No old chromedrivers seemed to exist
info: [debug] Spawning chromedriver with: C:\Program Files (x86)\Appium\node_modules\appium\build\chromedriver\windows\chromedriver.exe
info: [debug] [CHROMEDRIVER] Starting ChromeDriver 2.15.322448 (52179c1b310fec1797c81ea9a20326839860b7d3) on port 9515
Only local connections are allowed.
info: [debug] Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hub/session","method":"POST","json":{"sessionId":null,"desiredCapabilities":{"chromeOptions":{"androidPackage":"com.duokan.reader","androidUseRunningApp":true,"androidDeviceSerial":"af68ec7"}}}}
info: [debug] Didn't get a new command in 60 secs, shutting down...
info: Shutting down appium session
info: [debug] Pressing the HOME button
info: [debug] executing cmd: C:\Users\liming\AppData\Local\Android\sdk\platform-tools\adb.exe -s af68ec7 shell "input keyevent 3"
info: [debug] Stopping logcat capture
info: [debug] Logcat terminated with code null, signal SIGTERM
info: [debug] [BOOTSTRAP] [debug] Got data from client: {"cmd":"shutdown"}
info: [debug] [BOOTSTRAP] [debug] Got command of type SHUTDOWN
info: [debug] [BOOTSTRAP] [debug] Returning result: {"value":"OK, shutting down","status":0}
info: [debug] [BOOTSTRAP] [debug] Closed client connection
info: [debug] [UIAUTOMATOR STDOUT] INSTRUMENTATION_STATUS: numtests=1
info: [debug] [UIAUTOMATOR STDOUT] INSTRUMENTATION_STATUS: stream=.
info: [debug] [UIAUTOMATOR STDOUT] INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner
info: [debug] [UIAUTOMATOR STDOUT] INSTRUMENTATION_STATUS: test=testRunServer
info: [debug] [UIAUTOMATOR STDOUT] INSTRUMENTATION_STATUS: class=io.appium.android.bootstrap.Bootstrap
info: [debug] [UIAUTOMATOR STDOUT] INSTRUMENTATION_STATUS: current=1
info: [debug] [UIAUTOMATOR STDOUT] INSTRUMENTATION_STATUS_CODE: 0
info: [debug] [UIAUTOMATOR STDOUT] INSTRUMENTATION_STATUS: stream=
info: [debug] [UIAUTOMATOR STDOUT] Test results for WatcherResultPrinter=.
info: [debug] [UIAUTOMATOR STDOUT] Time: 81.623
info: [debug] [UIAUTOMATOR STDOUT] OK (1 test)
info: [debug] [UIAUTOMATOR STDOUT] INSTRUMENTATION_STATUS_CODE: -1
info: [debug] Sent shutdown command, waiting for UiAutomator to stop...
info: [debug] UiAutomator shut down normally
info: [debug] Cleaning up android objects
info: [debug] Cleaning up appium session
info: [debug] We shut down because no new commands came in
共收到 35 条回复 时间 点赞

从日志上看,chromedriver 起来后 appium server 就没有收到 client 的任何请求(卡在 chromedriver 的开 session 这里了,appium 发送了开 session 的请求后 chromedriver 一直没有反应),所以 session timeout 退出了。
原因应该是因为切换 context 这个请求一直没有返回消息给 client 端,所以client 一直停在切换 context 那一行等待 server 的返回消息,即切换 context 后的所有代码都没有执行过,所以你说的找元素和取源码都没有效果。

建议的解决方案:

  1. 根据 chromedriver 的Dependencies 和 Device Requirements 检查你的测试环境和被测应用是否符合要求:https://sites.google.com/a/chromium.org/chromedriver/getting-started/getting-started---android
  2. 检查你的参数配置是否有错,特别是 deviceName ,在 chromedriver 里面 deviceName (androidDeviceSerial )是用来选择特定设备的,必须和设备的序列号一致,如果你是单个 android 设备可以试试去掉 deviceName 这个参数。
  3. 升级 chromedriver 到最新版后直接在脚本里用 chromedriver 启动 session ,看到底出现什么错误。
lim #2 · 2015年04月20日 作者

#1楼 @chenhengjie123 多看的app是从官网上下载安装后,拿来做的测试。刚刚写了个webview demo进行了测试,发现是可以正确获得元素相关信息的。不知道跟app本身的编译方式或者设置有关系?

那可能是多看的app没有开 web debug 了。

想问下有没有什么办法能升级 app里内嵌的浏览器呢?

#1楼 @chenhengjie123
app里内嵌的浏览器有什么办法能升级吗?

升级是指使用其他浏览器?
你可以看看 crosswalk,把 chrome 内核打包到 app 中。

#6楼 @chenhengjie123 这个是测试app里的浏览器.
手机浏览器能升级; Android内嵌weibview的浏览器 怎么来升级

#7楼 @will_lee 据我所知,升级不了。webview 默认使用的浏览器是系统自带的,它不是以应用形式存在,只能通过升级系统来升级 android 内置 webview 浏览器。
你可以通过把浏览器内核打包到应用中来使用自己想用的版本的浏览器,前面我提到的 crosswalk 做的就是这个事情。缺点是应用体积会大不少。

@aicdlychee @chenhengjie123 问题解决了没?
我这里也遇到了一样的问题~,我是Appium1.3.1,然后替换的ChromeDriver.exe是2.14版本,设备是魅族MX4 PRO
Web Debug选项是打开的。

#9楼 @weamylady 我这里没出现过这个问题哦。
你也是 chromedriver 起来后没反应?你试试直接用 chromedriver ,不用 appium 看有没有问题?
正常来说用 chrome 浏览器能看到的 webview chromedriver 应该都能控制。

#10楼 @chenhengjie123 ChromeDriver是有响应的,只是不回应定位元素的Post:

info: --> POST /wd/hub/session/e386794d-1bb1-445c-872e-9410ccaf0d69/timeouts/imp
licit_wait {"ms":4000}
info: [debug] Proxying command to 127.0.0.1:9515
info: [debug] Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hu
b/session/ae767a83315371eceaf0d4c3c2a00d3d/timeouts/implicit_wait"
,"method":"POS
T"
,"json":{"ms":4000}}
info: [debug] Proxied response received with status 200: {"sessionId":"ae767a833
15371eceaf0d4c3c2a00d3d"
,"status":0,"value":null}
info: <-- POST /wd/hub/session/e386794d-1bb1-445c-872e-9410ccaf0d69/timeouts/imp
licit_wait 200 10.676 ms - 72
info: --> POST /wd/hub/session/e386794d-1bb1-445c-872e-9410ccaf0d69/element {"us
ing"
:"xpath","value":"//*[starts-with(translate(@text,' ',''),'取款密码') or sta
rts-with(translate(@content-desc,' ',''),'取款密码') or starts-with(translate(te
xt(),' ',''),'取款密码')][1]/following::*[1]"
}
info: [debug] Proxying command to 127.0.0.1:9515
info: [debug] Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hu
b/session/ae767a83315371eceaf0d4c3c2a00d3d/element"
,"method":"POST","json":{"usi
ng"
:"xpath","value":"//*[starts-with(translate(@text,' ',''),'取款密码') or star
ts-with(translate(@content-desc,' ',''),'取款密码') or starts-with(translate(tex
t(),' ',''),'取款密码')][1]/following::*[1]"
}}
info: [debug] Didn't get a new command in 60 secs, shutting down...

那我就不清楚了。
你试下去搜索 chromedriver ,看它不回应时从哪里能找到一些 log 信息?
或者直接用 chromedriver 来运行你的测试试试?

#12楼 @chenhengjie123 问你个问题,在真机Android4.3机器上,看不到WEBVIEW Context怎么搞?setWebContentsDebuggingEnabled只对Android4.4以上有用哦……

#13楼 @weamylady 只能用 Selendroid 模式。automationName:selendroid
chromedriver 只能测 4.4 以上。4.4 以下要用 Selendroid 。

#14楼 @chenhengjie123 用了Selendroid之后我就识别不了基本的Native元素了。我用的是Xpath。使用Selendroid有什么要注意的吗?我已经设置了grunt setConfigVer:selendroid。

#15楼 @weamylady 因为 selendroid 是基于 Instrumentation 的,而 appium 默认是基于 uiautomator ,所以两者获取回来的界面 xml 结构会有所不同,用 appium 时能定位的 xpath 在 selendroid 下可能会获取不了(xml 结构不一样了)。
我目前项目里没怎么用过 selendroid 模式,所以有什么要注意还真不大清楚哈。

#16楼 @chenhengjie123 您有没有遇到过hybird的 android app context不返回webview?我们的app是hybird但是有一个就是不返回webview,只有native_app 我是连真机4.4.2

#17楼 @irisliu 我自己没有,但我认识的人有。而且他用 remote debug 也看不到(他用的 app 在我的环境下可以看到 webview 的),最后解决方案是换手机。
可能性有两个,一个是 app 里禁用了 remote debug ,另一个是那台手机的系统本身有问题。
你试一下:

  1. remote debug 能否看到?看不到的话要不是禁用了 remote debug ,要不是 app 用的 webview 不是用 chronium 内核的。
  2. remote debug 能看到。升级一下 chromedriver 再试试。

#16楼 @chenhengjie123 确实是坑,在Selendroid模式下需要用@Value来定位,而不是用@Text。另外我现在用的Appium上Selendroid有bug,在新的0.15版本上有fix。
https://github.com/selendroid/selendroid/issues/309#issuecomment-36837808
不知道Appium1.4会不会使用Selendroid0.15以上的版本捏?~

#19楼 @weamylady 目前我所知道的在selendroid模式下,除了要用Value来定位,ByID的格式也不一样,要去掉com.xxx.xxx:id/ ,而且swip方法在4.2及以下设备上失效(可以通过adb shell input touchscreen swipe绕过),scoll方法失效。就连页面上的textview和imageview有时都会变成Novatextview和Novaimageview,到处都是坑。

#20楼 @sunrise 最大的坑还是整个页面都识别不出来……据说是因为Selendroid有bug,页面上元素带有$符号就会生成不了xml之类的,这个问题我现在还在愁呢!

#18楼 @chenhengjie123 确实是debug没开 代码里加了WebView.setWebContentsDebuggingEnabled(true)就可以了 多谢了

#21楼 @weamylady 是的,我也遇到了,有些页面我打印page_source直接报错了

#18楼 @chenhengjie123 请问hybrid app,用python实现hybrid切换到webview怎么弄呢?
我这样尝试的

#coding=utf-8

import os
import unittest,sys,time,re,datetime,HTMLTestRunner
from appium import webdriver
from time import sleep
from appium.common.exceptions import NoSuchContextException
import sys
from selenium.webdriver.support.ui import WebDriverWait

#reload(sys)
#sys.setdefaultencoding("utf-8")

# Returns abs path relative to this file and not cwd
PATH = lambda p: os.path.abspath(
os.path.join(os.path.dirname(__file__), p)
)

class ContactsAndroidTests(unittest.TestCase):
def setUp(self):
desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '4.4'
desired_caps['deviceName'] = '192.168.56.101:5555'
'''desired_caps['app'] = PATH(
'../../../sample-code/apps/ContactManager/ContactManager.apk'
)'''
desired_caps['appPackage'] = 'com.jiudao.ccare'
desired_caps['appActivity'] = '.MainActivity'
desired_caps["unicodeKeyboard"] = "True"
desired_caps["resetKeyboard"] = "True"


self.driver = webdriver.Remote('http://192.168.10.177:4723/wd/hub', desired_caps)
#self.driver.implicitly_wait(1)

def login(self):
#登录操作
#time.sleep(3)
self.driver.implicitly_wait(10)
a=self.driver.contexts
print (a)
self.driver.switch_to.context("pt1.1")

if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(ContactsAndroidTests("login"))
timestr = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
filename = "D:\\appium\\appiumresult\\result_" + timestr + ".html"
print (filename)
fp = open(filename, 'wb')
runner = HTMLTestRunner.HTMLTestRunner(
stream=fp,
title='测试结果',
description='测试报告'
)
runner.run(suite)
#g_browser.quit()
fp.close() #测试报告关闭

这是我获得的测试报告,我print出来的东西是pt1.1

#18楼 @chenhengjie123
实际上我切换的代码就三行

self.driver.implicitly_wait(10)
a=self.driver.contexts
print (a)

#23楼 @sunrise 这个问题你解决了吗?

#26楼 @weamylady 暂时无解,只能用uiautomation view来查看元素

#27楼 @sunrise 我指的不仅仅是查看元素,而是定位元素的时候就有问题,直接报500 Undefined~

#28楼 @weamylady 嗯,page_source都获取不到,自然也就没法定位。我是用uiautomator获取元素坐标,再用adb shell input tap点击的,这样可以绕过。还是希望selendroid能解决这个bug吧。

def __uidump(self):
#获取当前Activity控件树
self.tempFile = tempfile.gettempdir()
self.pattern = re.compile(r"\d+")
xml = "/data/local/tmp/uidump.xml"
os.popen("adb -s {0} shell uiautomator dump {1}".format(self.device_id, xml))
os.popen("adb -s {0} pull {1} {2}".format(self.device_id, xml, self.tempFile))

def get_element_point(self, attrib, name, nub):
"""
根据元素查找坐标,返回的坐标为元素中心点
传入元素类型、名称、下标,其中有多个元素时通过下标控制,默认为0

:Usage:
self.__element("
resource-id","scorebar",0)
"""

self.__uidump()
x = []
y = []
tree = ET.ElementTree(file=os.path.join(self.tempFile, "uidump.xml"))
treeIter = tree.iter(tag="node")
for elem in treeIter:
if elem.attrib[attrib] == name:
bounds = elem.attrib["bounds"]
coord = self.pattern.findall(bounds)
Xpoint = (int(coord[2]) + int(coord[0])) / 2.0
Ypoint = (int(coord[3]) + int(coord[1])) / 2.0
x.append(Xpoint)
y.append(Ypoint)
return x[nub], y[nub]

#29楼 @sunrise 腻害!果然好暴力的做法~ 3~ 我们的策略是先支持Android4.4以上的,4.3以下的只有一台机器就先不支持了。

Appium中,selendroid模式与uiautomator模式使用上最大的差别还是定位规则不统一。
selendroid模式并未完全规范化的支持xpath,所以定位起来跟uiautomator模式相差甚远没,甚至contains这样的语法都不能用。
关于ById的定位方式,从Appium@1.4.0之后估计就是一样的了。

然后,我就想问问,挖掘机技术哪家强!?

啊呸,为什么我的4.4系统,uiautomator模式下获取不到webview的context!?selendroid很正常啊。

#3楼 @chenhengjie123 请问下这一句 WebView.setWebContentsDebuggingEnabled(true),在python里应该怎么来写啊~~ 我也是切换到webview后,就定位不到元素了. 不知道在python里这个方法应该怎么来实现~~多谢啊

#32楼 @will_lee 这句是写到被测 app 里面的,不是测试脚本。。。

#31楼 @anikikun selendroid 模式和 uiautomator 模式不一样主要还是因为它们的实现完全不一样。
selendroid 底层是用 Instrumentation 的,dump 出来的结构是 hierarchyview 看到的结构
uiautomator 模式底层用的是 uiautomator ,dump 出来的结构是 uiautomatorviewer 看到的结构

你在同一个界面用两个不同模式 log source 看下就知道了,出来的东西完全不一样,所以 xpath 自然不一样。

#33楼 @chenhengjie123 如果我没有被测app的源代码,只能拿到apk的情况下,没有开web debug,这该怎么处理啊

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册