前言
作为一名测试工程师,工作中免不了会接触移动端测试工作,对于Android
而言,可以使用adb
与Android
设备进行通信,从而实现快捷安装、卸载、抓取日志、获取性能数据等功能,但对于Ios
来说好像会变得困难一些,幸好有大佬已经开源出相关工具tidevice
,该工具用于与iOS设备进行通信,还不了解的同学可以安装使用了解。当然用法并不是我们研究的重点,使用方法在作者提供的文档中已经详细介绍,我们主要研究学习作者的源码,到底是如何实现这样一款强大的工具呢?
usbmuxd
在研究源码之前,我们先了解一下,usbmuxd
是啥呢?这样有助于我们更好的查看源码。
usbmuxd的作用
usbmuxd是一个开源的守护进程,用于在iOS设备和计算机之间建立通信通道。它可以让计算机通过USB连接与iOS设备进行通信,以便进行诸如文件传输、应用程序安装和调试等操作。
具体来说,usbmuxd的主要作用包括以下几个方面:
- 监听来自iOS设备的USB连接请求。
- 为每个连接到计算机的iOS设备创建一个TCP端口。
- 将设备上的服务映射到TCP端口上。
- 允许计算机上运行的应用程序通过TCP/IP协议与设备进行通信,而无需直接使用USB。
usbmuxd的工作原理
usbmuxd的工作原理可以简单概括为以下几个步骤:
- usbmuxd监听来自iOS设备的USB连接请求。
- 当设备连接到计算机时,usbmuxd为该设备创建一个TCP端口。
- usbmuxd将设备上的服务映射到该TCP端口上。
- 应用程序通过TCP/IP协议与设备进行通信,而无需直接使用USB。
具体来说,当iOS设备连接到计算机时,它会发送一个USB连接请求。usbmuxd会监听这个请求,并为该设备创建一个TCP端口。然后,usbmuxd会将设备上的服务映射到该TCP端口上,例如文件传输服务、调试服务等。最后,应用程序可以通过TCP/IP协议与设备进行通信,例如使用SSH协议进行远程登录、使用iFuse工具进行文件系统挂载等。
usbmuxd的使用方法
usbmuxd是一个跨平台的工具,可以在Linux、macOS和Windows等操作系统上运行。它是开源的,并且可以在GitHub上找到其源代码。它还提供了一些命令行工具,例如iproxy和ifuse,可以帮助开发人员更方便地与iOS设备进行交互。
使用usbmuxd进行iOS开发需要以下几个步骤:
- 安装usbmuxd工具和相关驱动程序。
- 连接iOS设备到计算机上。
- 启动usbmuxd守护进程。
- 使用相关命令行工具进行文件传输、调试等操作。
一句话
简单点说,其实usbmuxd
就是一个服务。而tidevice
本质上应该是usbmuxd
服务的client
案例解读
tidevice
是如何实现这个client
?
tidevice/_usbmux.py
python
class Usbmux:
def __init__(self, address: Optional[Union[str, tuple]] = None):
pass
@property
def address(self) -> str:
pass
def _next_tag(self) -> int:
pass
def create_connection(self) -> PlistSocketProxy:
pass
def send_recv(self, payload: dict, timeout: float = None) -> dict:
pass
def device_list(self) -> typing.List[DeviceInfo]:
pass
def device_udid_list(self) -> typing.List[str]:
pass
def _check(self, data: dict):
pass
def read_system_BUID(self) -> str:
pass
def _gen_host_id(self):
pass
def watch_device(self) -> typing.Iterator[dict]:
pass
def connect_device_port(self, devid: int, port: int) -> PlistSocketProxy:
pass
我们讲解一下这个类的作用,方法的具体实现大家可以去翻源码,文章就不贴了显得都是代码不易阅读:
这是一个名为Usbmux
的类,它用于管理与USB设备进行通信的功能。下面是每个方法的作用:
__init__(self, address: Optional[Union[str, tuple]] = None)
: 这个方法是类的构造函数,用于初始化Usbmux
对象。它接受一个可选的address
参数,用于指定usbmuxd服务的地址。如果未指定address
,则根据操作系统类型自动设置默认地址。address(self) -> str
: 这是一个属性方法,用于获取usbmuxd服务的地址。_next_tag(self) -> int
: 这是一个私有方法,用于生成下一个标签(tag)值。create_connection(self) -> PlistSocketProxy
: 这个方法用于创建与usbmuxd服务的连接,并返回一个PlistSocketProxy
对象,该对象用于发送和接收数据。send_recv(self, payload: dict, timeout: float = None) -> dict
: 这个方法用于向usbmuxd服务发送请求,并接收响应数据。它接受一个payload
参数,其中包含要发送的数据,还可以指定超时时间。它返回一个包含响应数据的字典。device_list(self) -> typing.List[DeviceInfo]
: 这个方法用于获取连接到计算机的所有USB设备的信息。它向usbmuxd服务发送一个请求来获取设备列表,并将响应数据解析为DeviceInfo
对象列表。最后返回设备列表。device_udid_list(self) -> typing.List[str]
: 这个方法返回连接到计算机的所有USB设备的唯一设备标识符(UDID)列表。_check(self, data: dict)
: 这是一个私有方法,用于检查usbmuxd服务返回的数据是否包含错误信息。如果出现错误,它会引发MuxReplyError
异常。read_system_BUID(self) -> str
: 这个方法用于读取系统的BUID(Baseband Unique ID),它向usbmuxd服务发送一个请求,并返回BUID值。_gen_host_id(self)
: 这是一个私有方法,用于生成主机的唯一标识符。watch_device(self) -> typing.Iterator[dict]
: 这个方法返回一个迭代器,用于监听设备连接和断开的事件。它使用PlistSocketProxy
对象与usbmuxd服务建立连接,发送请求来监听设备事件,并以字典形式返回事件数据。connect_device_port(self, devid: int, port: int) -> PlistSocketProxy
: 这个方法用于连接到指定USB设备的指定端口。它向usbmuxd服务发送一个连接请求,并返回一个PlistSocketProxy
对象,该对象用于与设备进行通信。
方法测试
1、我们调用device_list
来获取设备信息,看看调用结果
scss
from tidevice._usbmux import Usbmux
usbmux = Usbmux()
devices = usbmux.device_list()
print(devices)
打印devices
,输出结果如下:
css
[DeviceInfo(udid='00008020-000B65101E06002E', device_id=3900, conn_type=<ConnectionType.USB: 'usb'>)]
2、我们调用device_udid_list
来获取设备标识符,看看调用结果
scss
uids = usbmux.device_udid_list()
print(uids)
打印uids
,输出结果如下:
css
['00008020-000B65101E06002E']
最后
Usbmux
类提供了与usbmuxd服务交互的各种方法,包括获取设备列表、连接设备端口、监听设备事件等功能。它简化了与USB设备通信的复杂性,并提供了高层次的接口供开发人员使用。当然这里看了一小块,源码中涉及到的PlistSocket
、PlistSocketProxy
我们之后研究的再介绍。