Android自动化学习4--uiautomator2判断是否滑

2021-05-29  本文已影响0人  wintests

前言

我们在使用 uiautomator2 做UI自动化时,有时需要进行多次滑动操作,比如我进入某个APP页面定位某个元素,如果该元素不存在,那么我可能会一直进行上滑操作,如果定位到该元素就停止继续滑动。

  • 一般的情况,如果页面是固定不变的内容,那么我们可以尝试并计算出大概需要滑动多少次才能到该元素的区域,这个时候我们直接把滑动次数写死就好。

  • 另一种情况,如果页面是经常变化的内容,这个时候我们就不知道到底需要滑动多少次,也许需要滑动到页面底部,才能判断该元素是否存在。

今天我们就学习下,如何在 uiautomator2 中判断是否已滑动到页面底部。

利用 dump_hierarchy() 获取界面UI结构

在 uiautomator2 中,我们通过 dump_hierarchy() 方法获取到当前界面的UI结构信息,同时该方法会把数据以 XML 形式的字符串进行返回。

import uiautomator2 as u2

d = u2.connect()
res = d.dump_hierarchy()

print(res)

返回的形式大致如下,它反应了当前页面的所有UI层次结构关系。

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<hierarchy rotation="0">
  <node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
    <node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
      <node index="0" text="" resource-id="android:id/content" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
        <node index="0" text="" resource-id="com.sec.android.app.launcher:id/launcher" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
          <node index="0" text="" resource-id="com.sec.android.app.launcher:id/drag_layer" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
            <node index="0" text="" resource-id="com.sec.android.app.launcher:id/apps_view" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
              <node index="0" text="" resource-id="com.sec.android.app.launcher:id/apps_content" class="com.android.launcher3.allapps.view.AppsPagedView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="true" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1920]">
                <node index="3" text="" resource-id="" class="android.view.ViewGroup" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[23,225][1057,1833]">
                  <node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[23,237][1057,1833]">
                    <node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="ATX" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="true" password="false" selected="false" visible-to-user="true" bounds="[23,237][274,549]">
                      <node index="0" text="" resource-id="com.sec.android.app.launcher:id/iconview_imageView" class="android.widget.ImageView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[67,256][229,418]" />
                      <node index="2" text="ATX" resource-id="com.sec.android.app.launcher:id/iconview_titleView" class="android.widget.TextView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[114,424][183,478]" />
                    </node>
                  </node>
                </node>
              </node>
              <node index="1" text="" resource-id="com.sec.android.app.launcher:id/apps_searchbar_container" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,99][1080,207]">
                <node index="0" text="" resource-id="com.sec.android.app.launcher:id/app_search_wrapper" class="android.widget.RelativeLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[60,99][1020,207]">
                  <node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[60,99][1020,207]">
                    <node index="0" text="" resource-id="com.sec.android.app.launcher:id/app_search_edit_text_wrapper" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[60,99][774,207]">
                      <node index="0" text="  搜索手机" resource-id="com.sec.android.app.launcher:id/app_search_edit_text" class="android.widget.EditText" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="true" password="false" selected="false" visible-to-user="true" bounds="[72,99][774,207]" />
                    </node>
                    <node index="1" text="" resource-id="com.sec.android.app.launcher:id/voice_search_button" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[774,99][894,207]">
                      <node index="0" text="" resource-id="com.sec.android.app.launcher:id/voice_search_icon_imageview" class="android.widget.ImageButton" package="com.sec.android.app.launcher" content-desc="语音搜索" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[774,99][894,207]" />
                    </node>
                    <node index="2" text="" resource-id="com.sec.android.app.launcher:id/apps_search_divider" class="android.view.View" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[915,129][918,177]" />
                    <node index="3" text="" resource-id="com.sec.android.app.launcher:id/more_button_search" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[939,117][1011,189]">
                      <node index="0" text="" resource-id="com.sec.android.app.launcher:id/more_icon_imageview" class="android.widget.ImageButton" package="com.sec.android.app.launcher" content-desc="更多选项" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[939,117][1011,189]" />
                    </node>
                  </node>
                  <node index="1" text="" resource-id="" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[60,204][1020,207]" />
                </node>
              </node>
            </node>
            <node index="2" text="" resource-id="com.sec.android.app.launcher:id/apps_page_indicator" class="android.widget.LinearLayout" package="com.sec.android.app.launcher" content-desc="第 4 页,共 4 页。" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[424,1821][655,1872]">
              <node NAF="true" index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[424,1821][475,1872]">
                <node index="0" text="" resource-id="com.sec.android.app.launcher:id/inactive" class="android.widget.ImageView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[424,1821][475,1872]" />
              </node>
              <node NAF="true" index="1" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[484,1821][535,1872]">
                <node index="0" text="" resource-id="com.sec.android.app.launcher:id/inactive" class="android.widget.ImageView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[484,1821][535,1872]" />
              </node>
              <node NAF="true" index="2" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[544,1821][595,1872]">
                <node index="0" text="" resource-id="com.sec.android.app.launcher:id/inactive" class="android.widget.ImageView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[544,1821][595,1872]" />
              </node>
              <node NAF="true" index="3" text="" resource-id="" class="android.widget.FrameLayout" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[604,1821][655,1872]">
                <node index="1" text="" resource-id="com.sec.android.app.launcher:id/active" class="android.widget.ImageView" package="com.sec.android.app.launcher" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[604,1821][655,1872]" />
              </node>
            </node>
          </node>
        </node>
      </node>
    </node>
  </node>
</hierarchy>

判断已经滑动到页面底部

我们可以利用 dump_hierarchy() 获取界面UI结构,那么需要怎么判断当前是否已滑动到底了呢?其实很简单,我们只需要判断每次滑动前的UI结构信息,与滑动后的UI结构信息一致,那么就可以看作是滑动到底部了。

import uiautomator2 as u2
import time

d = u2.connect()

while True:
    # 获取每次滑动前页面下半部分的所有元素
    page_content = d.dump_hierarchy()[(len(d.dump_hierarchy()) // 2):]
    d.swipe_ext("up")
    time.sleep(0.5)
    # 获取每次滑动后页面下半部分的所有元素,并与上一次滑动前的页面元素对比,页面元素没有变化时跳出循环
    new_page_content = d.dump_hierarchy()[(len(d.dump_hierarchy()) // 2):]
    if new_page_content == page_content:
        break

print("swipe end")
上一篇下一篇

猜你喜欢

热点阅读