Python Python3 UI 自动化通过线程解决安装 apk 时的权限弹窗 (二)

xiaoxiao · 2019年06月22日 · 最后由 xiaoxiao 回复于 2019年10月23日 · 2204 次阅读

上篇:https://testerhome.com/topics/19286

我们上一篇的介绍只是启动了线程,在实际项目需要中,可能需要在执行完 case 之后,停掉所有启动的线程。然而,Python 对线程的停止并不是那么友好。那么有什么方法可以更方便地达到此目的呢?经过一些尝试,发现可以通过设置标志位变量来进行操作。以下的例子中,因为涉及到多个 py 类文件,所以这个标志位就需要设置成全局变量。

前提条件:预先安装 uiautomator2,连接好手机后,在终端命令行执行以下命令:

pip3 install uiautomator2

再安装 atx:

python3 -m uiautomator2 init

1、新建 thread_deal_permission_box.py,用于点掉手机设备的相关弹窗,代码如下:

import threading
from global_parameters import GlobalParameters

# 注意:
# 如果本机未安装u2,需要先安装,命令行执行以下命令:
# pip3 install uiautomator2 # 安装u2
# python3 -m uiautomator2 init # 手机自动安装atx, u2APK
# pip3 install --pre -U weditor # 安装UI查看器
# python3 -m weditor # 启动UI查看器

import uiautomator2 as u2
driver = u2.connect("882QADT9UWT")
global_parameters = GlobalParameters()

class ThreadDealPermissionBox(threading.Thread):

    def __init__(self, driver):
        threading.Thread.__init__(self)
        self.driver = driver

    def terminate(self):
        global_parameters.set_value('_flag', True)

    def run(self): # 把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
        while True:
            self.click_permission_box()
            print('Flag:' + str(global_parameters.get_value('_flag')))
            if global_parameters.get_value('_flag'):
                break

    # 处理掉安装apk时的系统弹窗
    def click_permission_box(self):
        try:
            self.driver(text="允许").click_exists(timeout=1.0)
        except:
            pass
        try:
            self.driver(text="确认").click_exists(timeout=1.0)
        except:
            pass
        try:
            self.driver(text="继续安装").click_exists(timeout=1.0)
        except:
            pass
        try:
            self.driver(text="安装").click_exists(timeout=1.0)
        except:
            pass

2、新建 execute.py,封装执行 adb shell 的方法,代码如下:

import subprocess

class Execute():

    # 执行shell
    def shell(self, cmd):
        # 执行cmd命令,如果成功,返回(0, 'xxx');如果失败,返回(1, 'xxx')
        cmd_result = subprocess.getstatusoutput(cmd)
        # print(str(cmd_result))
        exit_code = cmd_result[0]
        output = cmd_result[1]
        if exit_code == 0:
            if 'error' in output:
                print('Maybe something wrong: ' + str(cmd_result))
            return output
        elif exit_code == 1:
            print("Failed to execute cmd: " + cmd)
            return output

3、新建 adb_completely_install.py,用于安装 apk 应用,代码如下:

from execute import Execute
import os
import time
import threading
# 注意:
# 如果本机未安装u2,需要先安装,命令行执行以下命令:
# pip3 install uiautomator2 # 安装u2
# python3 -m uiautomator2 init # 手机自动安装atx, u2APK
# pip3 install --pre -U weditor # 安装UI查看器
# python3 -m weditor # 启动UI查看器
# import uiautomator2 as u2

execute = Execute()
# driver = u2.connect("882QADT9UWT")

# class AdbInstall():
class AdbCompletelyInstall(threading.Thread):

    # 判断apk应用是否已安装到设备
    def is_apk_has_installed(self, package_name, device_id=''):
        if device_id != '':
            cmd = "adb -s " + device_id + " shell pm list package | grep '" + package_name + "'"
        else:
            cmd = "adb shell pm list package | grep '" + package_name + "'"
        result = os.popen(cmd).read()
        if package_name in result:
            return True
        else:
            return False

    # 卸载app应用
    def uninstall_app(self, package_name, device_id=''):
        if device_id != '':
            cmd = 'adb -s ' + device_id +' uninstall ' + package_name
        else:
            cmd = 'adb uninstall ' + package_name
        execute.shell(cmd)
        print("Uninstall app success~")

    # 强制安装
    def overlay_install(self, file_path, device_id=''):
        if device_id != '':
            cmd = 'adb -s ' + device_id + ' install -r ' + file_path
        else:
            cmd = 'adb install -r ' + file_path
        execute.shell(cmd)

    # 完全安装,如果已安装应用,需要卸载,重新安装
    def completely_install(self, file_path, package_name, device_id=''):
        if self.is_apk_has_installed(package_name, device_id):
            self.uninstall_app(package_name)
        print('Begin to install apk...')
        if device_id != '':
            cmd = 'adb -s ' + device_id + ' install -r ' + file_path
        else:
            cmd = 'adb install -r ' + file_path
        res = execute.shell(cmd)
        if str(res) == 'Success':
            print('The apk '+ file_path + ' install successfully')
            count = 0
            while not self.is_apk_has_installed(package_name) or count > 30:
                time.sleep(1)
                print('sleep......')
                count = count + 1
        else:
            print('The apk ' + file_path + ' install failed!!!')

4、新建 global_parameters.py,用于保存全局变量,代码如下:

class GlobalParameters():

    def __init__(self):
        global _global_dict
        _global_dict = {'_flag': False}

    def set_value(self, name, value):
        _global_dict[name] = value

    def get_value(self, name, defValue=None):
        try:
            return _global_dict[name]
        except KeyError:
            return defValue

5、新建 app_engine.py,用于安装启动 app 等,代码如下:

import uiautomator2 as u2
from thread_deal_permission_box import ThreadDealPermissionBox
from adb_completely_install import AdbCompletelyInstall

class AppEngine():

    def setUp(self):

        self.device = '882QADT9UWT'
        self.apk_file = 'xxxxxx.apk'
        self.app_package = 'com.xxx'
        self.app_activity = 'com.xxx.xxx.HomeActivity'

        driver = u2.connect(self.device)

        thread_deal_permission_box = ThreadDealPermissionBox(driver)
        thread_deal_permission_box.start()
        # 完全安装应用
        AdbCompletelyInstall().completely_install(self.apk_file, self.app_package, self.device)
        driver = self.app_start()
        thread_deal_permission_box.terminate()  # 停止线程

        return driver

    # 启动app
    def app_start(self):

        driver = u2.connect(self.device)
        driver.app_start(self.app_package, self.app_activity)

        return driver

    # 关闭app应用
    def app_stop(self):
        driver = u2.connect(self.device)
        driver.app_stop(self.app_package)

app_engine = AppEngine()
app_engine.setUp()

最后,直接在 pycharm 中执行 app_engine.py 文件即可。

共收到 4 条回复 时间 点赞
cccSummary 回复

可以再建多线程,通过传入不同的 deviceId 来操作手机

你好,我想问下,如果想支持多台手机同时运行,怎么弄哈

hljycrgl 回复

之前试过了-g 也并不能安装成功,弹窗不点掉的话,最后依然会失败 [INSTALL_FAILED_USER_RESTRICTED] 我的手机:meizu16😅

adb install -g xxx.apk 直接打开全部权限安装

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册