App操作的命令封装(python)

基本封装了Android常用的命令,IOS部分暂时没有支持太多,等后期慢慢维护 使用方法

from device_command import Device
#获取android设备列表
android_device_list = Device.get_android_devices()
ios_device_list = Device.get_ios_devices()

整体代码

# -*- coding: utf-8 -*

import os
import sys
import platform
import subprocess
import getopt
import re

"""
    python3 reduce函数需要单独引入
"""
try:
  from functools import reduce
except:
  pass

"""
   获取ios和android设备列表的常用命令封装,兼容window linux 和 mac
   ios设备列表需要安装依赖
"""

class Shell:
    def __init__(self):
        pass

    @staticmethod
    def invoke(cmd):
        output, errors = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
        o = output.decode("utf-8")
        return o


# 判断系统类型,windows使用findstr,linux使用grep
system = platform.system()
if system is "Windows":
    find_util = "findstr"
else:
    find_util = "grep"

# 判断是否设置环境变量ANDROID_HOME
if "ANDROID_HOME" in os.environ:
    if system == "Windows":
        command = os.path.join(os.environ["ANDROID_HOME"], "platform-tools", "adb.exe")
    else:
        command = os.path.join(os.environ["ANDROID_HOME"], "platform-tools", "adb")
else:
    print("Adb not found in $ANDROID_HOME path")


class ADB(object):
    """
      参数:  device_id
    """

    def __init__(self, device_id=""):

        if device_id == "":
            self.device_id = ""
        else:
            self.device_id = "-s %s" % device_id

    def adb(self, args):
        cmd = "%s %s %s" % (command, self.device_id, str(args))
        return Shell.invoke(cmd)

    def shell(self, args):
        cmd = "%s %s shell %s" % (command, self.device_id, str(args),)
        return Shell.invoke(cmd)

    def get_device_state(self):
        """
            获取设备状态: offline | bootloader | device
        """
        return self.adb("get-state").stdout.read().strip()

    def get_device_id(self):
        """
            获取设备id号,return serialNo
        """
        return self.adb("get-serialno").stdout.read().strip()

    def get_android_version(self):
        """
            获取设备中的Android版本号,如4.2.2
        """
        return self.shell(
            "getprop ro.build.version.release").strip()

    def get_sdk_version(self):
        """
            获取设备SDK版本号,如:24
        """
        return self.shell("getprop ro.build.version.sdk").strip()

    def get_product_brand(self):
        """
            获取设备品牌,如:HUAWEI
        """
        return self.shell("getprop ro.product.brand").strip()

    def get_product_model(self):
        """
            获取设备型号,如:MHA-AL00
        """
        return self.shell("getprop ro.product.model").strip()

    def get_product_rom(self):
        """
            获取设备ROM名,如:MHA-AL00C00B213
        """
        return self.shell("getprop ro.build.display.id").strip()

    def get_device_displays(self):
        """
            获取设备的分辨率
        """
        return self.shell("wm size | awk -F':' '{print $2}'").strip()

    def push_file(self, srcFile, deviceFile):
        """
            推送文件或者文件夹到设备
        """
        cmd = "push %s %s" % (srcFile, deviceFile)
        return self.adb(cmd).strip()

    def pull_file(self,srcFile,deviceFile):
        """
            从设备中拉取文件或者文件夹
        """
        cmd = "pull %s %s" % (deviceFile, srcFile)
        return self.adb(cmd).strip()

    def is_installed_app(self, packageName):
        """
            判断是否安装了app
        """
        return (packageName in self.get_package_list())

    def get_package_list(self):
        """
            获取设备安装的应用列表
        """
        result = self.shell("pm list packages").strip().replace('package:', '')
        return list(map(lambda item : item.strip(),result.split('\n')))

    def install_app(self, apkFile):
        """
            安装apk, 默认强制安装,并且支持低版本覆盖
        """
        if os.path.exists(apkFile):
            self.adb("install -r -d %s" % apkFile)
        else:
            print("%s : No such file" % apkFile)

    def uninstall_app(self, packageName):
        """
            卸载应用
        """
        if self.is_installed_app(packageName):
            self.adb("uninstall %s" % packageName)
        print("success")


    def get_app_mem(self, packageName):
        """
            获取app的内存占用(KB)
        """
        cmd = "dumpsys meminfo %s | %s TOTAL" % (packageName, "findstr" if system is "Windows" else "grep")
        return int(re.findall("\d+", self.shell(cmd).strip())[0])


    def get_cpu_info(self, packageName):
        """
            获取某一时间CPU时间片信息,app_used(应用占用), total(全部)
        """
        def to_int(x):
            try:
                x = int(x)
            except:
                x = 0
            return x  

        total_result = self.shell("cat /proc/stat")
        num_list = list(map(to_int,re.findall('\d+',total_result.split("cpu")[1])[0:7]))
        total = reduce(lambda x,y: x+y, num_list)

        pid = self.get_pid(packageName)
        app_result = self.shell("cat /proc/%s/stat" % pid)
        num_list = list(map(to_int, app_result.split(" ")))
        app_used = num_list[13] + num_list[14]
        return app_used, total



    def get_pid(self, packageName):
        """
            获取进程pid
        """
        if system is "Windows":
            pidInfo = self.shell("ps | findstr %s$" % packageName)
        else:
            pidInfo = self.shell("ps | grep -w %s" % packageName)

        if pidInfo == '':
            return "%s : the process doesn't exist." % packageName

        pattern = re.compile(r"\d+")
        result = pidInfo.split(" ")
        result.remove(result[0])

        return pattern.findall(" ".join(result))[0]

    def kill_process(self, pid):
        """
            杀死应用进程
        """
        if self.shell("kill %s" % str(pid)).stdout.read().split(": ")[-1] == "":
            return "kill success"
        else:
            return self.shell("kill %s" % str(pid)).stdout.read().split(": ")[-1]


