UiAutomator中android.widget.ListView控件的子元素遍历

本文详细介绍了在UiAutomator中如何通过遍历ListView来寻找并操作特定子元素,以实现自动化操作,如点击需要的switch按钮。通过实例演示了如何使用UiObject类的方法来获取、筛选并执行特定操作。

网上对于UiAutomator大都是简单demo的讲解,许多实用的技巧没有贴出来。今天介绍几个自己琢磨出来的技巧

1.android.widget.ListView控件的子元素遍历

对于一些列表控件,比如“设置”项里的每一行,都是ListView的子项,有时候需要遍历这些元素进行点击。举个例子,如下图:


我想打开蓝牙,但是必须点击右边的switch按钮才行,怎样才能找到这个按钮呢?直接用控件类别肯定不行,因为有多个switch控件。那找“蓝牙”文本,可也不行,你找到的只是文本控件,点击只是点击在文本上,switch按钮并不会被点击。最好的办法就是能找到每一行的控件,然后看这一行有没有包含“蓝牙”文本的控件,如果有,则查找switch控件,进行点击即可。问题就回到了如何遍历这个ListView。仔细看官方文档里的函数,找到这两个:



第一个函数时返回一个UiObject子元素的个数,第二个通过序号来遍历子元素。注意,这两个函数都是对于当前能看到的元素而言的,看不到的是不算在内的。也就是说,如果子元素有20个,但当前只能看到10个,那第一个函数就返回10.而第二个函数是从当前视线中1。。。10进行遍历。(在测试的过程中,发现第二个函数并不准确,可能只遍历到第7个的时候就认为遍历完了,因此如果有需要可以想其他办法优化这个地方)。下面贴代码:

UiScrollable functionItems = null; 
functionItems = new UiScrollable(new UiSelector().className("android.widget.ListView"));
int nIndex = 0;
for(nIndex = 0; nIndex < functionItems.getChildCount(); nIndex++) {
    UiObject apps = null;
    try {
        apps = functionItems.getChildByInstance(new UiSelector().className("android.widget.LinearLayout"), nIndex);
    } catch(UiObjectNotFoundException e) {}  
    if(apps == null || !apps.exist()) {
        continue;
    }
    try {
        lanya= apps.getChild(new UiSelector().text("蓝牙"));
    } catch(UiObjectNotFoundException e) {}  
    if(lanya == null || !lanya.exist()) {
        continue;
    }
    UiObject checkBox = null;
    try {
        checkBox = apps.getChild(new UiSelector().className("android.widget.CheckBox"));
    } catch(UiObjectNotFoundException e) {}
    if(checkBox != null && checkBox.exists() && checkBox.isChecked()) {
        checkBox.click();
    }
    UiObject switchCheck = null;
    try {
        switchCheck = apps.getChild(new UiSelector().className("android.widget.Switch"));
    } catch(UiObjectNotFoundException e) {}             
    if(switchCheck != null && switchCheck.exists() && switchCheck.isChecked()) {
        switchCheck.click();
    }
}


这里需要注意的是,一定要手动捕获异常。test函数是抛出异常的,但是,如果在找控件的过程中没有找到,会直接抛出异常,中断程序。对于遍历,找不到很正常,我们不希望程序中断。因此我们要再用try捕获异常,而且每次都要判断是否是null,不判断的话,一旦为null,程序立即退出。

