Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit d686f9e

Browse files
committed
upgrade pmd3 version from 2 to 4
1 parent cf5f70a commit d686f9e

File tree

6 files changed

+64
-14
lines changed

6 files changed

+64
-14
lines changed

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ readme = "README.md"
99

1010
[tool.poetry.dependencies]
1111
python = "^3.8"
12-
pymobiledevice3 = "^2.46.2"
12+
pymobiledevice3 = "^4.2.3"
1313
click = "*"
1414
pydantic = "^2.5.3"
1515
fastapi = "*"
1616
requests = "*"
1717
numpy = "*"
1818
imageio = {extras = ["ffmpeg"], version = "^2.33.1"}
1919
pillow = "^10.0"
20+
zeroconf = "^0.132.2"
2021

2122
[tool.poetry.group.dev.dependencies]
2223
pytest = "^7.4.4"

tests/test_api.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ def test_api(tmp_path: Path):
1111
for d in list_devices(usb=True):
1212
print("UDID:", d.Identifier)
1313
service_provider = connect_service_provider(d.Identifier)
14-
pil_im = screenshot(service_provider)
15-
pil_im.save(tmp_path / "screenshot.png")
14+
with service_provider:
15+
pil_im = screenshot(service_provider)
16+
pil_im.save(tmp_path / "screenshot.png")

tidevice3/api.py

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,33 @@
33

44
import datetime
55
import io
6+
import logging
67
import os
7-
from typing import Iterator, Optional
8+
import socket
9+
from typing import Any, Dict, Iterator, Optional
810

911
import requests
12+
from packaging.version import Version
1013
from PIL import Image
1114
from pydantic import BaseModel
15+
from pymobiledevice3.common import get_home_folder
16+
from pymobiledevice3.exceptions import AlreadyMountedError
1217
from pymobiledevice3.lockdown import LockdownClient, create_using_usbmux, usbmux
1318
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
1419
from pymobiledevice3.remote.remote_service_discovery import RemoteServiceDiscoveryService
20+
from pymobiledevice3.services.amfi import AmfiService
1521
from pymobiledevice3.services.dvt.dvt_secure_socket_proxy import DvtSecureSocketProxyService
1622
from pymobiledevice3.services.dvt.instruments.device_info import DeviceInfo
1723
from pymobiledevice3.services.dvt.instruments.screenshot import Screenshot
1824
from pymobiledevice3.services.installation_proxy import InstallationProxyService
25+
from pymobiledevice3.services.mobile_image_mounter import auto_mount
1926
from pymobiledevice3.services.screenshot import ScreenshotService
27+
from pymobiledevice3.utils import get_asyncio_loop
2028

2129
from tidevice3.exceptions import FatalError
2230
from tidevice3.utils.download import download_file, is_hyperlink
2331

32+
logger = logging.getLogger(__name__)
2433

