adb的那些使用技巧

ADB相信接触Android的同学不会陌生。Adb很多命令,可以很方便的操作手机。合理使用,会使我们的工作更高效。

ADB出来也很久了,也不是什么高新技术,网上的文章也是多如牛毛。很多只是简单列出命令。

本人就根据自己的实践,总结下这么多年用ADB的经验。

ADB是什么?
ADB是android sdk里的一个工具,adb的全称为AndroidDebug Bridge,就是起到调试桥的作用。
简单的说,Android系统,跟电脑系统,是两个独立的系统,独立的男女方,需要一个媒婆来牵线搭桥。

ADB怎么用?
开发的版本,一般都放在了服务器上,虽然可以从手机浏览器中下载,特别慢,个人喜欢用电脑上的ADB来操作,速度快多了。

apk相关:
1、安装apk
adb install test.apk -r 覆盖安装,保留数据和缓存文件 -d 解决低版本version问题 -s 安装apk到sd卡
2、卸载apk

adb uninstall -k <package_name>

可选参数-k的作用为卸载软件但是保留配置和缓存文件
3、查看app相关所有信息,包括action,codepath,version,需要的权限等等信息

adb shell dumpsys package <package_name>

4、查看app的路径

adb shell pm path <package_name>

查看了一个普通app的路径,如下,位于data/app下面的普通app
package:/data/app/com.tencent.test-1/base.apk
5、查看apk的版本信息

adb shell dumpsys package <package_name> | grep version

如果你得到的是下图的两个version版本,则为系统app,下面是系统app本身的版本,上面是升级之后的系统app的版本信息
versionCode=8 targetSdk=22 versionName=V0.08 versionCode=6 targetSdk=22 versionName=V0.0
6、启动activity

adb shell am start -n <package_name>/.<activity_class_name>

7、获得应用的启动时间,可以很方便地获取应用的启动时间

adb shell am start -W <package_name>/.<activity_class_name>

试验结果如下:

adb shell am start -W com.cc.test/com.painter.test.PainterMainActivity Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.cc.test/com.painter.test.PainterMainActivity } Status: ok Activity: com.cc.test/com.painter.test.PainterMainActivity ThisTime: 355 TotalTime: 355 WaitTime: 365 Complete

返回的几个结果,以WaitTime为准,返回的是从startActivity到应用第一帧完全显示的时间。
8、查看某一个app的内存占用

adb shell dumpsys meminfo <package_name|PID>

结果如下,其中的Heap size包括了Dalvik Heap和Native Heap,平时我们所说的内存限制指的是Dalvik Heap。
9、查看单个应用程序的最大内存限制

adb shell getprop | grep heapgrowthlimit

得到的结果为128M: [dalvik.vm.heapgrowthlimit]: [128m]
这就是说Dalvik Heap size的最大值超过了128M,就很可能发生OOM
10、获取单个应用的电量消耗信息
Battery Historian是Android 5.0开始引入的,下面的命令为获取单个app的电量消耗信息,获取系统耗电信息见下节

adb shell dumpsys batterystats > <package_name> > xxx.txt

以上的命令,在自动化中运用起来很方便。

系统相关
1、查看设备名称,豌豆荚等应用就是通过此来获得设备的名称

adb shell cat /system/build.prop/

结果:

ro.product.model=MI 3W ro.product.brand=Xiaomi

2、查看手机分辨率有两种方法,第二种方法最为简洁
2.1

adb shell dumpsys window | grep Surface

grep是一个非常有用的参数,具体含义和用法大家自行google一下,试验结果为1080 * 1920:
Surface: shown=false layer=21000 alpha=1.0 rect=(0.0,0.0) 1080.0 x 1920.0
2.2.

adb shell wm size

返回结果为:
Physical size: 1080x1920
3、查看手机sdk版本
adb shell getprop | grep version
运行上面的命令后,列出来的version中[ro.build.version.release]: [6.0.1]即为手机sdk版本
4、查看手机型号信息

adb shell getprop | grep product

运行此命令之后,能看到product,board,brand和cpu等等的型号
5、获取序列号,获取到的序列号即为adb devices列出来的序列号

adb get-serialno

6、查看连接的设备

adb devices

如果有多个设备连接,想对其中的某一设备进行操作,就需要在此命令的后面加参数
adb [-d|-e|-s ]   
-d:真机(多个设备中只有一个真机时适用)   
-e:模拟器(多个设备中只有一个模拟器时适用)   
-s:序列号
假如有两个真机连接了我的电脑,adb devices获取到的数据如下
List of devices attached 1b71651 device 12sdfsd device
进入1b71651设备的命令为:
adb -s 1b71651 shell

文件操作相关:
1、拷贝文件/目录到设备

adb push <local>...<remote>

2、从设备拷贝文件/目录,-a参数保留了文件的时间戳和模式

adb pull [-a] <remote>...<local>

3、查看设备log,和studio和eclipse的logcat相同,可通过参数控制输出的日志

adb logcat  

-s 过滤指定参数log
-v time 保留日志时间

当我们测试app的时候,需要用到各种型号的手机。如果发现bug,需要截屏。每个手机的截屏方式不一样,快捷键也不一样。截屏完了以后,需要填写到bug里面,这个过程有的麻烦。

我用adb来截屏,无需了解各种型号手机如何截屏,它自动从手机中保存到电脑中。这样就节约了很多时间。
操作起来很简单:

#!/usr/bin/env python
# Author: Anderson

#利用adb 截取Android手机图像,并且保存到本地

import os
import time

