appium get_attribute 方法
来源:互联网 发布:安卓录屏软件 编辑:程序博客网 时间:2024/05/01 00:49
问题描述
当使用类似下面的代码获取元素的 content-desc 属性时,会报 NoSuchElement 错误:
# pythonself.driver.find_element_by_id("id").get_attribute("content-desc")
但使用如下代码却能正常执行:
# pythonself.driver.find_element_by_id("id").click()
很明显,这个错误原因不是找不到元素,而是 get_attribute 出问题。
问题原因探究
appium server 在 android 原生应用上获取 attribute 的大致流程为:
- 从 client 收到获取 attribute 的请求
- 把请求转发给在手机上运行的 bootstrap
- bootstrap 调用相关方法进行实际操作
- bootstrap 返回结果给 appium server
- appium server 把结果返回给 client
通过排查各部分的代码发现,错误是在 bootstrap 产生的(排查过程涉及代码有点多,所以这里就不解释了),所以看看 bootstrap 相关源码:
lib/devices/android/bootstrap/src/io/appium/android/bootstrap/handler/GetAttribute.java
@Override public AndroidCommandResult execute(final AndroidCommand command) throws JSONException { if (command.isElementCommand()) { // only makes sense on an element final Hashtable<String, Object> params = command.params(); try { // 获取需要操作的 element 实例 final AndroidElement el = command.getElement(); // 获取需要获取的 attribute 的名称 final String attr = params.get("attribute").toString(); if (attr.equals("name") || attr.equals("text") || attr.equals("className") || attr.equals("resourceId")) { // 如果 attribute 名称为 name, text, className, resourceId ,调用元素的 getStringAttribute 方法获取 return getSuccessResult(el.getStringAttribute(attr)); } else { // 否则调用 getBoolAttribute 获取 (我们的 'content-desc' 执行的是这段语句) return getSuccessResult(String.valueOf(el.getBoolAttribute(attr))); } } catch (final NoAttributeFoundException e) { // 从这里开始就是第一个坑,无论是什么错误,最终返回的都是 NO_SUCH_ELEMENT return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT, e.getMessage()); } catch (final UiObjectNotFoundException e) { return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT, e.getMessage()); } catch (final Exception e) { // el is null return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT, e.getMessage()); } } else { // 没有给出需要获取属性的 element ,返回错误信息 return getErrorResult("Unable to get attribute without an element."); } }
其中 getStringAttribute
和 getBoolAttribute
源码如下:
lib/devices/android/bootstrap/src/io/appium/android/bootstrap/AndroidElement.java
public String getStringAttribute(final String attr) throws UiObjectNotFoundException, NoAttributeFoundException { String res; if (attr.equals("name")) { // 坑2:属性名称为 name 时,会先尝试获取 content-desc ,如果 content-desc 为空,则获取 text 。说白了,就算用 name 也不能保证你获取的就是 content-desc res = getContentDesc(); if (res.equals("")) { res = getText(); } } else if (attr.equals("text")) { res = getText(); } else if (attr.equals("className")) { res = getClassName(); } else if (attr.equals("resourceId")) { res = getResourceId(); } else { throw new NoAttributeFoundException(attr); } return res; }...public boolean getBoolAttribute(final String attr) throws UiObjectNotFoundException, NoAttributeFoundException { boolean res; // 这个方法只会获取值为布尔类型的属性,我们的 content-desc 的值不是布尔类型的,所以抛出 NoAttributeFoundException if (attr.equals("enabled")) { res = el.isEnabled(); } else if (attr.equals("checkable")) { res = el.isCheckable(); } else if (attr.equals("checked")) { res = el.isChecked(); } else if (attr.equals("clickable")) { res = el.isClickable(); } else if (attr.equals("focusable")) { res = el.isFocusable(); } else if (attr.equals("focused")) { res = el.isFocused(); } else if (attr.equals("longClickable")) { res = el.isLongClickable(); } else if (attr.equals("scrollable")) { res = el.isScrollable(); } else if (attr.equals("selected")) { res = el.isSelected(); } else if (attr.equals("displayed")) { res = el.exists(); } else { throw new NoAttributeFoundException(attr); } return res; }
总结
1、获取 content-desc 的方法为 get_attribute("name")
,而且还不能保证返回的一定是 content-desc (content-desc 为空时会返回 text 属性值)
2、get_attribute
方法不是我们在 uiautomatorviewer
看到的所有属性都能获取的(此处的名称均为使用 get_attribute 时使用的属性名称):
可获取的:
字符串类型:
- name(返回 content-desc 或 text)
- text(返回 text)
- className(返回 class,只有 API=>18 才能支持)
- resourceId(返回 resource-id,只有 API=>18 才能支持)
布尔类型(如果无特殊说明, get_attribute 里面使用的属性名称和 uiautomatorviewer 里面的一致):
- enabled
- checkable
- checked
- clickable
- focusable
- focused
- longClickable(返回 long-clickable)
- scrollable
- selected
- displayed(此元素是否在当前界面存在。调用的是 UIObject 的
exists()
方法,详情请看http://developer.android.com/reference/android/support/test/uiautomator/UiObject.html#exists())
获取不到,但会显示在 uiautomatorviewer 中的属性:
- index
- package
- password
- bounds(可通过 get_position 来获取其中部分内容)
- appium get_attribute 方法
- appium get_attribute 方法
- selenium 之get_attribute
- Appium基础篇16-appium截图方法
- appium client方法一览
- Appium常用方法总结
- Appium的滑动方法
- appium 获取元素方法
- Appium常用方法介绍
- appium常用方法
- Appium 截图方法
- appium driver 方法总结
- Appium 常用方法
- appium,智能查找方法
- appium常用方法
- Appium的定位方法
- Appium-bootstrap的调试方法
- Appium API常用方法解释
- Code 吟__001
- 笔记:动态获取ListView高度
- GDB调试带参数程序
- 如何使用WireShark抓取数据包?
- 在struts2中使用freemarker添加jsp标签支持
- appium get_attribute 方法
- window.parent和window.opener区别
- 织梦dedecms中html和xml格式的网站地图sitemap制作方法
- yunos系统的成功之路
- spring配置双数据源
- Python tips: 什么是*args和**kwargs?
- IOS开发系列--IOS程序开发概览(版本稍微老了一些)
- jsp常用的指令与标签
- StringBuffer代码优化