14

如何使用 Python 来扩展 adb 命令?

 5 years ago
source link: https://blog.csdn.net/lovecluo/article/details/84572483?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

生死看淡,不服就干!

0x00 缘起

作为一个标准的“工程师”,在控制台使用命令才是我们最终的归宿,看起来才更像大牛,当然,这都是题外话。

在进行 Android 开发时, adb 是我们最常使用的命令之一。

VZ3a2yN.png!web

当你正在调试代码逻辑时,产品同学过来说:“你把你刚发出来的那个提测的 APK 给我装一下呗。”虽然有一万只草尼玛从心中奔腾而过,但还是会屈服于产品的“美貌”,给他安装提测包。接下来,会做什么事情呢:

  1. 将产品同学的手机通过 USB 连接(有时候,你还需要手动去打开 USB 调试);
  2. 找到要安装的 APK 文件;
  3. 使用 adb 命令安装上面步骤中找到的那个 APK。

就在这个时候,你电脑上同时插着多台设备,输入的命令在执行就直接报错了:

error: more than one device/emulator
adb: error: failed to get feature set: more than one device/emulator
- waiting for device -
error: more than one device/emulator

超出了 adb 所支持的设备数,所以,你的步骤变得更非常地复杂。

  1. adb devices 列出你当前的设备列表,然后拷贝你要安装的设备 Device Id
  2. 使用 adb -s deviceId install .... 来进行 APK 安装。

这个步骤重复超过 10 次,你还在重复,请仔细阅读下文,本文将教会你如何解放自己的双手,让你有更多的时间做更多的需求,开不开心[手动坏笑]。

0x01 需求分析

上面问题的痛点是:我在执行命令时,不得不去手动拿到“Device Id”,并且手动设置上去。

类似案例分析:在使用 Android Studio Debug 运行 App 的时候,会让你先选择你要安装到的设备,然后才会进行编译、安装、启动页面。

所以,需要优化“Device Id”的获取方式。我们可以使用脚本来获取当前连接在电脑上的设备,并且给出一个输入的入口,让用户选择要执行命令的设备。

0x02 代码实现

在这里,笔者使用 Python 来实现自动获取“Device Id”的功能。

写好脚本,世界会更加美好。

  • 获取设备列表

    Android SDK 中提供的 adb 工具给我们提供了很多功能,获取设备的命令如下:

    adb devices

    所以,只需要使用 Python 执行这条 Shell 脚本,并解析脚本输出结果,就可以拿到设备列表。代码逻辑如下:

    def readDevicesList():
    	p=os.popen('adb devices') 
    	devicesList=p.read()
    	p.close()
    	lists = devicesList.split("\n")
    	devicesNames = []
    	for item in lists:
    		if(item.strip() == ""):
    			continue
    		elif(item.startswith("List of")) :
    			continue
    		else:
    			devicesNames.append(item.split("\t")[0])
    	return devicesNames

    如上,就可以拿到当前连接在 USB 的设备列表。

  • 让用户选择设备

    从上面拿到了设备列表,让用户输入一个给定的 index,然后去取 index 所对应的 Device Id

    def selectDevices(devicesIds):
    	print "Please Select Devices:"
    	i = 0
    	for deviceId in devicesIds :
    		print "\033[1;34m " + str(i) + ": " + getRealDeviceName(deviceId) + "\033[0m"
    		i += 1
    	print "\033[1;34m e: exit\033[0m"
    	try: 
    		inputIndex = raw_input("Enter your device index [0, " + str(i) + ") :")
    		value = int(inputIndex)
    		if value >= i: 
    			raise Exception("index is to big.")
    		return value
    	except (KeyboardInterrupt, SystemExit) :
    		return -1
    	except Exception as e:
    		if "e" == inputIndex or "E" == inputIndex:
    			return -1
    		else:
    			print "\033[1;31mYour select index is error, please try again.\033[0m"
    			return selectDevices(devicesIds)

    在这里,为了有更好的输出结果,我们需要处理 KeyboardInterrupt , SystemExit 的异常事件,遇到这种异常的时候,就直接终止。当然,我们还需要处理用户输入的字符,防止输入非法字符,引起异常。

    执行结果如下图:

    uyAnYjj.png!web

  • 拼装命令并执行在上面,已经拿到用户要安装的 APK 的 Device Id , 下面我们根据用户的输入命令来生成我们自己的命令。

    def generateShellCommand(deviceId):
    	shellCommand = "adb -s " + deviceId
    	for i in range(1, len(sys.argv)):
    		shellCommand += " " + repr(sys.argv[i])
    	print "execute shell command:"
    	print "  " + shellCommand
    	return shellCommand

    拿到生成的新命令,然后执行。

    if __name__ == '__main__':
    	devicesNames = readDevicesList()
    	if len(devicesNames) <= 0: 
    		print "Please connect your devices."
    	elif len(devicesNames) == 1:
    		shellCommand = generateShellCommand(devicesNames[0])
    		execShellCommand(shellCommand)		
    	else :
    		index = selectDevices(devicesNames)
    		if index != -1: 
    			useDeviceName = devicesNames[index]
    			shellCommand = generateShellCommand(useDeviceName)
    			execShellCommand(shellCommand)
  • 优化显示设备名称

    在前面获取到的 Device Id 列表,直接展示出来给用户选择,其实不太友好,谁会记得自己手机的 Device Id 呢。是吧。所以我们需要在进行一波操作,将 Device Id 转换成用户可以识别的设备名称。

    def getRealDeviceName(deviceId): 
    	p = os.popen('adb -s ' + deviceId + ' shell getprop ro.product.manufacturer')
    	manufacturer = p.read()
    	p.close()
    	p = os.popen('adb -s ' + deviceId + ' shell getprop ro.product.model')
    	model = p.read()
    	p.close()
    	return manufacturer.strip() + " " + model.strip()

    通过 adb 命令去拿到设备的 manufacturermodel 信息。

    VFfiYnU.png!web

    立竿见影的效果。

0x03 总结

Talk is cheap, show me the code.

有很多功能,我们可以一遍一遍的去写手动执行,但是稍加处理,使用少量脚本就可以处理这些问题。追求效率,释放双手。

欢迎关注我的公众号,一起交流技术事。

qUbauan.png!web

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK