uiautomator2+python+Android automation

In order to reduce personnel resource allocation and reduce repeatability testing time

Tip: The following is the text of this article

1. Import the library

import os
import time
import random
import datetime
import uiautomator2 as ut

2. Detect the connected mobile phone (the list is used for multi-threaded execution...not yet implemented)

devices = []
# 检测是否连接手机
try:
    for dName_ in os.popen("adb devices"):
        if "\t" in dName_:
            if dName_.find("emulator") < 0:
                devices.append(dName_.split("\t")[0])
    devices.sort(cmp=None, key=None, reverse=False)
except:
    pass

3. Alarm prompt (this location uses Feishuqun robot to alarm, other methods can also be used, such as: DingTalk, email, SMS)

    if devices == []:
        msg = 'Android手机 导致无法找到devices 进行启动Android自动化脚本。'
        send_FeiShu("无法连接", msg)
        exit()

4. Record the case execution video (directly use the current time as the video name to determine whether there is a video folder)

# today = (datetime.datetime.now() - datetime.timedelta(days=0)).strftime('%Y_%m_%d_%H_%M_%S') # 原
today = ((datetime.datetime.now() - datetime.timedelta(days=0)).strftime('%Y_%m_%d_%H_%M_%S')) # 改
VideoName = f"case_{
      
      today}"
if not os.path.exists("video"):
    os.makedirs('video')
VideoPath = 'video'
device.screenrecord(VideoPath + "/" + VideoName + ".mp4")

5. Find the application (get all the copy on the current page, determine whether the program is there, if not, search on the next screen until you find it and open it)

while True:
    device.press("home")
    device.press("home")
    text_list = [ele.text for ele in device.xpath('//android.widget.TextView').all()]
    if "XXX" not in text_list:
        device.swipe_ext('left', scale=0.9)
    else:
        device(text="XXX").click()
        time.sleep(5)
        try:
            device(resourceId="com.xxxxx.xxxxx:id/iv_dialog_active_close").click()
        except:
            print("不存在弹窗")
        break

6. Text document (write execution case, the format is as follows)

For example: 1. xx>xxx.xxxxx.xxxxx - xx>xxx.xxxxx.xxxxx
Among them: "1,", ">", "-" are used for analysis

1、首页>com.xxxxx.xxxxx:id/button_bar_home_img - 直播电商>xxx.xxxxx.xxxxx:id/button_bar_streaming_img - 达人>xxx.xxxxx.xxxxx:id/button_bar_ranking_img - 社区>xxx.xxxxx.xxxxx:id/button_bar_commodity_img - 我的>xxx.xxxxx.xxxxx:id/button_bar_user_img
2、实时直播>xpath('//*[@resource-id="com.xxxxx.xxxxx:id/rlHomeFunction"]/android.view.ViewGroup[1]/android.widget.ImageView[1]') - 退出页面登录>com.xxxxx.xxxxx/ivPhoneLoginBack
3、我的>com.xxxxx.xxxxx:id/button_bar_user_img - 登录 - 首页>com.xxxxx.xxxxx:id/button_bar_home_img
4、直播引流>com.xxxxx.xxxxx:id/tv_live_business_live_drainage - 上滑(下滑)

7. Parse the case (read the case document and parse it)

# 读取文档,获取case
with open('ExecuteCodeAndroid.text', 'r', encoding='UTF-8') as code_find:
     # 解析case
     code_list = [code_i.split('、')[1].replace('\n', '').split(' - ') for code_i in code_find.readlines()]
     for i in range(len(code_list)):
         for code_list_i in code_list[i]:

8. Verification pop-up window (get all the copy on the current page, verify whether there are keywords, and click the specified button if there are any)

# 获取当前页面文案,判断是否有弹窗
Tips = [elem.text for elem in device.xpath('//android.widget.TextView').all()]
if "个人信息保护指引" in Tips:
    device(resourceId="com.xxxxx.xxxxx:id/tv_dialog_agreement_confirm").click()
    device.swipe_ext("left", 0.6)
    device.swipe_ext("left", 0.6)
    device(resourceId="com.xxxxx.xxxxx:id/btn_item_welcome").click()