页面信息: 这是某一个按钮未展开情况下的信息: <?xml version='1.0' encoding='UTF-8' standalone='yes' ?> <hierarchy index="0" class="hierarchy" rotation="0" width="1080" height="2424"> <android.widget.FrameLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.FrameLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][1080,1075]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="0" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.LinearLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.LinearLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][1080,1075]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.FrameLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.FrameLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][1080,1075]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="2" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.FrameLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.FrameLayout" text="" resource-id="com.brother.ptouch.iprintandlabel:id/action_bar_root" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][1080,1075]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.FrameLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.FrameLayout" text="" resource-id="android:id/content" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][1080,1075]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <androidx.appcompat.widget.LinearLayoutCompat index="0" package="com.brother.ptouch.iprintandlabel" class="androidx.appcompat.widget.LinearLayoutCompat" text="" resource-id="com.brother.ptouch.iprintandlabel:id/parentPanel" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][1080,1075]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.FrameLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.FrameLayout" text="" resource-id="com.brother.ptouch.iprintandlabel:id/customPanel" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][1080,1075]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="3" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.FrameLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.FrameLayout" text="" resource-id="com.brother.ptouch.iprintandlabel:id/custom" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][1080,1075]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.LinearLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.LinearLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][1080,1075]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.view.ViewGroup index="0" package="com.brother.ptouch.iprintandlabel" class="android.view.ViewGroup" text="" resource-id="com.brother.ptouch.iprintandlabel:id/print_option_toolbar" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][1080,289]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.ImageButton index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.ImageButton" text="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,142][147,289]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="2" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.widget.TextView index="1" package="com.brother.ptouch.iprintandlabel" class="android.widget.TextView" text="Print Options" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[189,180][511,251]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.widget.Button index="2" package="com.brother.ptouch.iprintandlabel" class="android.widget.Button" text="PRINT" resource-id="com.brother.ptouch.iprintandlabel:id/printer_option_printer" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[849,152][1080,278]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="3" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> </android.view.ViewGroup> <android.widget.ScrollView index="1" package="com.brother.ptouch.iprintandlabel" class="android.widget.ScrollView" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,289][1080,1075]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="2" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.LinearLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.LinearLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,289][1080,1075]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.RelativeLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.RelativeLayout" text="" resource-id="com.brother.ptouch.iprintandlabel:id/option_print_lay" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,289][1080,484]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.TextView index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.TextView" text="Printer" resource-id="com.brother.ptouch.iprintandlabel:id/option_printer_title" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,331][152,382]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.widget.TextView index="1" package="com.brother.ptouch.iprintandlabel" class="android.widget.TextView" text="PT-P950NW(Not connected)" resource-id="com.brother.ptouch.iprintandlabel:id/option_printer_name" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="true" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,382][1038,439]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="2" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.view.View index="2" package="com.brother.ptouch.iprintandlabel" class="android.view.View" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,460][1038,463]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="3" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> </android.widget.RelativeLayout> <android.widget.RelativeLayout index="1" package="com.brother.ptouch.iprintandlabel" class="android.widget.RelativeLayout" text="" resource-id="com.brother.ptouch.iprintandlabel:id/option_resolution_lay" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,484][1080,685]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="2" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.TextView index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.TextView" text="Resolution" resource-id="com.brother.ptouch.iprintandlabel:id/option_resolution_title" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,526][216,577]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.widget.Spinner index="1" package="com.brother.ptouch.iprintandlabel" class="android.widget.Spinner" text="" resource-id="com.brother.ptouch.iprintandlabel:id/option_resolution_options" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="true" password="false" scrollable="true" selected="false" bounds="[42,577][1038,640]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="2" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.TextView index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.TextView" text="Normal" resource-id="com.brother.ptouch.iprintandlabel:id/resolution_spinner_txtV" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="true" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,580][912,637]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> </android.widget.Spinner> <android.view.View index="2" package="com.brother.ptouch.iprintandlabel" class="android.view.View" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,661][1038,664]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="3" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> </android.widget.RelativeLayout> <android.widget.RelativeLayout index="2" package="com.brother.ptouch.iprintandlabel" class="android.widget.RelativeLayout" text="" resource-id="com.brother.ptouch.iprintandlabel:id/option_copies_lay" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,685][1080,880]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="3" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.FrameLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.FrameLayout" text="" resource-id="com.brother.ptouch.iprintandlabel:id/option_copies" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,685][1038,880]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.RelativeLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.RelativeLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,685][1038,880]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.TextView index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.TextView" text="Copies" resource-id="com.brother.ptouch.iprintandlabel:id/option_title" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,727][156,778]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.widget.TextView index="1" package="com.brother.ptouch.iprintandlabel" class="android.widget.TextView" text="1" resource-id="com.brother.ptouch.iprintandlabel:id/option_number" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,778][786,835]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="2" showing-hint="false" text-entry-key="false" multiline="true" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" max-text-length="2" content-invalid="false" /> <android.view.View index="2" package="com.brother.ptouch.iprintandlabel" class="android.view.View" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,856][786,859]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="3" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.widget.ImageView index="3" package="com.brother.ptouch.iprintandlabel" class="android.widget.ImageView" text="" resource-id="com.brother.ptouch.iprintandlabel:id/option_down" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="true" password="false" scrollable="false" selected="false" bounds="[786,754][912,880]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="4" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.widget.ImageView index="4" package="com.brother.ptouch.iprintandlabel" class="android.widget.ImageView" text="" resource-id="com.brother.ptouch.iprintandlabel:id/option_up" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="true" password="false" scrollable="false" selected="false" bounds="[912,754][1038,880]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="5" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> </android.widget.RelativeLayout> </android.widget.FrameLayout> </android.widget.RelativeLayout> <android.widget.RelativeLayout index="3" package="com.brother.ptouch.iprintandlabel" class="android.widget.RelativeLayout" text="" resource-id="com.brother.ptouch.iprintandlabel:id/option_cut_lay" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,880][1080,1075]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="9" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.TextView index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.TextView" text="Cut Options" resource-id="com.brother.ptouch.iprintandlabel:id/option_cut_title" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,922][912,973]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.widget.TextView index="1" package="com.brother.ptouch.iprintandlabel" class="android.widget.TextView" text="No setting" resource-id="com.brother.ptouch.iprintandlabel:id/option_cut_options" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="true" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,973][912,1030]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="2" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.view.View index="2" package="com.brother.ptouch.iprintandlabel" class="android.view.View" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,1051][912,1054]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="3" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.widget.ImageView index="3" package="com.brother.ptouch.iprintandlabel" class="android.widget.ImageView" text="" resource-id="com.brother.ptouch.iprintandlabel:id/option_cut_expand" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[912,949][1038,1075]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="4" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> </android.widget.RelativeLayout> </android.widget.LinearLayout> </android.widget.ScrollView> </android.widget.LinearLayout> </android.widget.FrameLayout> </android.widget.FrameLayout> </androidx.appcompat.widget.LinearLayoutCompat> </android.widget.FrameLayout> </android.widget.FrameLayout> </android.widget.FrameLayout> </android.widget.LinearLayout> </android.widget.FrameLayout> </hierarchy> 这是展开组件后的信息: <?xml version='1.0' encoding='UTF-8' standalone='yes' ?> <hierarchy index="0" class="hierarchy" rotation="0" width="1080" height="2424"> <android.widget.FrameLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.FrameLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,577][912,829]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="0" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.FrameLayout index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.FrameLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,577][912,829]" displayed="true" a11y-important="false" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.ListView index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.ListView" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,577][912,829]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false"> <android.widget.CheckedTextView index="0" package="com.brother.ptouch.iprintandlabel" class="android.widget.CheckedTextView" text="Normal" resource-id="android:id/text1" checkable="true" checked="true" clickable="true" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,577][912,703]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="1" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> <android.widget.CheckedTextView index="1" package="com.brother.ptouch.iprintandlabel" class="android.widget.CheckedTextView" text="High" resource-id="android:id/text1" checkable="true" checked="false" clickable="true" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[42,703][912,829]" displayed="true" a11y-important="true" screen-reader-focusable="false" drawing-order="2" showing-hint="false" text-entry-key="false" dismissable="false" a11y-focused="false" heading="false" live-region="0" context-clickable="false" content-invalid="false" /> </android.widget.ListView> </android.widget.FrameLayout> </android.widget.FrameLayout> </hierarchy> 展开后的内容可能动态浮层的形式,增加1.写一个函数判断当前是否有浮层存在 2.定位获取新加载的元素并用于点击 3.参考def safe_select_from_spinner(self, spinner_id, target_text): """ 安全选择 Spinner 中的某个选项 """ try: # 1. 点击 Spinner 展开 spinner = self.driver.find_element(AppiumBy.ID, spinner_id) spinner.click() print(f"👉 已点击下拉框: {spinner_id}") # 2. 等待浮层中的选项出现 option_xpath = f"//android.widget.CheckedTextView[@text='{target_text}']" target_option = WebDriverWait(self.driver, 5).until( EC.element_to_be_clickable((AppiumBy.XPATH, option_xpath)) ) # 3. 点击目标选项 target_option.click() print(f"✅ 成功选择: {target_text}") return True except TimeoutException: print(f"❌ 超时:未找到选项 '{target_text}'") return False except Exception as e: print(f"❌ 操作失败: {e}") return False 修改我的现有代码,要求不丢失现有功能 from appium import webdriver from appium.options.android import UiAutomator2Options from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException, NoSuchElementException, ElementNotInteractableException import time # ==================== 目标应用配置 ==================== TARGET_PACKAGE = "com.brother.ptouch.iprintandlabel" TARGET_ACTIVITY = ".module.home.home.HomeActivity" # 主页 Activity MAX_RESTORE_ATTEMPTS = 2 MAX_HISTORY_REPEAT = 3 # ==================== 配置 Appium Options ==================== def create_driver(): options = UiAutomator2Options() options.set_capability("platformName", "Android") options.set_capability("deviceName", "emulator-5554") options.set_capability("automationName", "UiAutomator2") options.set_capability("noReset", True) options.set_capability("fullReset", False) options.set_capability("autoGrantPermissions", True) options.set_capability("newCommandTimeout", 600) options.set_capability("appPackage", TARGET_PACKAGE) options.set_capability("appActivity", TARGET_ACTIVITY) driver = webdriver.Remote('http://localhost:4723', options=options) return driver class AndroidAppExplorer: def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(driver, 10) self.clicked_identifiers = set() self.recovery_history = [] self.restore_attempt_count = 0 def get_current_state(self): try: current_package = self.driver.current_package current_activity = self.driver.current_activity return current_package, current_activity except: return None, None def is_in_target_app(self): pkg, _ = self.get_current_state() return pkg == TARGET_PACKAGE def wait_for_page_load(self, timeout=10): """等待页面加载完成""" try: WebDriverWait(self.driver, timeout).until( EC.presence_of_element_located(( 'xpath', '//android.view.ViewGroup[@displayed="true"] | ' '//android.widget.FrameLayout[@displayed="true"]' )) ) time.sleep(1) except Exception as e: print(f"⚠️ 页面等待超时或出错: {e}") def ensure_in_target_app(self): current_pkg, current_act = self.get_current_state() if not self.is_in_target_app(): print(f"⚠️ 当前不在目标应用 ({current_pkg}/{current_act}),正在尝试恢复...") current_key = (current_pkg, current_act) recent_entries = self.recovery_history[-10:] if recent_entries.count(current_key) >= MAX_HISTORY_REPEAT: print(f"🛑 已多次回到 {current_key},疑似陷入循环,停止恢复。") return False self.recovery_history.append(current_key) # 方法1:back 返回 if self.restore_attempt_count < MAX_RESTORE_ATTEMPTS: try: self.driver.back() time.sleep(1.5) if self.is_in_target_app(): print("✅ 通过 back 成功返回目标 App") self.restore_attempt_count = 0 self.wait_for_page_load(10) return True except: pass # 方法2:activate_app if self.restore_attempt_count < MAX_RESTORE_ATTEMPTS: try: self.driver.activate_app(TARGET_PACKAGE) print("🔁 正在通过 activate_app 恢复...") time.sleep(2) self.wait_for_page_load(10) if self.is_in_target_app(): print("✅ 成功激活目标 App") self.restore_attempt_count = 0 return True except Exception as e: print(f"❌ activate_app 失败: {e}") # 方法3:冷重启 if self.restore_attempt_count >= MAX_RESTORE_ATTEMPTS: try: print("💀 执行冷重启...") self.driver.terminate_app(TARGET_PACKAGE) time.sleep(2) self.driver.activate_app(TARGET_PACKAGE) time.sleep(5) self.wait_for_page_load(10) if self.is_in_target_app(): print("✅ 冷重启成功") self.restore_attempt_count = 0 return True except Exception as e: print(f"❌ 冷重启失败: {e}") self.restore_attempt_count += 1 if self.restore_attempt_count > 5: print("🛑 恢复尝试过多,终止运行") return False return True else: self.recovery_history.append((current_pkg, current_act)) self.wait_for_page_load(1) return True def get_element_identifier(self, element): try: attrs = [ element.get_attribute("resource-id") or "", element.get_attribute("text") or "", element.get_attribute("content-desc") or "", element.tag_name or "" ] return "/".join([a for a in attrs if a.strip()]) except: return "unknown_element" def find_clickable_elements(self): xpath = """ //*[(@clickable='true' or @focusable='true') and @displayed='true' and @enabled='true'] """ try: elements = self.driver.find_elements('xpath', xpath) return [e for e in elements if e.is_displayed()] except Exception as e: print(f"❌ 查找元素失败: {e}") return [] def classify_elements(self, elements): bottom_nav_container = "com.brother.ptouch.iprintandlabel:id/bottomNavigationView" nav_ids = [ "com.brother.ptouch.iprintandlabel:id/navigation_my_label", "com.brother.ptouch.iprintandlabel:id/navigation_setting", "com.brother.ptouch.iprintandlabel:id/navigation_buy" ] nav_elements = [] non_nav_elements = [] for elem in elements: try: res_id = elem.get_attribute("resource-id") or "" content_desc = elem.get_attribute("content-desc") or "" text = elem.get_attribute("text") or "" if (res_id == bottom_nav_container or res_id in nav_ids or content_desc in ["My Labels", "Settings", "Shop"]): nav_elements.append(elem) else: non_nav_elements.append(elem) except Exception as e: print(f"⚠️ 分类元素时异常: {e}") continue return nav_elements, non_nav_elements def handle_alert_popup(self): alert_xpath = "//*[contains(@text, 'OK') or contains(@text, '允许') or contains(@text, 'Allow')]" try: button = self.driver.find_element('xpath', alert_xpath) if button.is_displayed(): button.click() print("✅ 自动处理了弹窗") time.sleep(1) except: pass def is_interactive_input(self, element): """判断是否为可视且可交互的输入框""" try: if not element.is_displayed(): return False focusable = element.get_attribute("focusable") == "true" enabled = element.get_attribute("enabled") == "true" clazz = element.get_attribute("className") or "" is_edit_type = any(kw in clazz for kw in ["EditText", "TextInput"]) return focusable and enabled and is_edit_type except: return False def handle_input_field(self, input_elem): """处理输入框:显示提示、当前值,并让用户手动输入后读取结果""" hint = input_elem.get_attribute("hint") or "null" current_text = input_elem.get_attribute("text") or "" print(f"\n🔍 发现输入框") if hint != "null": print(f" 提示: '{hint}'") if current_text: print(f" 当前文本: '{current_text}'") print("请在设备上手动输入内容(3秒内完成)...") time.sleep(3) try: entered_value = input_elem.get_attribute("text") or "" # ✅ 使用 text 而非 value except: entered_value = "" print(f"📝 用户在输入框中输入的内容为: '{entered_value}'") def click_element_safely(self, element): try: identifier = self.get_element_identifier(element) if identifier in self.clicked_identifiers: return False try: self.driver.execute_script("arguments[0].scrollIntoView(true);", element) except: pass time.sleep(0.5) element.click() print(f"🟢 点击成功: {identifier}") self.clicked_identifiers.add(identifier) time.sleep(1.5) return True except Exception as e: print(f"🔴 点击失败 {self.get_element_identifier(element)}: {str(e)}") return False def explore_page(self): print("\n🔄 开始探索当前页面...") while True: if not self.ensure_in_target_app(): print("❌ 无法恢复至目标应用,退出。") break self.handle_alert_popup() elements = self.find_clickable_elements() if not elements: print("📭 当前页面无可点击元素。") try: self.driver.back() print("🔙 返回上一页...") time.sleep(2) continue except: break nav_elements, non_nav_elements = self.classify_elements(elements) print(f"📌 导航栏元素数量: {len(nav_elements)}, 非导航栏元素数量: {len(non_nav_elements)}") # === 第一阶段:优先点击导航栏元素 === navigated = False for elem in nav_elements: if self.is_interactive_input(elem): self.handle_input_field(elem) continue if self.click_element_safely(elem): navigated = True break if navigated: continue # === 第二阶段:点击非导航栏元素 === any_clicked = False for elem in non_nav_elements: if self.is_interactive_input(elem): self.handle_input_field(elem) continue if self.click_element_safely(elem): any_clicked = True break if not any_clicked: print("✅ 当前页面所有可点击元素已处理完毕。") try: self.driver.back() print("🔙 返回上一页继续探索...") time.sleep(2) except: print("🔚 无法返回,探索结束。") break time.sleep(1) def run(self): print("🚀 启动 Android 应用探索器...") try: self.explore_page() except KeyboardInterrupt: print("\n👋 用户中断执行。") except Exception as e: print(f"💥 执行过程中发生错误: {type(e).__name__}: {e}") finally: print("🔚 自动化结束。") # =============== 主程序入口 =============== if __name__ == "__main__": driver = create_driver() explorer = AndroidAppExplorer(driver) try: explorer.run() finally: driver.quit()
最新发布
10-17
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值