Appium Appium - iOS 定位方式 iOSNsPredicateString 详解

DC · July 19, 2017 · Last by houzezhen replied at August 01, 2022 · 7535 hits
本帖已被设为精华帖!

iOS 定位方式 iOSNsPredicateString 详解

前言

由于使用idclassNameAccessibilityId定位方式较为简单,多数情况下,在同一个页面,都不是唯一存在的,不能识别一个元素。而 xpath定位方式在 xcui 底层原生不支持,由 appium 额外支持的,定位速度很慢,而且有时候定位不到元素的情况存在。综上所述,在 iOS 的 UI 自动化中,使用原生支持的iOSNsPredicateString定位方式是最好,支持也是最好的。

定位方式

iOS 版本全支持,底层测试框架无论是 XCUITest 或 UIAutomation,可支持元素的单个属性和多个属性定位,推荐使用。一个元素有这些属性:typevaluenamelabelenabledvisible,有些元素的属性只有以上的部分属性,如下图所示,可根据这些属性进行元素定位。

元素属性的介绍

type:元素类型,与className作用一致,如:XCUIElementTypeStaticText
value: 一般不用
name:元素的文本内容,可用作 AccessibilityId定位方式,如:测试420班级群
label:绝大多数情况下,与 name 作用一致
enabled:元素是否可点击,一般值为true或者false
visible:元素是够可见,一般值为true或者false

定位方式

元素的定位方式都是一个属性+运算符+值形式存在

  1. 比较运算符:>,<,==,>=,<=,!=
    可用于数值和字符串的比较,
    如:name>100name == '测试'

  2. 范围运算符:IN,BETWEEN
    可用于数值和字符串的范围核对
    如:name BETWEEN {3,10}name IN {'Alan','May'}

  3. 字符串相关:CONTAINSBEGINSWITHENDSWITH
    包含某个字符串,如:label CONTAINS '测试'
    以某个字符串开头,如:label BEGINSWITH '420'
    以某个字符串结束,如:label ENDSWITH '班级群'
    PS:在三个关键字后加上[c]不区分大小写,可用于字母的校验;[d]不区分发音符号,即没有重音符号 ($、#、% 等);[cd]即不区分大小写,也不区分发音符号,如:name CONTAINS[c] ABcdname CONTAINS abcdname CONTAINS ABCD是等同的,注意后面两个没带[c]的不相等

  4. 通配符:LIKE
    通配符也接受[cd]?代表一个字符,*代表多个字符
    如:一个元素的label属性为

    label LIKE '420测试班级群'
    label LIKE '420测?班级群'
    label LIKE '420??班级群'
    label LIKE '42?测试班?群'
    label LIKE '*试班级群'
    label LIKE '420测试班*'
    label LIKE '42*级群'
    label LIKE '4*试*群'
    

    以上这么多种文本都可以被识别为同一个元素。

  5. 正则表达式:MATCHES
    如:以4开头,以结束,

    label MATCHES '^4.+群$'
    

    PS:具体正则表达式语法,请百度一下,你就知道

以一种属性定位元素

可以用元素的属性:typevaluenamelabelenabledvisible,进行定位:

type == XCUIElementTypeStaticText,
label CONTAINS '测试'
label LIKE '*试班级群'
enabled == true
visible == false

以两种或两种以上属性定位元素

就是以上单个属性定位用符号AND连接起来即可。如:

type == XCUIElementTypeStaticText AND label CONTAINS '测试
type == XCUIElementTypeStaticText AND label CONTAINS '测试' AND enabled == true
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 75 条回复 时间 点赞
DC Appium-同一个元素不同定位方式的区别 中提及了此贴 19 Jul 09:38
DC appium python 脚本 xpath 报错,求指点 中提及了此贴 19 Jul 09:39

写得很详细,好评~ 不过 iOS Predicate 在 iOS10 以下也支持哒

NOTE: iOS predicates are usable in iOS 9.3 and below using the -ios uiautomation locator strategy and they are usable in iOS 10 and above using the -ios predicate string locator strategy

特别好,值得参考,不过有个问题还想请教一个问题:sdk '10.1.1' was not in list of simctl sdks
这个问题解决了,反复出现,大家有没有遇到

DC #5 · July 20, 2017 Author
JoTsai 回复

我的错,9.3 以下版本没用过,不敢确认,现在我去修改下,感谢指正啊😁

DC 关闭了讨论 20 Jul 09:44
DC 重新开启了讨论 20 Jul 09:44
思寒_seveniruby 将本帖设为了精华贴 20 Jul 21:04

小而美的文章

能举个 appium 里使用 python 编写的脚本例子吗,谢谢

“xpath 定位方式在 xcui 底层原生不支持” 楼主这句话的意思是 iOS10 以上都不支持 xpath 定位吗?

DC #12 · July 21, 2017 Author
steven 回复

不是,在 Appium 和 Macaca 上都支持 xpath 定位,但是这不是底层本身支持的,会有缺陷的

DC #13 · July 21, 2017 Author
safasdfawgwefs 回复

我在用 java,python 不怎么会啊

学习了,最近马上要弄这一块东西,提前了解下😀

DC 回复

java 也行啊,嘿嘿😀

type == XCUIElementTypeStaticText 不一定能定位到你想要的那个 text 吧?

请问楼主,这个 iOSNsPredicateString 工具 需要单独下载吗

DC #18 · July 27, 2017 Author
依旧 回复

如果一个页面,只有一个 XCUIElementTypeStaticText,就会定位到。如果多个,就会定位在页面第一个 XCUIElementTypeStaticText

DC #19 · July 27, 2017 Author
dabao 回复

这是 appium 本身支持的一种定位方式,不需要重新下载,在代码使用就可以

DC #20 · July 27, 2017 Author

谢谢大神,以后会努力发帖😁

DC 回复

我看你有几个截图 是用啥打开的

DC #22 · July 28, 2017 Author
dabao 回复

Appium Desktop,新的 appium 客户端

这种定位方式其实就是根据元素的属性进行定位,但是页面上很多的元素的属性其实基本上是一样的,对于这种元素有没有好的办法进行定位呢

回复

相同属性的元素可以生成一个 List,然后根据 index 定位

依旧 回复

如果页面元素很多的话,其实也不是很好判断这个 List 有多大以及这个元素在 List 中的位置吧,难道要先打印出来 list 再来定位吗?

DC #26 · August 07, 2017 Author
回复

ios 有些元素是获取不了 text 的值,一般都是将相同的元素生成一个 List,或者在编写用例的时候,强制使用其中一个元素

DC 回复

好吧,最近才开始搞这个 ios 自动化,相较 android 而言,确实繁杂许多啊😂

DC #28 · August 09, 2017 Author
回复

对的,比 android 繁琐好多,很多限制,ios 整个生态决定,没有办法啊

你好 可以举一个简单的例子吗 这个是通过 findby 什么定位的 我在 findby 列表下没有找到你说的这个定位方式 请指教谢谢

匿名 #30 · August 15, 2017

@sysayy 楼主的这个方式应该就是 appium 里面的 findbyid/type
ios 底层对 id name AccessibilityId 是相同的处理

DC 回复

我现在使用 iOSNSPredicateString 的时候发现一个诡异的情况,总是会有发生找不到元素的情况,使用隐式等待也没用,只能到页面之后 sleep 显示等待才能找到,而 xpath 基本上能找到,你有碰到过吗?

DC #32 · August 15, 2017 Author
回复

遇到过,这个的原因估计是查找元素的动作过后,页面才显示元素。xpath 没事,因为 xpath 速度比较慢。所以这种情况下最好封装下元素查找,让元素在某段时间内,不断地循环查找

DC #33 · August 15, 2017 Author
斯拉 回复

有的,就是 FindsByIosNSPredicate

DC 回复

现在用的 pagefactory 初始化页面元素的,不是很好封装😭

DC #35 · August 17, 2017 Author
回复

这个没怎么用过

请教个问题,我们在用 appium 做 iOS 端的自动化测试,想通过给控件添加 accessibilitylabel 的方法实现 find_element_by_accessibility 的方式获取控件,现在遇到的问题是加完上面的属性后,空间的 value,name,label 属性的值都变成了我们添加的 accessibilitylabel,请问原因是什么啊?

DC 回复

请教一下,我用了 type == XCUIElementTypeCell 查找;在页面中有很多个 XCUIElementTypeCell;照您的逻辑是找到第一个,我想要的也是第一个 cell;可是我这边是直接找不到;然后开始重试;想问一下是怎么回事?

DC #38 · August 17, 2017 Author
樂易 回复

先仔细看看你的页面第一个 cell 是不是你想要那个?有时候第一个 cell 在列表之外

DC #39 · August 17, 2017 Author
He Bin 回复

value,name,label 这三个属性本来就一致的啊

DC 回复

额,我可能没描述清楚,我添加了 accessibilitylabel 后,value,name, label 这三个属性都显示成了 ID 的值,但是控件本身是有文本信息的,文本信息如何获取?

DC #41 · August 18, 2017 Author
He Bin 回复

你是要先获取元素,再获取文本值?

DC 回复

是的,先获取元素,再获取文本,文本是根据数据动态加载的

DC #43 · August 18, 2017 Author
He Bin 回复

appium 的 api 应该有一个元素的 getText() 方法的。你可以试试

发现个问题,不知道是不是个例,我用 iOSNSPredicate 定位一个不在当前屏的元素然后进行点击操作,它居然没有抛 NosuchElement 的异常但也没有点击成功就这么过去了,看日志也没有什么异常抛出。

DC #45 · August 23, 2017 Author
回复

inspector 一下当前屏的元素,看看有没有你所点击的那个元素。如果有,iOSNSPredicate 定位肯定没问题的。但因为那个元素不在当前屏,所以肯定没办法点击成功,你试试用其他方式定位那个元素,看看是不是也没有报错

回复

element visible = false , 你把 location(x,y),打印下,是不是变成(0,0)了

DC 回复

发现如果当前页面超过一屏,使用 inspector 能解析到屏幕以外的元素,而且 isvisible 以及 enable 都是 true,所以 findElement 的时候没有跑出 nosuchelement 的异常,但是不在当前屏幕上所以点击肯定是没效果的。有点误解啊。。

vegetableBird 回复

我打印了下元素的信息如下,确实坐标 (0,0),isDisplayed 为 false,但是 inspector 上的 isVisible 是 true

DC #49 · August 24, 2017 Author
回复

所以判断元素是否可用,可以用 isdisplayed 这个方法,而不是直接定位

回复

inspector 不是很准确的,你可以在定位 element 的时候,加上 visible = true

vegetableBird 回复

嗯,加了之后就可以了,被 inspector 误导了,谢谢

回复

客气了

正好最近在学这个,太及时,先赞再看。谢谢了先。

为什么我的 appium 没有 iOSNsPredicateString 这个定位方式

回复

java-client 版本低

我导入了一个 Java-client5.0 的,也还是没有。但是我的 4.1.2 版本没有删除,一旦删除 4.1.2iosdriver 就会报错

回复

说明你还是用的 4.1.2

vegetableBird 回复

好的,谢谢你!

你好,我从 Java-client 5.0 的 beta1 一直试到 beta9 然后又用的 java-client 5.0.1 和 5.0.2 也还是没有 driver.findElementByIosNsPredicate。。。可以给个你的那个 jar 包吗?十分感谢

DC #60 · September 12, 2017 Author
回复

你的 driver 一定要是 iosDriver 才能用的,不然不能用

DC 回复

是 iosDriver,而且我在我的 io.appium.java.client 下也找到了 findElementByIosNsPredicate。但是就是不能调用

回复

我用的是 eclipse,请问您用的是什么框架

DC #63 · September 12, 2017 Author
回复

我用的是 IDEA,不过这个应该不跟 IDE 有关系才对啊。你这个要好好看下你的代码才行了

大神这怎么安装?怎么驱动的?

DC #65 · October 13, 2017 Author
卢山 回复

不用另外安装啊,这个 Appium 本身就支持的

66Floor has deleted

那是怎么打开这个界面的。是 appium 点击 start session。然后启动完会出现的界面么

DC #68 · October 13, 2017 Author
卢山 回复

对的,但还是要填写参数

DC 回复

大神我配置好了参数,start session 后 ,但是 inspector 没有截图显示,无法看到对应元素(app 已被驱动开):[debug] [iProxy] Error connecting to device![debug] [JSONWP Proxy] Proxying [GET /screenshot] to [GET http://localhost:8100/session/CDBB28E1-F406-4F6C-AD5C-640A477B63A9/screenshot] with no body[error] [MJSONWP] Encountered internal error running command: ProxyRequestError: Could not proxy command to remote server. Original error: Error: socket hang up
at JWProxy.proxy$ (/Applications/Appium.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/jsonwp-proxy/proxy.js:153:13)
at tryCatch (/Applications/Appium.app/Contents/Resources/app/node_modules/appium/node_modules/babel-runtime/regenerator/runtime.js:67:40)
at GeneratorFunctionPrototype.invoke as _invoke
at GeneratorFunctionPrototype.prototype.(anonymous function) as throw
at GeneratorFunctionPrototype.invoke (/Applications/Appium.app/Contents/Resources/app/node_modules/appium/node_modules/babel-runtime/regenerator/runtime.js:136:37)
[info] [HTTP] <-- GET /wd/hub/session/0168ffd7-d357-4d0d-94e2-a3d16c5be10b/screenshot 500 17254 ms - 250 [info] [XCUITest] xcodebuild exited with code '65' and signal 'null'

DC #70 · October 15, 2017 Author
卢山 回复

你这是环境没配置好吧

DC 回复

可以了 我的 Appium 版本有问题 我下载了最新的就好了 那大神 你说的是元素定位 那具体的动作呢?比如 click(),有没有个参考例子呢?带动作的那种

DC #72 · October 16, 2017 Author
卢山 回复

元素定位和动作没分开的,动作具体要看这个元素是设什么类型,文本框,按钮还是其他

@xiaoyuezuibang 你的问题解决了没?我也遇到相同问题。能说下方法吗?

这个是只有 appium 支持吗?使用 macaca 没有看到对应的 api,XCTestWD version: 1.3.1,应该是没有问题的吧

DC #75 · October 31, 2017 Author
曾晖斌 回复

应该都支持的,有些地方可能需要改改,你可以试试

具体怎么用,能给个完整的例子么

hello 一招让 IOS 自动化化快的飞起 中提及了此贴 07 Sep 15:25

刚入门不久,看到这篇文章涨知识了

simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 13 Dec 14:44

请问用谓词代替 Xpath 怎么用?我试了一下报错:WebElement 不能隐式的转换成 IosElement、

回复

工厂模式:@iOSXCUITFindBy(iOSNsPredicate = sting)

大神你好,帮忙看下这个报错是哪里版本不对了吗?
An unknown server-side error occurred while processing the command. Original error: Unsupported locator strategy: -ios predicate string

85Floor has deleted

楼主你好 我也刚用 ios_predicate 的方式,请问怎么处理层级之间的关系来进行定位呢?

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up