基本封装了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)