Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 21 additions & 10 deletions driver/connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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()
10 changes: 6 additions & 4 deletions init/tunnel.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
69 changes: 39 additions & 30 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
import coloredlogs
import os
import asyncio

from driver import location

Expand All @@ -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():
Expand All @@ -52,30 +61,31 @@ 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}")

# get route
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)")
Expand All @@ -86,8 +96,7 @@ def main():
process.terminate()
logger.info("tunnel process terminated")
print("Bye")



if __name__ == "__main__":
main()
main()
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
pymobiledevice3==2.46.1
pymobiledevice3==4.14.11
PyYAML==6.0.1
geopy==2.4.1