2534
class DeviceShortInfo(BaseModel):
2635
BuildVersion: str
@@ -78,15 +87,34 @@ def connect_service_provider(udid: Optional[str], force_usbmux: bool = False, us
7887
return lockdown
7988

8089

81-
def connect_remote_service_discovery_service(udid: str, tunneld_url: str = 'http://localhost:5555') -> RemoteServiceDiscoveryService:
90+
class EnterableRemoteServiceDiscoveryService(RemoteServiceDiscoveryService):
91+
def __enter__(self) -> EnterableRemoteServiceDiscoveryService:
92+
get_asyncio_loop().run_until_complete(self.connect())
93+
return self
94+
95+
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
96+
get_asyncio_loop().run_until_complete(self.close())
97+
98+
99+
def is_port_open(ip: str, port: int) -> bool:
100+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
101+
return s.connect_ex((ip, port)) == 0
102+
103+
104+
def connect_remote_service_discovery_service(udid: str, tunneld_url: str = None) -> EnterableRemoteServiceDiscoveryService:
105+
if tunneld_url is None:
106+
if is_port_open("localhost", 49151):
107+
tunneld_url = "http://localhost:49151"
108+
else:
109+
tunneld_url = "http://localhost:5555" # for backward compatibility
110+
82111
try:
83112
resp = requests.get(tunneld_url, timeout=DEFAULT_TIMEOUT)
84-
tunnels = resp.json()
113+
tunnels: Dict[str, Any] = resp.json()
85114
ipv6_address = tunnels.get(udid)
86115
if ipv6_address is None:
87116
raise FatalError("tunneld not ready for device", udid)
88-
rsd = RemoteServiceDiscoveryService(ipv6_address)
89-
rsd.connect()
117+
rsd = EnterableRemoteServiceDiscoveryService(ipv6_address)
90118
return rsd
91119
except requests.RequestException:
92120
raise FatalError("Please run `sudo t3 tunneld` first")
@@ -136,4 +164,23 @@ def app_install(service_provider: LockdownClient, path_or_url: str):
136164
ipa_path = path_or_url
137165
else:
138166
raise ValueError("local file not found", path_or_url)
139-
InstallationProxyService(lockdown=service_provider).install_from_local(ipa_path)
167+
InstallationProxyService(lockdown=service_provider).install_from_local(ipa_path)
168+
169+
170+
def enable_developer_mode(service_provider: LockdownClient):
171+
""" enable developer mode """
172+
if Version(service_provider.product_version) >= Version("16"):
173+
if not service_provider.developer_mode_status:
174+
logger.info('enable developer mode')
175+
AmfiService(service_provider).enable_developer_mode()
176+
else:
177+
logger.info('developer mode already enabled')
178+
179+
try:
180+
xcode = get_home_folder() / 'Xcode.app'
181+
xcode.mkdir(parents=True, exist_ok=True)
182+
auto_mount(service_provider, xcode=xcode)
183+
logger.info('mount developer image')
184+
except AlreadyMountedError:
185+
logger.info('developer image already mounted')
186+

tidevice3/cli/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def cli_app_install(service_provider: LockdownClient, path_or_url: str):
4040

4141

4242
@app.command("list")
43-
@click.option('app_type', '-t', '--type', type=click.Choice(['System', 'User', 'Hidden', 'Any']), default='Any',
43+
@click.option('app_type', '-t', '--type', type=click.Choice(['System', 'User', 'Hidden', 'Any']), default='User',
4444
help='include only applications of given type')
4545
@click.option("--calculate-sizes/--no-calculate-size", default=False)
4646
@pass_service_provider

tidevice3/cli/relay.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
Ref: https://github.com/doronz88/pymobiledevice3/blob/master/pymobiledevice3/cli/usbmux.py#L32
77
"""
88

9-
from functools import partial
109
import logging
1110
import tempfile
1211
import threading
12+
from functools import partial
13+
1314
import click
1415
from pymobiledevice3.lockdown import LockdownClient
1516
from pymobiledevice3.tcp_forwarder import UsbmuxTcpForwarder

tidevice3/cli/tunneld.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
from fastapi import FastAPI
2020
from packaging.version import Version
2121
from pymobiledevice3.exceptions import MuxException
22-
from pymobiledevice3.cli.cli_common import is_admin_user
22+
from pymobiledevice3.osu.os_utils import OsUtils
2323

2424
from tidevice3.cli.cli_common import cli
2525
from tidevice3.cli.list import list_devices
2626
from tidevice3.utils.common import threadsafe_function
2727

2828
logger = logging.getLogger(__name__)
29-
29+
os_utils = OsUtils.create()
3030

3131
class Address(NamedTuple):
3232
ip: str
@@ -157,7 +157,7 @@ def run_forever(self):
157157
@click.option("--port", "port", help="listen port", default=5555)
158158
def tunneld(pmd3_path: str, port: int):
159159
"""start server for iOS >= 17 auto start-tunnel, function like pymobiledevice3 remote tunneld"""
160-
if not is_admin_user():
160+
if not os_utils.is_admin:
161161
logger.error("Please run as root(Mac) or administrator(Windows)")
162162
sys.exit(1)
163163

0 commit comments

Comments
 (0)