class DeviceInfo:
    def __init__(self, udid, platform, platformVersion, brand, model,displays):
        self.udid = udid
        self.platform = platform
        self.platformVersion = platformVersion
        #self.sdk_version = sdk_version
        self.brand = brand
        self.modelNo = model
        self.deviceName = '{brand} {modelNo}'.format(brand=brand,modelNo=model)
        self.displays = displays


class Device:
    def __init__(self):
        pass

    @staticmethod
    def get_android_devices():
        android_devices_list = []
        android_devices_infos = []
        for device in Shell.invoke('adb devices').splitlines():
            if 'device' in device and 'devices' not in device:
                device = device.split('\t')[0]
                android_devices_list.append(device)
        for device_udid in android_devices_list:
            adb = ADB(device_udid)
            device_info = DeviceInfo(device_udid, "ANDROID", adb.get_android_version(),
                                     adb.get_product_brand(), adb.get_product_model(),adb.get_device_displays())
            android_devices_infos.append(device_info.__dict__)
        return android_devices_infos

    @staticmethod
    def get_ios_devices():
        devices = []
        output = Shell.invoke('idevice_id -l')

        if len(output) > 0:
            udids = output.split('\n')
            udids.pop()
            for udid in udids:
                dic = {"platform": 'IOS', "udid": udid}
                shell_command = 'ideviceinfo -u %s -k ProductType' % udid
                print(shell_command)
                output = Shell.invoke(shell_command)
                print(output)
                device_type = config[output.strip('\n')]
                brand = ''
                # -1表示找不到 0表示下标
                if device_type.find("iPhone") != -1:
                    brand = 'iPhone'
                elif device_type.find("iPad") != -1:
                    brand = 'iPad'
                elif device_type.find("iPod") != -1:
                    brand = 'iPod'

                dic['brand'] = brand
                dic['modelNo'] = device_type

                output = Shell.invoke('ideviceinfo -u %s -k ProductVersion' % udid)
                dic['platform'] = 'IOS'
                dic['platformVersion'] = output.strip('\n')

                output = Shell.invoke('idevicename -u %s' % udid)
                dic['deviceName'] = output.strip('\n')
                dic['displays'] = '1680X1920'
                devices.append(dic)
        return devices


class Apk:
    def __init__(self, apkFile):
        if os.path.exists(apkFile):
            self.apkFile = apkFile
        else:
            raise Exception("%s : No such file" % apkFile)

        self.__init()

    def __invoke(self):
        """
            执行命令获取apk信息
        """
        return Shell.invoke("aapt dump badging %s" % self.apkFile)

    def __init(self):
        """
            初始化内容
        """
        self.__analyse(self.__invoke())

    def __analyse(self, result):
        """
            处理apk信息
        """
        temp_dict = {}
        # 可以简化为只用一次正则匹配 '(.*?)' 即可以一次性获取所有内容,此处多次使用正则为了保证准确性
        temp_dict.setdefault("packageName", re.findall("name='(.*?)'", result)[0])
        temp_dict.setdefault("permissions", re.findall("uses-permission: name='(.*?)'", result))
        temp_dict.setdefault("versionName", re.findall("versionName='(.*?)'", result)[0])
        # temp_dict.setdefault("compileSdkVersion", re.findall("compileSdkVersion='(.*?)'", result)[0])
        temp_dict.setdefault("sdkVersion", re.findall("sdkVersion:'(.*?)'", result)[0])
        temp_dict.setdefault("targetSdkVersion", re.findall("sdkVersion:'(.*?)'", result)[0])
        self.__dict = temp_dict

    def get_apk_full_info(self):
        """
            获取apk完整信息
        """
        return self.__dict


    def get_apk_package_name(self):
        """
            获取apk包名
        """
        return self.__dict.get("packageName", None)

    def get_apk_version(self):
        """
            获取apk版本号
        """
        return self.__dict.get("versionName", None)

    def get_apk_permissions(self):
        """
            获取apk权限列表
        """
        return self.__dict.get("permissions", [])

    def get_sdk_version(self):
        """
            获取apk sdk version
        """
        return self.__dict.get("sdkVersion", None)

    def get_target_apk_version(self):
        """
            获取apk targetSdkVersion
        """
        return self.__dict.get("targetSdkVersion", None)