airtest.core.ios.instruct_cmd 源代码

# -*- coding: utf-8 -*-
import subprocess
import time
import sys
import random
import shutil
import platform
import warnings
import threading
import wda
from copy import copy
from functools import partial
from airtest.core.error import AirtestError, LocalDeviceError
from airtest.utils.snippet import reg_cleanup, make_file_executable, get_std_encoding, kill_proc
from airtest.utils.logger import get_logger
from airtest.utils.retry import retries
from airtest.utils.compat import SUBPROCESS_FLAG
from airtest.core.ios.constant import DEFAULT_IPROXY_PATH
from airtest.core.ios.relay import ThreadedTCPServer, TCPRelay

LOGGING = get_logger(__name__)


[文档]class InstructHelper(object): """ ForwardHelper class or help run other Instruction """ def __init__(self, uuid=None): self.subprocessHandle = [] # uuid不是ios手机序列号,而是wda.info['uuid']字段 self.uuid = uuid # 下面_udid这个是真正的手机序列号,检测到是USB设备,才会记录这个字段 self._udid = None self._device = None # 记录曾经使用过的端口号和关闭端口用的方法,方便后续释放端口, _port_using_func[port] = kill_func self._port_using_func = {} reg_cleanup(self.tear_down)
[文档] @staticmethod def builtin_iproxy_path(): # Port forwarding for iOS: # 1. Windows/Mac: iproxy.exe/iproxy -u uid port1 port2 # 2. Ubuntu linux: apt-get install libusbmuxd-tools; iproxy port1 port2 # 3. Use python (low efficiency): python relay.py -t 5100:5100 if shutil.which("iproxy"): return shutil.which("iproxy") system = platform.system() iproxy_path = DEFAULT_IPROXY_PATH.get(system) if iproxy_path: if system == "Darwin": make_file_executable(iproxy_path) return iproxy_path warnings.warn("Please install iproxy for a better experience(Ubuntu Linux): apt-get install libusbmuxd-tools") return None
@property def usb_device(self): """ Whether the current iOS uses the local USB interface, if so, return the wda.usbmux.Device object 当前iOS是否使用了本地USB接口,如果是,返回wda.usbmux.Device对象 Returns: wda.usbmux.Device or None """ if not self._device: # wda无法直接获取iOS的udid,因此先检查usb连接的手机udid列表 try: device_list = wda.usbmux.Usbmux().device_list() except ConnectionRefusedError: # windows上必须要先启动iTunes才能获取到iOS设备列表 LOGGING.warning("If you are using iOS device in windows, please check if iTunes is launched") return None except Exception as e: # 其他异常,例如 socket unix:/var/run/usbmuxd unable to connect print(e) return None for dev in device_list: udid = dev.get('SerialNumber') usb_dev = wda.Client(url=wda.requests_usbmux.DEFAULT_SCHEME + udid) # 对比wda.info获取到的uuid是否一致 try: if usb_dev.info['uuid'] == self.uuid: self._device = wda.usbmux.Device(udid) self._udid = udid except: return None return self._device
[文档] def tear_down(self): # 退出时的清理操作,目前暂时只有清理端口 using_ports = copy(list(self._port_using_func.keys())) for port in using_ports: try: kill_func = self._port_using_func.pop(port) kill_func() except: continue
# this function auto gen local port
[文档] @retries(3) def setup_proxy(self, device_port): """ Map a port number on an iOS device to a random port number on the machine 映射iOS设备上某个端口号到本机的随机端口号 Args: device_port: The port number to be mapped on the ios device Returns: """ if not self.usb_device: raise LocalDeviceError("Currently only supports port forwarding for locally connected iOS devices") local_port = random.randint(11111, 20000) self.do_proxy(local_port, device_port) return local_port, device_port
[文档] def remove_proxy(self, local_port): if local_port in self._port_using_func: kill_func = self._port_using_func.pop(local_port) kill_func()
[文档] def do_proxy(self, port, device_port): """ Start do proxy of ios device and self device 目前只支持本地USB连接的手机进行端口转发,远程手机暂时不支持 Returns: None """ if not self.usb_device: raise LocalDeviceError("Currently only supports port forwarding for locally connected iOS devices") proxy_process = self.builtin_iproxy_path() or shutil.which("tidevice") if proxy_process: cmds = [proxy_process, "-u", self._udid, str(port), str(device_port)] else: # Port forwarding using python self.do_proxy_usbmux(port, device_port) return # Port forwarding using iproxy # e.g. cmds=['/usr/local/bin/iproxy', '-u', '00008020-001270842E88002E', '11565', '5001'] proc = subprocess.Popen( cmds, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=SUBPROCESS_FLAG ) # something like port binding fail time.sleep(0.5) if proc.poll() is not None: stdout, stderr = proc.communicate() stdout = stdout.decode(get_std_encoding(sys.stdout)) stderr = stderr.decode(get_std_encoding(sys.stderr)) raise AirtestError((stdout, stderr)) self._port_using_func[port] = partial(kill_proc, proc)
[文档] def do_proxy_usbmux(self, lport, rport): """ Mapping ports of local USB devices using python multithreading 使用python多线程对本地USB设备的端口进行映射(当前仅使用USB连接一台iOS时才可用) Args: lport: local port rport: remote port Returns: """ server = ThreadedTCPServer(("localhost", lport), TCPRelay) server.rport = rport server.device = self.usb_device server.bufsize = 128 self.server = server self.server_thread = threading.Thread(target=self.server.serve_forever) self.server_thread.daemon = True self.server_thread.start() self._port_using_func[lport] = self.server.shutdown
if __name__ == '__main__': ins = InstructHelper() ins.do_proxy_usbmux(5001, 5001)