diff --git a/driver/connect.py b/driver/connect.py index b4be45d..2550e0f 100644 --- a/driver/connect.py +++ b/driver/connect.py @@ -3,10 +3,15 @@ from pymobiledevice3.lockdown import create_using_usbmux, LockdownClient -from pymobiledevice3.cli.remote import install_driver_if_required -from pymobiledevice3.cli.remote import select_device, RemoteServiceDiscoveryService -from pymobiledevice3.cli.remote import start_tunnel -from pymobiledevice3.cli.remote import verify_tunnel_imports +# select_device and install_driver_if_required were +# already deprecated in pymobiledevice3 v4.14.11 +from pymobiledevice3.remote.utils import get_rsds +from pymobiledevice3.cli.remote import RemoteServiceDiscoveryService +from pymobiledevice3.remote.tunnel_service import ( + start_tunnel, + create_core_device_tunnel_service_using_rsd, + TunnelProtocol +) from pymobiledevice3.services.amfi import AmfiService @@ -42,14 +47,20 @@ def reveal_developer_mode(lockdown: LockdownClient): def enable_developer_mode(lockdown: LockdownClient): AmfiService(lockdown).enable_developer_mode() -def get_serverrsd(): - install_driver_if_required() - if not verify_tunnel_imports(): - exit(1) - return select_device(None) + +async def get_serverrsd(): + # install_driver_if_required() not required in MacOS + rsds = await get_rsds() + if not rsds: + raise NoDeviceConnectedError("未发现可用设备或 RSD 服务") + rsd = rsds[0] + return rsd async def tunnel(rsd: RemoteServiceDiscoveryService, queue: multiprocessing.Queue): - async with start_tunnel(rsd, None) as tunnel_result: + # 先构造协议处理器(CoreDeviceTunnelService) + service = await create_core_device_tunnel_service_using_rsd(rsd) + # ios18.7 测试,改用 TCP 协议才能成功 + async with start_tunnel(service, protocol=TunnelProtocol.TCP) as tunnel_result: queue.put((tunnel_result.address, tunnel_result.port)) await tunnel_result.client.wait_closed() diff --git a/init/tunnel.py b/init/tunnel.py index 5119d90..2b5adab 100644 --- a/init/tunnel.py +++ b/init/tunnel.py @@ -3,17 +3,19 @@ from driver import connect -def tunnel_proc(queue: multiprocessing.Queue): - server_rsd = connect.get_serverrsd() - asyncio.run(connect.tunnel(server_rsd, queue)) +async def _tunnel_proc_async(queue: multiprocessing.Queue): + server_rsd = await connect.get_serverrsd() + await connect.tunnel(server_rsd, queue) +def tunnel_proc(queue: multiprocessing.Queue): + asyncio.run(_tunnel_proc_async(queue)) def tunnel(): # start the tunnel in another process queue = multiprocessing.Queue() process = multiprocessing.Process(target=tunnel_proc, args=(queue,)) process.start() - + # get the address and port of the tunnel address, port = queue.get() diff --git a/main.py b/main.py index cb273db..e118ce6 100644 --- a/main.py +++ b/main.py @@ -2,6 +2,7 @@ import logging import coloredlogs import os +import asyncio from driver import location @@ -21,17 +22,25 @@ # set logging level coloredlogs.install(level=logging.INFO) -logging.getLogger('wintun').setLevel(logging.DEBUG if debug else logging.WARNING) +logging.getLogger('wintun').setLevel( + logging.DEBUG if debug else logging.WARNING) logging.getLogger('quic').setLevel(logging.DEBUG if debug else logging.WARNING) -logging.getLogger('asyncio').setLevel(logging.DEBUG if debug else logging.WARNING) -logging.getLogger('zeroconf').setLevel(logging.DEBUG if debug else logging.WARNING) -logging.getLogger('parso.cache').setLevel(logging.DEBUG if debug else logging.WARNING) -logging.getLogger('parso.cache.pickle').setLevel(logging.DEBUG if debug else logging.WARNING) -logging.getLogger('parso.python.diff').setLevel(logging.DEBUG if debug else logging.WARNING) -logging.getLogger('humanfriendly.prompts').setLevel(logging.DEBUG if debug else logging.WARNING) -logging.getLogger('blib2to3.pgen2.driver').setLevel(logging.DEBUG if debug else logging.WARNING) -logging.getLogger('urllib3.connectionpool').setLevel(logging.DEBUG if debug else logging.WARNING) - +logging.getLogger('asyncio').setLevel( + logging.DEBUG if debug else logging.WARNING) +logging.getLogger('zeroconf').setLevel( + logging.DEBUG if debug else logging.WARNING) +logging.getLogger('parso.cache').setLevel( + logging.DEBUG if debug else logging.WARNING) +logging.getLogger('parso.cache.pickle').setLevel( + logging.DEBUG if debug else logging.WARNING) +logging.getLogger('parso.python.diff').setLevel( + logging.DEBUG if debug else logging.WARNING) +logging.getLogger('humanfriendly.prompts').setLevel( + logging.DEBUG if debug else logging.WARNING) +logging.getLogger('blib2to3.pgen2.driver').setLevel( + logging.DEBUG if debug else logging.WARNING) +logging.getLogger('urllib3.connectionpool').setLevel( + logging.DEBUG if debug else logging.WARNING) def main(): @@ -52,6 +61,10 @@ def main(): process, address, port = tunnel.tunnel() signal.signal(signal.SIGINT, original_sigint_handler) logger.info("tunnel started") + + # pymobiledevice3 v4.14.11 RemoteServiceDiscoveryService 只实现了异步上下文管理器 + rsd = RemoteServiceDiscoveryService((address, port)) + asyncio.run(rsd.connect()) try: logger.debug(f"tunnel address: {address}, port: {port}") @@ -59,23 +72,20 @@ def main(): loc = route.get_route() logger.info(f"got route from {config.config.routeConfig}") - - with RemoteServiceDiscoveryService((address, port)) as rsd: - with DvtSecureSocketProxyService(rsd) as dvt: - try: - print(f"已开始模拟跑步,速度大约为 {config.config.v} m/s") - print("会无限循环,按 Ctrl+C 退出") - print("请勿直接关闭窗口,否则无法还原正常定位") - run.run(dvt, loc, config.config.v) - except KeyboardInterrupt: - logger.debug("get KeyboardInterrupt (inner)") - logger.debug(f"Is process alive? {process.is_alive()}") - finally: - logger.debug(f"Is process alive? {process.is_alive()}") - logger.debug("Start to clear location") - location.clear_location(dvt) - logger.info("Location cleared") - + with DvtSecureSocketProxyService(rsd) as dvt: + try: + print(f"已开始模拟跑步,速度大约为 {config.config.v} m/s") + print("会无限循环,按 Ctrl+C 退出") + print("请勿直接关闭窗口,否则无法还原正常定位") + run.run(dvt, loc, config.config.v) + except KeyboardInterrupt: + logger.debug("get KeyboardInterrupt (inner)") + logger.debug(f"Is process alive? {process.is_alive()}") + finally: + logger.debug(f"Is process alive? {process.is_alive()}") + logger.debug("Start to clear location") + location.clear_location(dvt) + logger.info("Location cleared") except KeyboardInterrupt: logger.debug("get KeyboardInterrupt (outer)") @@ -86,8 +96,7 @@ def main(): process.terminate() logger.info("tunnel process terminated") print("Bye") - - + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/requirements.txt b/requirements.txt index a35c754..0090961 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -pymobiledevice3==2.46.1 +pymobiledevice3==4.14.11 PyYAML==6.0.1 geopy==2.4.1