elif "好像哪里出错了" in Tips:
    device.xpath('//*[@text="返回"]').click()
elif "信息走失啦" in Tips:
    device.xpath('//*[@text="刷新"]').click()
elif "暂无数据" in Tips:
    device.xpath('//*[@text="稍后再试"]').click()
elif "访问过于频繁" in Tips:
    device.xpath('//*[@text="稍后再试"]').click()
elif "您当前账号登录" in Tips:
    device.xpath('//*[@text="取消"]').click()

9. Execution (detailed execution function click operation)

# # 解析后长度大于等于 2 的时候
# if len(code_list_i.split('>')) >= 2:
#     if 'xpath' in code_list_i.split('>')[1]:
#         device.xpath(f"""{code_list_i.split('>')[1].split("xpath('")[1].split("')")[0]}""").click()
#     else:
#         if ", text=" in code_list_i.split('>')[1]:
#             resourceId_ = code_list_i.split('>')[1].split(', text=')[0]
#             text_ = code_list_i.split('>')[1].split(', text=')[1].replace('"', '')
#             device(resourceId=f"{resourceId_}", text=f"{text_}").click()
#         else:
#             if "text" in code_list_i.split(">")[1]:
#                 text_name = code_list_i.split(">")[1].split('(text="')[1].split('")')[0]
#                 device(text=f"{text_name}").click()
#             else:
#                 device(resourceId=f"{code_list_i.split('>')[1]}").click()
# # 小于 2
# elif code_list_i.split('>')[0] == "登录":
#     AndroidLogin()
# elif code_list_i.split('>')[0] == "退出登录":
#     AndroidLogout()
# elif code_list_i.split(">")[0] == "输入":
#     device(resourceId="com.xxxxx.xxxxx:id/etSearchEdit").set_text(InputGbk2312())
#     device.send_action('search')
# elif code_list_i.split('>')[0] == "上滑":
#     Slide_up()
# elif code_list_i.split('>')[0] == "下拉":
#     Slide_down()
# 改后
# 解析后长度大于等于 2 的时候
if len(code_list_i.split('>')) >= 2:
    if 'xpath' in code_list_i.split('>')[1]:
        print("xpath", code_list_i.split('>')[1])
        xpath_code = code_list_i.split('>')[1].split("xpath('")[1].split("')")[0]
        print(f"device.xpath('{
      
      xpath_code}').click()")
        device.xpath(f'{
      
      xpath_code}').click()
    else:
        # if ", text=" in code_list_i.split('>')[1]:
        #     print(", text", code_list_i.split('>')[1])
        #     resourceId_ = code_list_i.split('>')[1].split(', text="')[0]
        #     text_ = code_list_i.split('>')[1].split(', text="')[1].replace('"', '')
        #     print(resourceId_, text_)
        #     print(f'device(resourceId="{resourceId_}", text="{text_}").click()')
        #     device(resourceId=f"{resourceId_}", text=f"{text_}").click()
        # # 该执行方式有误,网上说没有打开USB点击模式?  没有找到在哪里
        # # 再就是还有 UI 结构层次混乱,从而导致元素选择器获取不到指定元素
        # else:
        if "text" in code_list_i.split(">")[1]:
            text_name = code_list_i.split(">")[1].split('(text="')[1].split('")')[0]
            print("text", code_list_i.split(">")[1])
            device(text=f"{
      
      text_name}").click()
        else:
            print("resourceId", code_list_i.split(">")[1])
            device(resourceId=f"{
      
      code_list_i.split('>')[1]}").click()
# 小于 2
elif code_list_i.split('>')[0] == "登录":
    AndroidLogin()
elif code_list_i.split('>')[0] == "退出登录":
    AndroidLogout()
elif code_list_i.split(">")[0] == "输入":
    device(resourceId="com.aiyingli.douchacha:id/etSearchEdit").set_text(InputGbk2312())
    device.send_action('search')
