Android设备连接Profiler有两种方式,一种是直接通过IP进行连接,需要手机和电脑处于可连通的网络环境中;另一种是借助ADB命令,使用USB进行连接。我通常都是使用USB的方式,网络连通这个条件可能在大多数工作环境下都比较困难,相比之下使用USB就很方便了,还不用输一串的IP地址。不过USB方式需要执行一个连接转发的命令:
adb forward tcp:54999 localabstract:Unity-{insert bundle identifier here}
之前的很长一段时间里,我都是把这个命令放到印象笔记里,用的时候复制出来执行。因为游戏的包名通常不会变,所以这个命令基本是固定的。
前几天翻项目共享盘的时候,发现了一个执行上面命令的bat脚本。这是一种更方便的方式,写好脚本放在桌面上,需要的时候双击即可执行。这个脚本方便是方便,却有个小缺陷,无论命令是否执行成功,都会输出连接成功……然后我强迫症就犯了……
虽然想把问题解决掉,可我不会bat命令啊,也不想去学……然后就用Python重写了一个自己用的~
import subprocess
import os
# ADB命令所在路径,例:r'D:\android-sdk-windows\platform-tools\adb.exe'
ADB_Path = None
# 游戏包名(package),例:'com.walsite.game'
App_Package = None
def is_adb_valid():
"""
判断ADB命令是否已经添加到环境变量
:rtype: bool
"""
proc = subprocess.run('adb help', shell=True, stderr=subprocess.PIPE)
return proc.returncode == 0
def forward_adb_cmd(adb: str, package: str):
"""
执行连接Profiler的命令
:param adb: adb命令所在的路径
:param package: 游戏包名
:return: 返回命令执行是否成功
:rtype: bool
"""
cmd = adb + ' forward tcp:54999 localabstract:Unity-' + package
return os.system(cmd) == 0
def main():
package = App_Package
if package is None or '' == package:
package = input('请输入游戏的包名(package):')
adb = ADB_Path
if adb is None or '' == adb:
if is_adb_valid():
adb = 'adb'
else:
adb = input('请输入adb完整路径:')
if forward_adb_cmd(adb, package):
print('执行成功~')
else:
print('\n')
print('* ' * 20)
print('操作失败!!')
print('* ' * 20, '\n')
os.system('pause')
if __name__ == '__main__':
main()
代码逻辑很简单,这里简单介绍下用来执行cmd命令的两个标准库函数。
1) os.system(command: str)
# 执行cmd命令,它会返回执行结果的状态码。
# 命令产生的输出,会直接显示到命令行中,不会通过返回值返回。
# command:要执行的命令
2) subprocess.run(args, shell: bool, stderr)
# 这个函数的功能比较丰富,参数也很多,这里只摘取了用到的部分,功能说明也不代表其全部。
# 通过它判断命令是否执行成功,并且不让命令输出显示出来。
# args: 要执行的命令,这里使用拼接好的str。
# shell: 标记为是否是shell模式。
# stderr:设定标准错误输出的位置,这里为了不让命令的产生的输出显示到命令行上,
# 将标准输出指向了PIPE。
is_adb_valid这个函数也值得说一下。通常我们检查环境变量是否配置正确,都会在cmd里直接执行一个命令,如果输出和这个命令相关的内容,就代表配置成功。比如配置ADB的时候,会直接执行<code>adb</code>,然后命令行会输出ADB命令的帮助文档。这一现象看似是命令执行成功了,实际却是失败了。我想这应该是ADB命令的一种处理错误的方式把,接收到错误的命令时会输出help信息,帮助使用者纠正错误。
由于在Python里执行cmd命令只能获得错误码,所以做验证时必须使用一个能返回“执行成功”错误码(0)的命令,也就是这里选择的<code>adb help</code>。它不需要多余变量参数与条件,只要ADB在环境变量中配置正确,它就会返回“执行成功”。
昨天加班用这个命令的时候输出了一个错误消息:<code>error: more than one device/emulator</code>
它的意思大概是“当前连接了多个设备,不知道该选择哪一个”,但是我只连了一个测试机。这个问题出现频率还挺高的,我就遇到过好多次,不过原因一直没找到。使用<code>adb kill-server</code>断开所有连接可以解决问题。我调整了下脚本,把这个问题加进去了,完整代码可参考profiler_by_adb。
修改的两个关键点:
1)使用<code>subprocess.run</code>执行命令,通过返回的CompletedProcess.stderr获得错误消息
2)调用run时设置参数<code>universal_newlines=True</code>保证stderr是文本形式(不指定这个参数的话,如果发生了异常,stderr返回的是bytes信息,无法定位问题)