UiObject

UiObject UiObject表示一个控件,可以通过这个对象获取到控件的属性,也可以对控件进行点击、长按等操作。 获取一个UiObject通常通过选择器的findOne(), findOnce()等函数,也可以通过UiCollection来获取,或者通过UiObject.child(), UiObject.parent()等函数来获取一个控件的子控件或父控件。 UiObject.click() 返回值类型 备注 Boolean 点击该控件,并返回是否点击成功。 如果该函数返回false,可能是该控件不可点击(clickable为false),当前界面无法响应该点击等。 以下非官方文档内容 下面是新浪微博登录例子。 注意代码中的click()前面使用了findOne() 如果没有findOne(),判断会出错。 //此代码由飞云脚本圈原创(www.feiyunjs.com) if (text("微博用户协议和隐私条款").exists()) { let isEnter = false //是否继续执行 if (id("checkBox").findOne().click()) { //判断选中状态,自动处理 if (id("checkBox").findOne().checked()) { log("已选中") isEnter = true } else { if (id("checkBox").findOne().click()) { log("已选中") isEnter = true } else { log("未选中") } } } if (isEnter) { log("我已阅读并同意上述条款") sleep(random(1000, 3000)) //随机延时 if (id("next").findOne().click()) { log("下一步") sleep(random(1000, 3000)) //随机延时 } } } 有的APP中,尽管该函数返回false,实际上仍然是点击成功的。 比如QQ附近的人,从会话页返回到个人资料页: //返回到个人资料页 //此代码由飞云脚本圈原创(www.feiyunjs.com) //判断返回按钮是否存在 var object = id('name').className('LinearLayout').clickable(true).depth(7) if (object .exists()) { //点击返回按钮 object .click() log("返回到个人资料页") sleep(random(1000,3000)); //随机延时 }; 而下面这种写法就是错误的。脚本运行时,会因为判断问题出现页面反复闪回的问题。 var object = id('name').className('LinearLayout').clickable(true).depth(7) if (object.click()) { log("返回到个人资料页") sleep(random(1000,3000)); //随机延时 } else { log("返回失败") }; UiObject.longClick() 返回值类型 备注 Boolean 长按该控件,并返回是否点击成功。 如果该函数返回false,可能是该控件不可点击(longClickable为false),当前界面无法响应该点击等。 UiObject.setText(text) 参数 类型 描述 text {string} 文本 返回值类型 备注 Boolean 设置输入框控件的文本内容,并返回是否设置成功。 该函数只对可编辑的输入框(editable为true)有效。 UiObject.copy() 返回值类型 备注 Boolean 对输入框文本的选中内容进行复制,并返回是否操作成功。 该函数只能用于输入框控件,并且当前输入框控件有选中的文本。可以通过setSelection()函数来设置输入框选中的内容。 var et = className("EditText").findOne(); //选中前两个字 et.setSelection(0, 2); //对选中内容进行复制 if(et.copy()){ toast("复制成功"); }else{ toast("复制失败"); } UiObject.cut() 返回值类型 备注 Boolean 对输入框文本的选中内容进行剪切,并返回是否操作成功。 该函数只能用于输入框控件,并且当前输入框控件有选中的文本。可以通过setSelection()函数来设置输入框选中的内容。 UiObject.paste() 返回值类型 备注 Boolean 对输入框控件进行粘贴操作,把剪贴板内容粘贴到输入框中,并返回是否操作成功。 //设置剪贴板内容为“你好” setClip("你好"); var et = className("EditText").findOne(); et.paste(); UiObject.setSelection(start, end) 参数 类型 描述 start {number} 选中内容起始位置 end {number} 选中内容结束位置(不包括) 返回值类型 备注 Boolean 对输入框控件设置选中的文字内容,并返回是否操作成功。 索引是从0开始计算的;并且,选中内容不包含end位置的字符。例如,如果一个输入框内容为"123456789",要选中"4567"的文字的代码为et.setSelection(3, 7)。 该函数也可以用来设置光标位置,只要参数的end等于start,即可把输入框光标设置在start的位置。例如et.setSelection(1, 1)会把光标设置在第一个字符的后面。 UiObject.scrollForward() 返回值类型 备注 Boolean 对控件执行向前滑动的操作,并返回是否操作成功。 向前滑动包括了向右和向下滑动。如果一个控件既可以向右滑动和向下滑动,那么执行scrollForward()的行为是未知的(这是因为Android文档没有指出这一点,同时也没有充分的测试可供参考)。 滑动操作的第一步是找到需要滑动的控件,例如要滑动QQ消息列表,则在悬浮窗布局层次分析中找到AbsListView,这个控件就是消息列表控件。注意到其scrollable属性为true,并找出其id为"recent_chat_list",从而下滑QQ消息列表的代码为: id("recent_chat_list").className("AbsListView").findOne().scrollForward(); 以下非官方例子: 抖音v6.6.0其他用户的关注列表,翻页例子。如果要操作粉丝列表,将depth的值改为9即可。 //等待抖音其他用户的关注列表页面出现: waitForActivity("com.ss.android.ugc.aweme.following.ui.FollowRelationTabActivity") //翻页: log(id("cd0").depth(10).findOne().scrollForward()) 另一种操作抖音用户的粉丝列表的简单写法: do { sleep(1000);//停个1秒 等页面滑动执行完成 //当前页面逻辑 } while (scrollForward()); image.png UiObject.scrollBackward() 返回值类型 备注 Boolean 对控件执行向后滑动的操作,并返回是否操作成功。 向后滑动包括了向右和向下滑动。如果一个控件既可以向右滑动和向下滑动,那么执行scrollForward()的行为是未知的(这是因为Android文档没有指出这一点,同时也没有充分的测试可供参考)。 UiObject.select() 返回值类型 备注 Boolean 对控件执行"选中"操作,并返回是否操作成功。"选中"和isSelected()的属性相关,但该操作十分少用。 UiObject.collapse() 返回值类型 备注 Boolean 对控件执行折叠操作,并返回是否操作成功。 UiObject.expand() 返回值类型 备注 Boolean 对控件执行操作,并返回是否操作成功。 UiObject.show() 返回值类型 备注 Boolean 对集合中所有控件执行显示操作,并返回是否全部操作成功。 UiObject.scrollUp() 返回值类型 备注 Boolean 对集合中所有控件执行向上滑的操作,并返回是否全部操作成功。 UiObject.scrollDown() 返回值类型 备注 Boolean 对集合中所有控件执行向下滑的操作,并返回是否全部操作成功。 UiObject.scrollLeft() 返回值类型 备注 Boolean 对集合中所有控件执行向左滑的操作,并返回是否全部操作成功。 UiObject.scrollRight() 返回值类型 备注 Boolean 对集合中所有控件执行向右滑的操作,并返回是否全部操作成功。 children() 返回值类型 备注 UiCollection 控件集合 返回该控件的所有子控件组成的控件集合。可以用于遍历一个控件的子控件,例如: id("a64").findOne().children().forEach(function (child) { log(child.className()); }); 也可以这样写,但是这种方法容易出问题,不推荐使用: var object = id("a64").findOne().children() for (var i = 0; i < object.length; i++) { log(object[i].className()); }; 约宝宝APP遍历附近的人表项: //此代码由飞云脚本圈原创(www.feiyunjs.com) let object = className("android.view.ViewGroup").find(); if (!object.empty()) { // 遍历组件 object.forEach(function (currentValue, index) { // 遍历子组件 currentValue.children().forEach(function (child, num) { log(child.id()); //根据得到的id,判断是否进入用户详情 }); }); }; image.png 微信运动点赞实例: 下面这个代码的写法有些臃肿了,其中使用了多次遍历子组件。更简单的办法是直接寻找点赞图标。不过那样似乎不太稳定,有时候会出现找不到的情况。 // 检查页面 //此代码由飞云脚本圈原创(www.feiyunjs.com) object = text("排行榜").findOnce(); if (object != null) { object = desc("返回").findOnce(); if (object != null) { toast("开始执行"); while (true) { let object = id("bks").find(); //寻找图像前的序号(跳过自己) if (!object.empty()) { // 遍历组件 object.forEach(function (currentValue, index) { let father = currentValue.parent(); //取昵称父组件对象 if (father && father.id()) { // com.tencent.mm:id/bkr //列表项目item object = currentValue.parent().parent().parent(); if (object && object.id()) { // com.tencent.mm:id/nc object.children().forEach(function (child) { // com.tencent.mm:id/be8 // 遍历子组件 child.children().forEach(function (child1) { child1.children().forEach(function (child2) { child2.children().forEach(function (child3) { child3.children().forEach(function (child4) { if (child4.id() == "com.tencent.mm:id/bkx") { log(child4.text()); //用户备注/昵称 }; if (child4.id() == "com.tencent.mm:id/bjb") { log("找到点赞图标"); }; }); }); }); }); }); }; }; }); } else { toastLog("解析列表失败"); device.vibrate(500); //震动提示 exit(); }; //检测是否到达尾部 object = text("邀请朋友").findOnce(); if (object != null) { toastLog("已到达尾部"); exit(); }; // 向上翻页 swipe(100, device.height - 10, 100, getHeadHeight() + 50, random(500, 1000)); //向上滑动翻页 sleep(1000) }; }; }; //取头部高度 function getHeadHeight() { let rect = id("jw").findOne().bounds(); return rect.height(); }; childCount() 返回值类型 备注 number 返回子控件数目。 child(i) 参数 类型 描述 i {number} 子控件索引 返回值类型 备注 UiObject 返回第i+1个子控件。如果i>=控件数目或者小于0,则抛出异常。 需要注意的是,由于布局捕捉的问题,该函数可能返回null,也就是可能获取不到某个子控件。 遍历子控件的示例: var list = className("AbsListView").findOne(); for(var i = 0; i < list.childCount(); i++){ var child = list.child(i); log(child.className()); } parent() 返回值类型 备注 UiObject 返回该控件的父控件。如果该控件没有父控件,返回null。 // 花椒直播关注用户接口 //此代码由飞云脚本圈原创(www.feiyunjs.com) function APP_关注用户() { if (textEndsWith("关注").exists() && text("TA").exists() && text("私信").exists()) { if (text("已关注").exists()) { log("该用户已关注") } else if (id("csi").findOne().parent().click()) { // 该用户未关注 log("关注成功") sleep(1000); //延时 return true; } else { log("Error:界面分析失败,请检查APP版本或运行环境") }; return false; }; }; // 遍历抖音用户,粉丝列表中的用户昵称 // APP版本:7.2.1 //此代码由飞云脚本圈原创(www.feiyunjs.com) var object = className("TextView").depth(13).find(); if (!object.empty()) { for (var i = 0; i < object.length; i++) { if (object[i].text() != "" && object[i].text() != "关注") { var tv = object[i].parent().parent().parent(); if (tv != null) { tv.click() //点击列表项,进入用户资料页 sleep(random(1000,3000)) // 执行发送私信/关注等操作 if (textStartsWith("作品").exists() && textStartsWith("动态").exists() && textStartsWith("粉丝").exists()) { back() sleep(random(1000,3000)) } } else { log("点击表项失败") }; } }; } else { log("Error:没找到用户昵称╭(╯^╰)╮"); }; 遍历兄弟组件: // 微博的用户任务中心,遍历兄弟组件 // APP版本:9.7.3 //此代码由飞云脚本圈原创(www.feiyunjs.com) let object = textStartsWith("填写学校").findOne(1000) if (object != null) { let child = object.parent().children() for (var i = 0; i < child.length; i++) { let tv = child[i] log(tv.text()) }; } else { log("未找到组件") } bounds() 返回值类型 备注 Rect 返回控件在屏幕上的范围,其值是一个Rect对象。 示例: var scope = text("Auto.js").findOne().bounds(); toast("控件在屏幕上的范围为" + scope); 如果一个控件本身无法通过click()点击,那么我们可以利用bounds()函数获取其坐标,再利用坐标点击。例如: let scope = desc("打开侧拉菜单").findOne().bounds(); let x = scope.centerX() let y = scope.centerY() click(parseInt(x), parseInt(y)) //如果使用root权限,则用 Tap 以下非官方说明 参数 描述 x1 区域左上角x坐标 y1 区域左上角y坐标 x2 区域右下角x坐标 y2 区域右下角y坐标 boundsInParent() 返回值类型 备注 Rect 返回控件在父控件中的范围,其值是一个Rect对象。 drawingOrder() 返回值类型 备注 number 返回控件在父控件中的绘制次序。该函数在安卓7.0及以上才有效,7.0以下版本调用会返回0。 id() 返回值类型 备注 string 获取控件的id,如果一个控件没有id,则返回null。 text() 返回值类型 备注 string 获取控件的文本,如果控件没有文本,返回""。 // 取抖音用户昵称 //此代码由飞云脚本圈原创(www.feiyunjs.com) function APP_取用户昵称() { // 判斷是否在用戶資料頁 desc("更多").waitFor(); //等待控件出现 if (text("获赞").exists() && text("关注").exists() && text("粉丝").exists()) { //判断是否存在指定节点 if (id("bka").exists()) { return id("bka").findOne().text(); //返回用户昵称 } else { log("Error:界面分析失败,请检查抖音版本或运行环境") }; } else { log("Error:当前不在用户资料页") }; }; Auto.js Pro获取QQ附近的人资料页用户昵称 // 取QQ附近的人用户昵称 //此代码由飞云脚本圈原创(www.feiyunjs.com) /* 修改日期:20190628 功能说明: 起始界面:用户资料页 备注说明:这段代码不准确。需要进一步优化 分辨率:全分辨率 模块作者: */ function APP_取用户昵称() { // 判斷是否在用戶資料頁 waitForActivity("com.tencent.mobileqq.nearby.profilecard.NearbyPeopleProfileActivity"); //等待页面出现 if (text("资料").exists() && text("动态").exists()) { //判断是否存在指定节点 var object = id("name").depth(10).className("TextView") if (object.exists()) { return object.findOne().text() }; } else { log(getNowFormatDate() + "当前不在用户资料页") }; return ""; }; findByText(str) 参数 类型 描述 str {string} 文本 返回 UiCollection 根据文本text在子控件中递归地寻找并返回文本或描述(desc)包含这段文本str的控件,返回它们组成的集合。 该函数会在当前控件的子控件,孙控件,曾孙控件…中搜索text或desc包含str的控件,并返回它们组合的集合。 findOne(selector) 参数 类型 描述 selector UiSelector 返回值类型 备注 UiObject 根据选择器selector在该控件的子控件、孙控件…中搜索符合该选择器条件的控件,并返回找到的第一个控件;如果没有找到符合条件的控件则返回null。 例如,对于酷安动态列表,我们可以遍历他的子控件(每个动态列表项),并在每个子控件中依次寻找点赞数量和图标,对于点赞数量小于10的点赞: //找出动态列表 var list = id("recycler_view").findOne(); //遍历动态 list.children().forEach(function(child){ //找出点赞图标 var like = child.findOne(id("feed_action_view_like")); //找出点赞数量 var likeCount = child.findOne(id("text_view")); //如果这两个控件没有找到就不继续了 if(like == null || likeCount == null){ return; } //判断点赞数量是否小于10 if(parseInt(likeCount.text()) < 10){ //点赞 like.click(); } }); find(selector) 参数 类型 描述 selector UiSelector 返回值类型 备注 UiCollection 控件集合 根据选择器selector在该控件的子控件、孙控件…中搜索符合该选择器条件的控件,并返回它们组合的集合。 UiCollection UiCollection, 控件集合, 通过选择器的find(), untilFind()方法返回的对象。 UiCollection"继承"于数组,实际上是一个UiObject的数组,因此可以使用数组的函数和属性,例如使用length属性获取UiCollection的大小,使用forEach函数来遍历UiCollection。 例如,采用forEach遍历屏幕上所有的文本控件并打印出文本内容的代码为: console.show(); className("TextView").find().forEach(function(tv){ if(tv.text() != ""){ log(tv.text()); } }); 也可以使用传统的数组遍历方式: console.show(); var uc = className("TextView").find(); for(var i = 0; i < uc.length; i++){ var tv = uc[i]; if(tv.text() != ""){ log(tv.text()); } } UiCollection的每一个元素都是UiObject,我们可以取出他的元素进行操作,例如取出第一个UiObject并点击的代码为ui[0].click()。 如果想要对该集合的所有元素进行操作,可以直接在集合上调用相应的函数,例如uc.click(),该代码会对集合上所有UiObject执行点击操作并返回是否全部点击成功。 因此,UiCollection具有所有UiObject对控件操作的函数,包括click(), longClick(), scrollForward()等等,不再赘述。 UiCollection.size() 返回值类型 备注 number 返回集合中的控件数。 历史遗留函数,相当于属性length。 UiCollection.get(i) 参数 类型 描述 i {number} 索引 返回值类型 备注 UiObject 返回集合中第i+1个控件(UiObject)。 历史遗留函数,建议直接使用数组下标的方式访问元素。 UiCollection.each(func) 参数 类型 描述 func {Function} 遍历函数,参数为UiObject。 遍历集合。 历史遗留函数,相当于forEach。参考forEach。 empty() 返回值类型 备注 Boolean 返回控件集合是否为空。 nonEmpty() 返回值类型 备注 Boolean 返回控件集合是否非空。 UiCollection.find(selector) 参数 类型 描述 selector UiSelector 返回值类型 备注 UiCollection 控件集合 根据selector所确定的条件在该控件集合的控件、子控件、孙控件…中找到所有符合条件的控件并返回找到的控件集合。 注意这会递归地遍历控件集合里所有的控件以及他们的子控件。和数组的filter函数不同。 例如: var names = id("name").find(); //在集合 var clickableNames = names.find(clickable()); UiCollection.findOne(selector) 参数 类型 描述 selector UiSelector 返回值类型 备注 UiObject 根据选择器selector在该控件集合的控件的子控件、孙控件…中搜索符合该选择器条件的控件,并返回找到的第一个控件;如果没有找到符合条件的控件则返回null。