elif code_list_i.split('>')[0] == "上滑":
    print("上滑页面")
    Slide_up()
elif code_list_i.split('>')[0] == "下拉":
    print("下拉页面")
    Slide_down()

10. All codes





#
为了减少人员的资源分配,减少可重复性检测的时间
---
提示:以下是本篇文章正文内容

## 1.引入库
```python
import os
import time
import random
import datetime
import uiautomator2 as ut

2. Detect the connected mobile phone (the list is used for multi-threaded execution...not yet implemented)

devices = []
# 检测是否连接手机
try:
    for dName_ in os.popen("adb devices"):
        if "\t" in dName_:
            if dName_.find("emulator") < 0:
                devices.append(dName_.split("\t")[0])
    devices.sort(cmp=None, key=None, reverse=False)
except:
    pass

3. Alarm prompt (this location uses Feishuqun robot to alarm, other methods can also be used, such as: DingTalk, email, SMS)

    if devices == []:
        msg = 'Android手机 导致无法找到devices 进行启动Android自动化脚本。'
        send_FeiShu("无法连接", msg)
        exit()

4. Record the case execution video (directly use the current time as the video name to determine whether there is a video folder)

# today = (datetime.datetime.now() - datetime.timedelta(days=0)).strftime('%Y_%m_%d_%H_%M_%S') # 原
today = ((datetime.datetime.now() - datetime.timedelta(days=0)).strftime('%Y_%m_%d_%H_%M_%S')) # 改
VideoName = f"case_{
      
      today}"
if not os.path.exists("video"):
    os.makedirs('video')
VideoPath = 'video'
device.screenrecord(VideoPath + "/" + VideoName + ".mp4")

5. Find the application (get all the copy on the current page, determine whether the program is there, if not, search on the next screen until you find it and open it)

while True:
    device.press("home")
    device.press("home")
    text_list = [ele.text for ele in device.xpath('//android.widget.TextView').all()]
    if "XXX" not in text_list:
        device.swipe_ext('left', scale=0.9)
    else:
        device(text="XXX").click()
        time.sleep(5)
        try:
            device(resourceId="com.xxxxx.xxxxx:id/iv_dialog_active_close").click()
        except:
            print("不存在弹窗")
        break

6. Text document (write execution case, the format is as follows)

For example: 1. xx>xxx.xxxxx.xxxxx - xx>xxx.xxxxx.xxxxx
Among them: "1,", ">", "-" are used for analysis

1、首页>com.xxxxx.xxxxx:id/button_bar_home_img - 直播电商>xxx.xxxxx.xxxxx:id/button_bar_streaming_img - 达人>xxx.xxxxx.xxxxx:id/button_bar_ranking_img - 社区>xxx.xxxxx.xxxxx:id/button_bar_commodity_img - 我的>xxx.xxxxx.xxxxx:id/button_bar_user_img
2、实时直播>xpath('//*[@resource-id="com.xxxxx.xxxxx:id/rlHomeFunction"]/android.view.ViewGroup[1]/android.widget.ImageView[1]') - 退出页面登录>com.xxxxx.xxxxx/ivPhoneLoginBack
3、我的>com.xxxxx.xxxxx:id/button_bar_user_img - 登录 - 首页>com.xxxxx.xxxxx:id/button_bar_home_img
4、直播引流>com.xxxxx.xxxxx:id/tv_live_business_live_drainage - 上滑(下滑)

7. Parse the case (read the case document and parse it)

# 读取文档,获取case
with open('ExecuteCodeAndroid.text', 'r', encoding='UTF-8') as code_find:
     # 解析case
     code_list = [code_i.split('、')[1].replace('\n', '').split(' - ') for code_i in code_find.readlines()]
     for i in range(len(code_list)):
         for code_list_i in code_list[i]:

8. Verification pop-up window (get all the copy on the current page, verify whether there are keywords, and click the specified button if there are any)

# 获取当前页面文案,判断是否有弹窗
Tips = [elem.text for elem in device.xpath('//android.widget.TextView').all()]
if "个人信息保护指引" in Tips:
    device(resourceId="com.xxxxx.xxxxx:id/tv_dialog_agreement_confirm").click()
    device.swipe_ext("left", 0.6)
    device.swipe_ext("left", 0.6)
    device(resourceId="com.xxxxx.xxxxx:id/btn_item_welcome").click()
elif "好像哪里出错了" in Tips:
    device.xpath('//*[@text="返回"]').click()
elif "信息走失啦" in Tips:
    device.xpath('//*[@text="刷新"]').click()
elif "暂无数据" in Tips:
    device.xpath('//*[@text="稍后再试"]').click()
elif "访问过于频繁" in Tips:
    device.xpath('//*[@text="稍后再试"]').click()
elif "您当前账号登录" in Tips:
    device.xpath('//*[@text="取消"]').click()

9. Execution (detailed execution function click operation)

# # 解析后长度大于等于 2 的时候
# if len(code_list_i.split('>')) >= 2:
#     if 'xpath' in code_list_i.split('>')[1]:
#         device.xpath(f"""{code_list_i.split('>')[1].split("xpath('")[1].split("')")[0]}""").click()
#     else:
#         if ", text=" in code_list_i.split('>')[1]:
#             resourceId_ = code_list_i.split('>')[1].split(', text=')[0]
#             text_ = code_list_i.split('>')[1].split(', text=')[1].replace('"', '')
#             device(resourceId=f"{resourceId_}", text=f"{text_}").click()
#         else:
#             if "text" in code_list_i.split(">")[1]:
#                 text_name = code_list_i.split(">")[1].split('(text="')[1].split('")')[0]
#                 device(text=f"{text_name}").click()
#             else:
#                 device(resourceId=f"{code_list_i.split('>')[1]}").click()
# # 小于 2
# elif code_list_i.split('>')[0] == "登录":
#     AndroidLogin()
# elif code_list_i.split('>')[0] == "退出登录":
#     AndroidLogout()
# elif code_list_i.split(">")[0] == "输入":
#     device(resourceId="com.xxxxx.xxxxx:id/etSearchEdit").set_text(InputGbk2312())
#     device.send_action('search')
# elif code_list_i.split('>')[0] == "上滑":
#     Slide_up()
# elif code_list_i.split('>')[0] == "下拉":
#     Slide_down()
# 改后
# 解析后长度大于等于 2 的时候
if len(code_list_i.split('>')) >= 2:
    if 'xpath' in code_list_i.split('>')[1]:
        print("xpath", code_list_i.split('>')[1])
        xpath_code = code_list_i.split('>')[1].split("xpath('")[1].split("')")[0]
        print(f"device.xpath('{
      
      xpath_code}').click()")
        device.xpath(f'{
      
      xpath_code}').click()
    else:
        # if ", text=" in code_list_i.split('>')[1]:
        #     print(", text", code_list_i.split('>')[1])
        #     resourceId_ = code_list_i.split('>')[1].split(', text="')[0]
        #     text_ = code_list_i.split('>')[1].split(', text="')[1].replace('"', '')
        #     print(resourceId_, text_)
        #     print(f'device(resourceId="{resourceId_}", text="{text_}").click()')
        #     device(resourceId=f"{resourceId_}", text=f"{text_}").click()
        # # 该执行方式有误,网上说没有打开USB点击模式?  没有找到在哪里
        # # 再就是还有 UI 结构层次混乱,从而导致元素选择器获取不到指定元素
        # else:
        if "text" in code_list_i.split(">")[1]:
            text_name = code_list_i.split(">")[1].split('(text="')[1].split('")')[0]
            print("text", code_list_i.split(">")[1])
            device(text=f"{
      
      text_name}").click()
        else:
            print("resourceId", code_list_i.split(">")[1])
            device(resourceId=f"{
      
      code_list_i.split('>')[1]}").click()
# 小于 2
elif code_list_i.split('>')[0] == "登录":
    AndroidLogin()
elif code_list_i.split('>')[0] == "退出登录":
    AndroidLogout()
elif code_list_i.split(">")[0] == "输入":
    device(resourceId="com.xxxxx.xxxxx:id/etSearchEdit").set_text(InputGbk2312())
    device.send_action('search')
elif code_list_i.split('>')[0] == "上滑":
    print("上滑页面")
    Slide_up()
elif code_list_i.split('>')[0] == "下拉":
    print("下拉页面")
    Slide_down()

10. All codes

import os
import time
import random
import datetime
import uiautomator2 as ut
from call_the_police import send_FeiShu

while True:
    devices = []
    # 检测是否连接手机
    print("检测是否连接手机")
    try:
        for dName_ in os.popen("adb devices"):
            if "\t" in dName_:
                if dName_.find("emulator") < 0:
                    devices.append(dName_.split("\t")[0])
        devices.sort(cmp=None, key=None, reverse=False)
    except:
        pass

    if devices == []:
        msg = 'Android手机 导致无法找到devices 进行启动Android自动化脚本。'
        send_FeiShu("无法连接", msg)
        exit()
    else:
        print("<————————执行用例————————>")
        try:
            device = ut.connect_usb(devices[0])
        except:
            os.popen("adb kill-server")
            os.popen("adb start-server")
            device = ut.connect_usb(devices[0])

        # 录制视频
        if not os.path.exists("Android/video"):
            os.makedirs('Android/video')
        today = ((datetime.datetime.now() - datetime.timedelta(days=0)).strftime('%Y_%m_%d_%H_%M_%S'))
        VideoName = f"case_{
      
      today}"

        VideoPath = 'Android/video'
        print("<————————开始录制————————>")
        device.screenrecord(VideoPath + "/" + VideoName + ".mp4")

        # 手机中查找 相关应用
        print("<————————查找抖查查————————>")
        while True:
            device.press("home")
            device.press("home")
            text_list = [ele.text for ele in device.xpath('//android.widget.TextView').all()]
            if "抖查查" not in text_list:
                device.swipe_ext('left', scale=0.9)
            else:
                device(text="抖查查").click()
                time.sleep(5)
                try:
                    device(resourceId="com.xxxxx.xxxxx:id/iv_dialog_active_close").click()
                except:
                    print("不存在弹窗活动弹窗!!!")
                break


        # 登录
        def AndroidLogin():
            try:
                device.xpath(
                    '//*[@resource-id="com.xxxxx.xxxxx:id/ll_user_top"]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]').click()
            except:
                print('非"我的"页面进行登录')
            device(text="密码登录").click()
            device(resourceId="com.xxxxx.xxxxx:id/cb").click()
            device(text="请输入手机号").set_text("18730301074")
            device(text="请输入密码").set_text("ceshi123")
            device(text="登录").click()


        # 退出登录
        def AndroidLogout():
            device(resourceId="com.xxxxx.xxxxx:id/tv_user_setting").click()
            device(resourceId="com.xxxxx.xxxxx:id/btnLogout").click()
            device(resourceId="com.xxxxx.xxxxx:id/tv_logout_confirm").click()


        # 随机输入 1 个字
        def InputGbk2312():
            head = random.randint(0xb0, 0xf7)
            body = random.randint(0xa1, 0xfe)
            val = f'{
      
      head:x}{
      
      body:x}'
            str = bytes.fromhex(val).decode('gb2312')
            return str


        # 上滑
        def Slide_up():
            device.swipe_ext("up", 0.6)


        # 下拉
        def Slide_down():
            device.swipe_ext("down", 0.6)


        # 读取文档,获取case
        with open('Android/ExecuteCodeAndroid.text', 'r', encoding='UTF-8') as code_find:
            # 解析case
            code_list = [code_i.split('、')[1].replace('\n', '').split(' - ') for code_i in code_find.readlines()]
            for i in range(len(code_list)):
                for code_list_i in code_list[i]:
                    time.sleep(1)
                    # 获取当前页面文案,判断是否有弹窗
                    print('判断是否有弹窗')
                    Tips = [elem.text for elem in device.xpath('//android.widget.TextView').all()]
                    if "个人信息保护指引" in Tips:
                        device(resourceId="com.xxxxx.xxxxx:id/tv_dialog_agreement_confirm").click()
                        device.swipe_ext("left", 0.6)
                        device.swipe_ext("left", 0.6)
                        device(resourceId="com.xxxxx.xxxxx:id/btn_item_welcome").click()
                    elif "如遇问题请添加抖查查客服" in Tips:
                        device.xpath(
                            '//*[@resource-id="com.xxxxx.xxxxx:id/centerPopupContainer"]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]').click()
                    elif "信息走失啦" in Tips:
                        device.xpath('//*[@text="刷新"]').click()
                    elif "暂无数据" in Tips:
                        device.xpath('//*[@text="稍后再试"]').click()
                    elif "访问过于频繁" in Tips:
                        device.xpath('//*[@text="稍后再试"]').click()
                    elif "您当前账号登录" in Tips:
                        device.xpath('//*[@text="取消"]').click()
                    # 解析后长度大于等于 2 的时候
                    if len(code_list_i.split('>')) >= 2:
                        if 'xpath' in code_list_i.split('>')[1]:
                            print("xpath", code_list_i.split('>')[1])
                            xpath_code = code_list_i.split('>')[1].split("xpath('")[1].split("')")[0]
                            print(f"device.xpath('{
      
      xpath_code}').click()")
                            device.xpath(f'{
      
      xpath_code}').click()
                        else:
                            # if ", text=" in code_list_i.split('>')[1]:
                            #     print(", text", code_list_i.split('>')[1])
                            #     resourceId_ = code_list_i.split('>')[1].split(', text="')[0]
                            #     text_ = code_list_i.split('>')[1].split(', text="')[1].replace('"', '')
                            #     print(resourceId_, text_)
                            #     print(f'device(resourceId="{resourceId_}", text="{text_}").click()')
                            #     device(resourceId=f"{resourceId_}", text=f"{text_}").click()
                            # # 该执行方式有误,网上说没有打开USB点击模式?  没有找到在哪里
                            # # 再就是还有 UI 结构层次混乱,从而导致元素选择器获取不到指定元素
                            # else:
                            if "text" in code_list_i.split(">")[1]:
                                text_name = code_list_i.split(">")[1].split('(text="')[1].split('")')[0]
                                print("text", code_list_i.split(">")[1])
                                device(text=f"{
      
      text_name}").click()
                            else:
                                print("resourceId", code_list_i.split(">")[1])
                                device(resourceId=f"{
      
      code_list_i.split('>')[1]}").click()
                    # 小于 2
                    elif code_list_i.split('>')[0] == "登录":
                        AndroidLogin()
                    elif code_list_i.split('>')[0] == "退出登录":
                        AndroidLogout()
                    elif code_list_i.split(">")[0] == "输入":
                        device(resourceId="com.xxxxx.xxxxx:id/etSearchEdit").set_text(InputGbk2312())
                        device.send_action('search')
                    elif code_list_i.split('>')[0] == "上滑":
                        print("上滑页面")
                        Slide_up()
                    elif code_list_i.split('>')[0] == "下拉":
                        print("下拉页面")
                        Slide_down()

                #     list_data = [elem.text for elem in device.xpath('//android.widget.TextView').all()]
                # if "暂无相关数据" in list_data:
                #     msg = f"case: {i + 1}"
                #     send_FeiShu("无数据", msg)  # 增加钉钉或飞书报警
        # 结束录制
        print("<————————录制结束————————>")
        device.screenrecord.stop()
    break


Summarize

For example: The above is what I will talk about today. This article is only about the use of uiautomator2+Android+python, and uiautomator2 still has a lot to be discovered, waiting for us to discover.

The automation of ios will be synchronized here in the near future, so stay tuned!


# 总结
例如:以上就是今天要讲的内容,本文仅仅只是对于uiautomator2+Android+python的使用,而uiautomator2依旧有很多待发现的内容,等待我们发现。

近期会将ios的自动化同步到此,敬请期待哦!

Guess you like

Origin blog.csdn.net/weixin_43603846/article/details/126248667