PATH = lambda p: os.path.abspath(p)

def screenshot():
    path = PATH(os.getcwd() + "/screenshot")
    timestamp = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime(time.time()))
    os.popen("adb wait-for-device")
    os.popen("adb shell screencap -p /data/local/tmp/tmp.png")

    if not os.path.isdir(PATH(os.getcwd() + "/screenshot")):
        os.makedirs(path)

    os.popen("adb pull /data/local/tmp/tmp.png " + PATH(path + "/" + timestamp + ".png"))
    os.popen("adb shell rm /data/local/tmp/tmp.png")
    print("success")


if __name__ == "__main__":
    screenshot()

可以把常用的adb 写成一个类,作为自己的库,在自动化测试中灵活调用:

#encoding=utf-8

# Author: Anderson

"""
aadb 工具类
"""

import os
import platform
import re


class AdbTools(object):
    def __init__(self, device_id=''):
        self.__system = platform.system()
        self.__find = ''
        self.__command = ''
        self.__device_id = device_id
        self.__get_find()
        self.__check_adb()
        self.__connection_devices()

    def __get_find(self):
        """
        判断系统类型,windows使用findstr,linux使用grep
        :return:
        """
        if self.__system is "Windows":
            self.__find = "findstr"
        else:
            self.__find = "grep"

    def __check_adb(self):
        """
        检查adb
        判断是否设置环境变量ANDROID_HOME
        :return:
        """
        if "ANDROID_HOME" in os.environ:
            if self.__system == "Windows":
                path = os.path.join(os.environ["ANDROID_HOME"], "platform-tools", "adb.exe")
                if os.path.exists(path):
                    self.__command = path
                else:
                    raise EnvironmentError(
                        "Adb not found in $ANDROID_HOME path: %s." % os.environ["ANDROID_HOME"])
            else:
                path = os.path.join(os.environ["ANDROID_HOME"], "platform-tools", "adb")
                if os.path.exists(path):
                    self.__command = path
                else:
                    raise EnvironmentError(
                        "Adb not found in $ANDROID_HOME path: %s." % os.environ["ANDROID_HOME"])
        else:
            raise EnvironmentError(
                "Adb not found in $ANDROID_HOME path: %s." % os.environ["ANDROID_HOME"])

    def __connection_devices(self):
        """
        连接指定设备,单个设备可不传device_id
        :return:
        """
        if self.__device_id == "":
            return
        self.__device_id = "-s %s" % self.__device_id

    def adb(self, args):
        """
        执行adb命令
        :param args:参数
        :return:
        """
        cmd = "%s %s %s" % (self.__command, self.__device_id, str(args))
        # print(cmd)
        return os.popen(cmd)

    def shell(self, args):
        """
        执行adb shell命令
        :param args:参数
        :return:
        """
        cmd = "%s %s shell %s" % (self.__command, self.__device_id, str(args))
        # print(cmd)
        return os.popen(cmd)

    def mkdir(self, path):
        """
        创建目录
        :param path: 路径
        :return:
        """
        return self.shell('mkdir %s' % path)

    def get_devices(self):
        """
        获取设备列表
        :return:
        """
        l = self.adb('devices').readlines()
        return (i.split()[0] for i in l if 'devices' not in i and len(i) > 5)

    def get_current_application(self):
        """
        获取当前运行的应用信息
        :return:
        """
        return self.shell('dumpsys window w | %s \/ | %s name=' % (self.__find, self.__find)).read()

    def get_current_package(self):
        """
        获取当前运行app包名
        :return:
        """
        reg = re.compile(r'name=(.+?)/')
        return re.findall(reg, self.get_current_application())[0]

    def get_current_activity(self):
        """
        获取当前运行activity
        :return: package/activity
        """
        reg = re.compile(r'name=(.+?)\)')
        return re.findall(reg, self.get_current_application())[0]

    def __get_process(self, package_name):
        """
        获取进程信息
        :param package_name:
        :return:
        """
        if self.__system is "Windows":
            pid_command = self.shell("ps | %s %s$" % (self.__find, package_name)).read()
        else:
            pid_command = self.shell("ps | %s -w %s" % (self.__find, package_name)).read()
        return pid_command

    def process_exists(self, package_name):
        """
        返回进程是否存在
        :param package_name:
        :return:
        """
        process = self.__get_process(package_name)
        return package_name in process

    def get_pid(self, package_name):
        """
        获取pid
        :return:
        """
        pid_command = self.__get_process(package_name)
        if pid_command == '':
            print("The process doesn't exist.")
            return pid_command

        req = re.compile(r"\d+")
        result = str(pid_command).split()
        result.remove(result[0])
        return req.findall(" ".join(result))[0]

    def get_uid(self, pid):
        """
        获取uid
        :param pid:
        :return:
        """
        result = self.shell("cat /proc/%s/status" % pid).readlines()
        for i in result:
            if 'uid' in i.lower():
                return i.split()[1]

    def get_flow_data_tcp(self, uid):
        """
        获取应用tcp流量
        :return:(接收, 发送)
        """
        tcp_rcv = self.shell("cat proc/uid_stat/%s/tcp_rcv" % uid).read().split()[0]
        tcp_snd = self.shell("cat proc/uid_stat/%s/tcp_snd" % uid).read().split()[0]
        return tcp_rcv, tcp_snd

技术在于积累,再基础的东西,如果运用得恰当,能提高工作效率的。

更多精彩,请关注微信公众号:python爱好部落

发布了162 篇原创文章 · 获赞 33 · 访问量 43万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览