### Application Management with InstallationProxyService Source: https://context7.com/artehe/netimobiledevice/llms.txt Installs, upgrades, uninstalls, and enumerates applications on the device. Requires a local .ipa file for installation or upgrade operations. ```csharp using Netimobiledevice; using Netimobiledevice.InstallationProxy; using Netimobiledevice.Plist; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using InstallationProxyService proxy = new InstallationProxyService(lockdown); CancellationToken ct = CancellationToken.None; // List all user apps DictionaryNode apps = await proxy.GetApps("User", calculateSizes: true, cancellationToken: ct); foreach (var (bundleId, info) in apps) { DictionaryNode appInfo = info.AsDictionaryNode(); Console.WriteLine($"{bundleId}: {appInfo["CFBundleDisplayName"].AsStringNode().Value}"); } // List specific apps DictionaryNode whatsapp = await proxy.GetApps( bundleIdentifiers: ["net.whatsapp.WhatsApp"], cancellationToken: ct); // Install from a local .ipa file IProgress installProgress = new Progress(p => Console.Write($"\rInstalling: {p}%")); await proxy.Install("/path/to/MyApp.ipa", ct, progress: installProgress); // Upgrade an already-installed app await proxy.Upgrade("/path/to/MyApp_v2.ipa", ct); // Uninstall by bundle ID await proxy.Uninstall("com.mycompany.myapp", ct); // Browse apps with specific return attributes ArrayNode browsed = await proxy.Browse( new DictionaryNode { { "ApplicationType", new StringNode("User") } }, attributes: [new StringNode("CFBundleIdentifier"), new StringNode("CFBundleDisplayName")], cancellationToken: ct); ``` -------------------------------- ### InstallationProxyService Source: https://context7.com/artehe/netimobiledevice/llms.txt Installs, upgrades, uninstalls, and enumerates applications on the device. ```APIDOC ## InstallationProxyService ### Description Installs, upgrades, uninstalls, and enumerates applications on the device. ### Methods - `GetApps(string type, bool calculateSizes = false, CancellationToken cancellationToken = default)`: Retrieves a list of applications of a specified type (e.g., "User"). - `GetApps(IEnumerable bundleIdentifiers, CancellationToken cancellationToken = default)`: Retrieves information for specific applications by their bundle identifiers. - `Install(string ipaPath, CancellationToken cancellationToken = default, IProgress? progress = null)`: Installs an application from a local .ipa file. - `Upgrade(string ipaPath, CancellationToken cancellationToken = default)`: Upgrades an already installed application. - `Uninstall(string bundleId, CancellationToken cancellationToken = default)`: Uninstalls an application by its bundle ID. - `Browse(DictionaryNode options, IEnumerable attributes, CancellationToken cancellationToken = default)`: Browses applications with specified return attributes. ### Example Usage ```csharp using Netimobiledevice; using Netimobiledevice.InstallationProxy; using Netimobiledevice.Plist; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using InstallationProxyService proxy = new InstallationProxyService(lockdown); CancellationToken ct = CancellationToken.None; // List all user apps DictionaryNode apps = await proxy.GetApps("User", calculateSizes: true, cancellationToken: ct); foreach (var (bundleId, info) in apps) { DictionaryNode appInfo = info.AsDictionaryNode(); Console.WriteLine($"{bundleId}: {appInfo["CFBundleDisplayName"].AsStringNode().Value}"); } // List specific apps DictionaryNode whatsapp = await proxy.GetApps( bundleIdentifiers: ["net.whatsapp.WhatsApp"], cancellationToken: ct); // Install from a local .ipa file IProgress installProgress = new Progress(p => Console.Write($"\rInstalling: {p}%")); await proxy.Install("/path/to/MyApp.ipa", ct, progress: installProgress); // Upgrade an already-installed app await proxy.Upgrade("/path/to/MyApp_v2.ipa", ct); // Uninstall by bundle ID await proxy.Uninstall("com.mycompany.myapp", ct); // Browse apps with specific return attributes ArrayNode browsed = await proxy.Browse( new DictionaryNode { { "ApplicationType", new StringNode("User") } }, attributes: [new StringNode("CFBundleIdentifier"), new StringNode("CFBundleDisplayName")], cancellationToken: ct); ``` ``` -------------------------------- ### Get App Icon and Wallpaper with SpringBoardServices Source: https://context7.com/artehe/netimobiledevice/llms.txt Use SpringBoardServices to retrieve an app's icon and the device's wallpaper as PNG data. Ensure the necessary using directives are included. ```csharp using Netimobiledevice; using Netimobiledevice.SpringBoardServices; using Netimobiledevice.Plist; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using SpringBoardServicesService sb = new SpringBoardServicesService(lockdown); CancellationToken ct = CancellationToken.None; // Get an app icon as PNG bytes DataNode iconPng = await sb.GetIconPngDataAsync("net.whatsapp.WhatsApp", ct); await File.WriteAllBytesAsync("whatsapp_icon.png", iconPng.Value); // Get the wallpaper as PNG bytes DataNode wallpaper = await sb.GetWallpaperPngDataAsync(ct); await File.WriteAllBytesAsync("wallpaper.png", wallpaper.Value); // Query screen orientation ScreenOrientation orientation = await sb.GetScreenOrientationAsync(ct); Console.WriteLine($"Orientation: {orientation}"); // ScreenOrientation: Unknown, Portrait, PortraitUpsideDown, LandscapeLeft, LandscapeRight ``` -------------------------------- ### Provisioning Profile Management Source: https://context7.com/artehe/netimobiledevice/llms.txt This section covers the `MisagentService` for installing, removing, and listing provisioning profiles on an iOS device. ```APIDOC ## Provisioning Profile Management — `MisagentService` Installs, removes, and lists provisioning profiles on the device. ### Method ```csharp List profiles = await misagent.GetInstalledProvisioningProfiles(); await misagent.Install(profilePlist); await misagent.Uninstall("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); ``` ### Description - `GetInstalledProvisioningProfiles()`: Retrieves a list of all installed provisioning profiles on the device. - `Install(PropertyNode profilePlist)`: Installs a provisioning profile. The profile should be provided as a parsed `PropertyNode`. - `Uninstall(string profileUuid)`: Removes a provisioning profile from the device using its UUID. ``` -------------------------------- ### Manage Notifications with NotificationProxyService Source: https://context7.com/artehe/netimobiledevice/llms.txt Subscribe to device notifications and post notifications to the device using NotificationProxyService. Includes methods to observe specific or all notifications, handle received notifications, start/stop the listener, and post custom notifications. Remember to start the listener before expecting notifications. ```csharp using Netimobiledevice; using Netimobiledevice.NotificationProxy; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using NotificationProxyService np = new NotificationProxyService(lockdown); // Subscribe to a specific notification await np.ObserveNotificationAsync(ReceivableNotification.SyncCancelRequest); await np.ObserveNotificationAsync(ReceivableNotification.RequestPair); // Subscribe to all built-in notifications await np.ObserveAllAsync(); np.ReceivedNotification += (_, e) => { Console.WriteLine($"[{e.DeviceUdid}] Notification: {e.Event}"); }; // Start background listener np.Start(); // Post a notification to the device await np.PostAsync(SendableNotificaton.SyncWillStart); // Stop listening np.Stop(); ``` -------------------------------- ### Manage Provisioning Profiles with MisagentService Source: https://context7.com/artehe/netimobiledevice/llms.txt Use MisagentService to list, install, and uninstall provisioning profiles on an iOS device. Ensure the profile is correctly parsed into a PropertyNode before installation. ```csharp using Netimobiledevice; using Netimobiledevice.Misagent; using Netimobiledevice.Plist; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using MisagentService misagent = new MisagentService(lockdown); // List all installed provisioning profiles List profiles = await misagent.GetInstalledProvisioningProfiles(); foreach (PropertyNode profile in profiles) { DictionaryNode dict = profile.AsDictionaryNode(); Console.WriteLine(dict["Name"].AsStringNode().Value); } // Install a profile (pass a parsed plist PropertyNode of the .mobileprovision) byte[] profileBytes = await File.ReadAllBytesAsync("MyProfile.mobileprovision"); PropertyNode profilePlist = await PropertyList.LoadFromByteArrayAsync(profileBytes); await misagent.Install(profilePlist); // Uninstall by UUID await misagent.Uninstall("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); ``` -------------------------------- ### Get Connected iOS Devices Source: https://github.com/artehe/netimobiledevice/blob/main/README.md Retrieves a list of all currently connected iOS devices using Usbmux. ```csharp using Netimobiledevice.Usbmuxd; List devices = Usbmux.GetDeviceList(); Console.WriteLine($"There's {devices.Count} devices connected"); foreach (UsbmuxdDevice device in devices) { Console.WriteLine($"Device found: {device.DeviceId} - {device.Serial}"); } ``` -------------------------------- ### Get iOS App Icon PNG Source: https://github.com/artehe/netimobiledevice/blob/main/README.md Fetches the PNG data for an application's icon from an iOS device using its device ID. ```csharp using (UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux("60653a518d33eb53b3ca2322de3f44e162a42069")) { SpringBoardServicesService springBoard = new SpringBoardServicesService(lockdown); PropertyNode png = springBoard.GetIconPNGData("net.whatsapp.WhatsApp"); } ``` -------------------------------- ### Discover Connected iOS Devices Source: https://context7.com/artehe/netimobiledevice/llms.txt Retrieve a list of connected iOS devices. You can get a synchronous or asynchronous list, look up a specific device by UDID, or check if a device is currently connected. ```csharp using Netimobiledevice.Usbmuxd; // Synchronous list List devices = Usbmux.GetDeviceList(); Console.WriteLine($"{devices.Count} device(s) connected:"); foreach (UsbmuxdDevice device in devices) { Console.WriteLine($" ID={device.DeviceId} UDID={device.Serial} via={device.ConnectionType}"); } // Async list List devicesAsync = await Usbmux.GetDeviceListAsync(); // Look up a single device by UDID, prefer USB UsbmuxdDevice? target = Usbmux.GetDevice("60653a518d33eb53b3ca2322de3f44e162a42069", connectionType: UsbmuxdConnectionType.Usb); // Check connectivity bool connected = Usbmux.IsDeviceConnected("60653a518d33eb53b3ca2322de3f44e162a42069"); ``` -------------------------------- ### Plist Handling Source: https://context7.com/artehe/netimobiledevice/llms.txt This section details the `PropertyList` class for parsing and building property list (plist) files in both XML and binary formats. ```APIDOC ## Plist Handling — `PropertyList` Netimobiledevice includes a full plist parser that handles both XML and binary formats, used throughout the library and available for direct use. ### Method ```csharp PropertyNode root = await PropertyList.LoadFromByteArrayAsync(xmlBytes); byte[] xmlOut = PropertyList.SaveAsByteArray(dict, PlistFormat.Xml); byte[] binOut = PropertyList.SaveAsByteArray(dict, PlistFormat.Binary); ``` ### Description - `LoadFromByteArrayAsync(byte[] data)`: Parses a property list from a byte array, automatically detecting XML or binary format. - `SaveAsByteArray(PropertyNode node, PlistFormat format)`: Serializes a `PropertyNode` into a byte array in the specified format (XML or Binary). - Building Plists: Allows for the creation of new property list structures programmatically using `DictionaryNode`, `StringNode`, `BooleanNode`, `IntegerNode`, `DataNode`, and `ArrayNode`. ``` -------------------------------- ### Create a Lockdown Client Source: https://context7.com/artehe/netimobiledevice/llms.txt Initialize a lockdown client to manage the device's lockdownd session, including SSL upgrades and pairing records. Supports synchronous, asynchronous, TCP, and logger-configured connections. ```csharp using Netimobiledevice; using Netimobiledevice.Lockdown; using Microsoft.Extensions.Logging; // Synchronous using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux("60653a518d33eb53b3ca2322de3f44e162a42069"); Console.WriteLine($"Device : {lockdown.DeviceName}"); Console.WriteLine($"Model : {lockdown.ProductFriendlyName}"); Console.WriteLine($"iOS : {lockdown.OsVersion}"); Console.WriteLine($"Paired : {lockdown.IsPaired}"); // Async variant using UsbmuxLockdownClient lockdownAsync = await MobileDevice.CreateUsingUsbmuxAsync("60653a518d33eb53b3ca2322de3f44e162a42069"); // TCP (Wi-Fi / RemoteXPC) using TcpLockdownClient tcpLockdown = MobileDevice.CreateUsingTcp("fe80::1%en0"); // With ILogger using ILoggerFactory logFactory = LoggerFactory.Create(b => b.SetMinimumLevel(LogLevel.Debug).AddConsole()); using UsbmuxLockdownClient loggedLockdown = MobileDevice.CreateUsingUsbmux(logger: logFactory.CreateLogger("Netimobiledevice")); ``` -------------------------------- ### Creating a Lockdown Client — MobileDevice.CreateUsingUsbmux Source: https://context7.com/artehe/netimobiledevice/llms.txt `MobileDevice` is the entry-point factory. It creates a `UsbmuxLockdownClient` (or `PlistUsbmuxLockdownClient`) that manages the lockdownd session, SSL upgrade, and pairing records. Pass an empty serial to connect to the first available device. ```APIDOC ## Creating a Lockdown Client — MobileDevice.CreateUsingUsbmux ### Description `MobileDevice` is the entry-point factory. It creates a `UsbmuxLockdownClient` (or `PlistUsbmuxLockdownClient`) that manages the lockdownd session, SSL upgrade, and pairing records. Pass an empty serial to connect to the first available device. ### Method `MobileDevice.CreateUsingUsbmux(string? serial = null, ILogger? logger = null)` (Synchronous) `MobileDevice.CreateUsingUsbmuxAsync(string? serial = null, ILogger? logger = null)` (Asynchronous) `MobileDevice.CreateUsingTcp(string host, int port = 27010, ILogger? logger = null)` (TCP/RemoteXPC) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp using Netimobiledevice; using Netimobiledevice.Lockdown; using Microsoft.Extensions.Logging; // Synchronous using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux("60653a518d33eb53b3ca2322de3f44e162a42069"); Console.WriteLine($"Device : {lockdown.DeviceName}"); Console.WriteLine($"Model : {lockdown.ProductFriendlyName}"); Console.WriteLine($"iOS : {lockdown.OsVersion}"); Console.WriteLine($"Paired : {lockdown.IsPaired}"); // Async variant using UsbmuxLockdownClient lockdownAsync = await MobileDevice.CreateUsingUsbmuxAsync("60653a518d33eb53b3ca2322de3f44e162a42069"); // TCP (Wi-Fi / RemoteXPC) using TcpLockdownClient tcpLockdown = MobileDevice.CreateUsingTcp("fe80::1%en0"); // With ILogger using ILoggerFactory logFactory = LoggerFactory.Create(b => b.SetMinimumLevel(LogLevel.Debug).AddConsole()); using UsbmuxLockdownClient loggedLockdown = MobileDevice.CreateUsingUsbmux(logger: logFactory.CreateLogger("Netimobiledevice")); ``` ### Response #### Success Response (200) - **lockdown** (`UsbmuxLockdownClient` or `TcpLockdownClient`) - An instance of a lockdown client. - **DeviceName** (string) - The name of the connected device. - **ProductFriendlyName** (string) - The friendly name of the device model. - **OsVersion** (string) - The operating system version of the device. - **IsPaired** (bool) - Indicates if the device is paired. #### Response Example ```json { "example": "{\n \"DeviceName\": \"My iPhone\",\n \"ProductFriendlyName\": \"iPhone 14 Pro\",\n \"OsVersion\": \"16.5.1\",\n \"IsPaired\": true\n}" } ``` ``` -------------------------------- ### Create iTunes Backup Source: https://github.com/artehe/netimobiledevice/blob/main/README.md Initiates an iTunes-style backup of an iOS device, with options for customization and event handling. ```csharp using (UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux("60653a518d33eb53b3ca2322de3f44e162a42069")) { using (Mobilebackup2Service mb2 = new Mobilebackup2Service(lockdown)) { mb2.BeforeReceivingFile += BackupJob_BeforeReceivingFile; mb2.Completed += BackupJob_Completed; mb2.Error += BackupJob_Error; mb2.FileReceived += BackupJob_FileReceived; mb2.FileReceiving += BackupJob_FileReceiving; mb2.FileTransferError += BackupJob_FileTransferError; mb2.PasscodeRequiredForBackup += BackupJob_PasscodeRequiredForBackup; mb2.Progress += BackupJob_Progress; mb2.Status += BackupJob_Status; mb2.Started += BackupJob_Started; await mb2.Backup(true, true, "backups", tokenSource.Token); } } ``` -------------------------------- ### Querying and Setting Device Values with LockdownClient Source: https://context7.com/artehe/netimobiledevice/llms.txt Reads and writes arbitrary lockdownd properties. Pass null for domain and key to retrieve all values, or specify a domain and/or key for targeted operations. Ensure the device is paired and accessible. ```csharp using Netimobiledevice; using Netimobiledevice.Lockdown; using Netimobiledevice.Plist; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); // Specific key from default domain string udid = lockdown.GetValue(null, "UniqueDeviceID")?.AsStringNode().Value ?? ""; Console.WriteLine($"UDID: {udid}"); // Domain-scoped key bool wifiEnabled = lockdown .GetValue("com.apple.mobile.wireless_lockdown", "EnableWifiConnections") ?.AsBooleanNode().Value ?? false; // Enable Wi-Fi connections for lockdown lockdown.SetValue("com.apple.mobile.wireless_lockdown", "EnableWifiConnections", new BooleanNode(true)); // Async variant PropertyNode? buildVersion = await lockdown.GetValueAsync(null, "BuildVersion"); Console.WriteLine($"Build: {buildVersion?.AsStringNode().Value}"); ``` -------------------------------- ### Pairing a Device with LockdownClient Source: https://context7.com/artehe/netimobiledevice/llms.txt Initiates a trust-handshake with the device to establish a secure connection. Reports state transitions via an IProgress interface. Ensure the device is connected and accessible. ```csharp using Netimobiledevice; using Netimobiledevice.Lockdown; using Netimobiledevice.Lockdown.Pairing; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(autopair: false); Progress progress = new Progress(state => { Console.WriteLine($"Pairing state: {state}"); // States: PairingDialogResponsePending, PasswordProtected, UserDeniedPairing, Paired }); using CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); bool paired = await lockdown.PairAsync(progress, cts.Token); Console.WriteLine(paired ? "Successfully paired!" : "Pairing failed or was denied."); // Unpair await lockdown.UnpairAsync(); ``` -------------------------------- ### Query Device Information with DiagnosticsService Source: https://context7.com/artehe/netimobiledevice/llms.txt Utilize DiagnosticsService to query MobileGestalt keys for hardware capabilities, battery, and storage information. It also allows reading IORegistry entries and issuing power commands. Ensure proper using directives are present. ```csharp using Netimobiledevice; using Netimobiledevice.Diagnostics; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using DiagnosticsService diag = new DiagnosticsService(lockdown); CancellationToken ct = CancellationToken.None; // Battery info from MobileGestalt Netimobiledevice.Plist.DictionaryNode battery = await diag.GetBatteryDetails(ct); Console.WriteLine($"Battery: {battery["BatteryCurrentCapacity"].AsIntegerNode().Value}%"); Console.WriteLine($"Charging: {battery["BatteryIsCharging"].AsBooleanNode().Value}"); // Storage from MobileGestalt Dictionary storage = await diag.GetStorageDetailsAsync(ct); foreach (var (key, bytes) in storage) { Console.WriteLine($"{key}: {bytes / (1024 * 1024)} MB"); } // Query specific MobileGestalt keys Netimobiledevice.Plist.DictionaryNode caps = await diag.MobileGestaltAsync( ["CPUArchitecture", "ModelNumber", "UniqueChipID"], ct); // IORegistry query Netimobiledevice.Plist.DictionaryNode ioEntry = await diag.IORegistryAsync(name: "IOPMPowerSource", cancellationToken: ct); // Power commands diag.Restart(); diag.Sleep(); diag.Shutdown(); // Async power commands await diag.Restart(ct); await diag.SleepAsync(ct); await diag.ShutdownAsync(ct); ``` -------------------------------- ### SpringBoardServicesService Source: https://context7.com/artehe/netimobiledevice/llms.txt Provides methods to retrieve app icons, the home-screen wallpaper, and the current device screen orientation. ```APIDOC ## SpringBoard Services — `SpringBoardServicesService` Retrieves app icons, the home-screen wallpaper, and the current device screen orientation. ### Methods - **GetIconPngDataAsync** - Description: Retrieves an app icon as PNG bytes. - Parameters: - `bundleIdentifier` (string) - Required - The bundle identifier of the app. - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `Task` - A DataNode containing the PNG data of the icon. - **GetWallpaperPngDataAsync** - Description: Retrieves the device's wallpaper as PNG bytes. - Parameters: - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `Task` - A DataNode containing the PNG data of the wallpaper. - **GetScreenOrientationAsync** - Description: Queries the current screen orientation of the device. - Parameters: - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `Task` - An enum value representing the screen orientation (Unknown, Portrait, PortraitUpsideDown, LandscapeLeft, LandscapeRight). ``` -------------------------------- ### Restoring Device from Backup with Mobilebackup2Service Source: https://context7.com/artehe/netimobiledevice/llms.txt Restores a previously-created backup directory to the connected device. Allows fine-grained control over restored components and backup encryption management. Ensure the backup directory exists and is valid. ```csharp using Netimobiledevice; using Netimobiledevice.Backup; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using Mobilebackup2Service mb2 = new Mobilebackup2Service(lockdown); mb2.Progress += (_, e) => Console.Write($"\rRestore: {e.ProgressPercentage}%"); mb2.Completed += (_, e) => Console.WriteLine($"\nDone: {e.ResultCode}"); ResultCode result = await mb2.Restore( backupDirectory: "./MyBackups", system: false, // skip system files reboot: true, // reboot when done copy: true, // keep a copy of the backup settings: true, // restore settings remove: false, // don't remove unlisted items password: "", // password if backup is encrypted cancellationToken: CancellationToken.None); // Backup encryption management await mb2.SetBackupPassword("MySecretPassword"); // enable encryption await mb2.ChangeBackupPassword("MySecretPassword", "NewPass"); // change password await mb2.RemoveBackupPassword("NewPass"); // disable encryption ``` -------------------------------- ### Device Pairing - LockdownClient.PairAsync Source: https://context7.com/artehe/netimobiledevice/llms.txt Initiates the trust-handshake with the device, generating host certificates and saving the pair record. Reports each state transition via IProgress. ```APIDOC ## Device Pairing — `LockdownClient.PairAsync` Initiates the trust-handshake with the device, generating host certificates and saving the pair record. Reports each state transition via `IProgress`. ```csharp using Netimobiledevice; using Netimobiledevice.Lockdown; using Netimobiledevice.Lockdown.Pairing; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(autopair: false); Progress progress = new Progress(state => { Console.WriteLine($"Pairing state: {state}"); // States: PairingDialogResponsePending, PasswordProtected, UserDeniedPairing, Paired }); using CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); bool paired = await lockdown.PairAsync(progress, cts.Token); Console.WriteLine(paired ? "Successfully paired!" : "Pairing failed or was denied."); // Unpair await lockdown.UnpairAsync(); ``` ``` -------------------------------- ### iOS Device Interaction with Logging Source: https://github.com/artehe/netimobiledevice/blob/main/README.md Demonstrates how to use Netimobiledevice with a custom logger (Microsoft.Extensions.Logging.ILogger) for detailed logging during operations like backup. ```csharp using Microsoft.Extensions.Logging; using ILoggerFactory factory = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.Debug).AddConsole()); using (LockdownClient lockdown = MobileDevice.CreateUsingUsbmux(testDevice?.Serial ?? string.Empty, logger: factory.CreateLogger("Netimobiledevice"))) { using (Mobilebackup2Service mb2 = new Mobilebackup2Service(lockdown)) { await mb2.Backup(true, true, "backups", tokenSource.Token); } } ``` -------------------------------- ### SyslogService Source: https://context7.com/artehe/netimobiledevice/llms.txt Streams raw syslog lines from the device in real time, supporting both synchronous and asynchronous iteration. ```APIDOC ## Syslog Streaming — `SyslogService` Streams raw syslog lines from the device in real time. Works both synchronously (blocking `IEnumerable`) and asynchronously (`IAsyncEnumerable`). ### Methods - **WatchAsync** - Description: Asynchronously streams syslog lines from the device. - Parameters: - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `IAsyncEnumerable` - An asynchronous enumerable of syslog lines. - **Watch** - Description: Synchronously streams syslog lines from the device. - Returns: `IEnumerable` - An enumerable of syslog lines. ``` -------------------------------- ### Performing Device Backup with Mobilebackup2Service Source: https://context7.com/artehe/netimobiledevice/llms.txt Performs an iTunes-compatible full or incremental device backup. Exposes events for progress, file transfer, errors, and passcode prompts. Requires a paired device and a valid backup directory path. ```csharp using Netimobiledevice; using Netimobiledevice.Backup; using System.ComponentModel; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux("60653a518d33eb53b3ca2322de3f44e162a42069"); using Mobilebackup2Service mb2 = new Mobilebackup2Service(lockdown); mb2.Started += (_, e) => Console.WriteLine($"Backup started for {e.Udid}"); mb2.Progress += (_, e) => Console.Write($"\rProgress: {e.ProgressPercentage}% "); mb2.FileReceived += (_, e) => Console.WriteLine($"\nReceived: {e.BackupFile.LocalPath}"); mb2.FileTransferError += (_, e) => Console.Error.WriteLine($"Transfer error: {e.BackupFile.LocalPath}"); mb2.PasscodeRequiredForBackup += (_, _) => Console.WriteLine("Please enter your device passcode to continue..."); mb2.Completed += (_, e) => Console.WriteLine($"\nBackup completed. Result: {e.ResultCode}"); mb2.Error += (_, e) => Console.Error.WriteLine($"Backup error: {e.GetException()?.Message}"); using CancellationTokenSource cts = new CancellationTokenSource(); ResultCode result = await mb2.Backup( fullBackup: true, ignoreTransferErrors: true, performBackupSizeCheck: true, backupDirectory: "./MyBackups", cancellationToken: cts.Token); Console.WriteLine($"Final result code: {result}"); ``` -------------------------------- ### File System Access with AfcService Source: https://context7.com/artehe/netimobiledevice/llms.txt Provides full file-system access to the device's publicly accessible directories. Supports listing, reading, writing, downloading, and recursively deleting files. ```csharp using Netimobiledevice; using Netimobiledevice.Afc; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using AfcService afc = new AfcService(lockdown); CancellationToken ct = CancellationToken.None; // List root directory List rootEntries = await afc.GetDirectoryList(ct); Console.WriteLine("Root: " + string.Join(", ", rootEntries)); // List a subdirectory List mediaFiles = await afc.GetDirectoryList("/DCIM", ct); // Read a file's raw bytes byte[]? contents = await afc.GetFileContents("/iTunes_Control/iTunes/iTunesPrefs.plist", ct); // Write a file await afc.SetFileContents("/Documents/hello.txt", System.Text.Encoding.UTF8.GetBytes("Hello from Netimobiledevice!"), ct); // Download a file to a local path with progress IProgress downloadProgress = new Progress(bytes => Console.Write($"\rDownloaded {bytes} bytes")); await afc.DownloadFileContentsAsync("/DCIM/100APPLE/IMG_0001.JPG", "./IMG_0001.JPG", downloadProgress, ct); // Get metadata about a file Netimobiledevice.Plist.DictionaryNode? info = await afc.GetFileInfo("/iTunesPrefs.plist", ct); // Check existence bool exists = await afc.Exists("/Books/iBooksData2.plist", ct); // Recursive remove List undeleted = await afc.Rm("/Documents/old_folder", ct, force: true); // Walk directory tree (async streaming) await foreach (string entry in afc.LsDirectory("/", ct, depth: 1)) { Console.WriteLine(entry); } ``` -------------------------------- ### Handle Plists with Netimobiledevice.Plist Source: https://context7.com/artehe/netimobiledevice/llms.txt Utilize the PropertyList class to parse, manipulate, and save property list files in both XML and binary formats. This class is essential for handling configuration and data files compatible with Apple's ecosystem. ```csharp using Netimobiledevice.Plist; // Parse from bytes (XML or binary auto-detected) byte[] xmlBytes = File.ReadAllBytes("Info.plist"); PropertyNode root = await PropertyList.LoadFromByteArrayAsync(xmlBytes); DictionaryNode dict = root.AsDictionaryNode(); string productType = dict["ProductType"].AsStringNode().Value; bool boolVal = dict["SomeFlag"].AsBooleanNode().Value; ulong intVal = dict["SomeInt"].AsIntegerNode().Value; // Save as XML byte[] xmlOut = PropertyList.SaveAsByteArray(dict, PlistFormat.Xml); await File.WriteAllBytesAsync("output.plist", xmlOut); // Save as Binary byte[] binOut = PropertyList.SaveAsByteArray(dict, PlistFormat.Binary); // Build a plist from scratch DictionaryNode newPlist = new DictionaryNode { { "Name", new StringNode("My Device") }, { "Enabled", new BooleanNode(true) }, { "Version", new IntegerNode(42) }, { "Data", new DataNode(new byte[] { 0xDE, 0xAD, 0xBE, 0xEF }) }, { "Tags", new ArrayNode { new StringNode("ios"), new StringNode("device") } } }; ``` -------------------------------- ### Listen for iOS Device Connection Events Source: https://github.com/artehe/netimobiledevice/blob/main/README.md Subscribes to connection events from Usbmux to be notified when devices connect or disconnect. ```csharp Usbmux.Subscribe(SubscriptionCallback); private static void SubscriptionCallback(UsbmuxdDevice device, UsbmuxdConnectionEventType connectionEvent) { Console.WriteLine("NewCallbackExecuted"); Console.WriteLine($"Connection event: {connectionEvent}"); Console.WriteLine($"Device: {device.DeviceId} - {device.Serial}"); } ``` -------------------------------- ### AfcService Source: https://context7.com/artehe/netimobiledevice/llms.txt Provides full file-system access to the device's publicly accessible directories. Supports listing, reading, writing, downloading, and recursively deleting files. ```APIDOC ## AfcService ### Description Provides full file-system access to the device's publicly accessible directories (`/`). Supports listing, reading, writing, downloading, and recursively deleting files. ### Methods - `GetDirectoryList(CancellationToken ct)`: Lists the contents of a directory. - `GetFileContents(string path, CancellationToken ct)`: Reads the raw bytes of a file. - `SetFileContents(string path, byte[] contents, CancellationToken ct)`: Writes content to a file. - `DownloadFileContentsAsync(string sourcePath, string destinationPath, IProgress progress, CancellationToken ct)`: Downloads a file to a local path with progress reporting. - `GetFileInfo(string path, CancellationToken ct)`: Retrieves metadata about a file. - `Exists(string path, CancellationToken ct)`: Checks if a file or directory exists. - `Rm(string path, CancellationToken ct, bool force = false)`: Recursively removes a file or directory. - `LsDirectory(string path, CancellationToken ct, int depth = 0)`: Asynchronously streams entries in a directory tree. ### Example Usage ```csharp using Netimobiledevice; using Netimobiledevice.Afc; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using AfcService afc = new AfcService(lockdown); CancellationToken ct = CancellationToken.None; // List root directory List rootEntries = await afc.GetDirectoryList(ct); Console.WriteLine("Root: " + string.Join(", ", rootEntries)); // List a subdirectory List mediaFiles = await afc.GetDirectoryList("/DCIM", ct); // Read a file's raw bytes byte[]? contents = await afc.GetFileContents("/iTunes_Control/iTunes/iTunesPrefs.plist", ct); // Write a file await afc.SetFileContents("/Documents/hello.txt", System.Text.Encoding.UTF8.GetBytes("Hello from Netimobiledevice!"), ct); // Download a file to a local path with progress IProgress downloadProgress = new Progress(bytes => Console.Write($"\rDownloaded {bytes} bytes")); await afc.DownloadFileContentsAsync("/DCIM/100APPLE/IMG_0001.JPG", "./IMG_0001.JPG", downloadProgress, ct); // Get metadata about a file Netimobiledevice.Plist.DictionaryNode? info = await afc.GetFileInfo("/iTunesPrefs.plist", ct); // Check existence bool exists = await afc.Exists("/Books/iBooksData2.plist", ct); // Recursive remove List undeleted = await afc.Rm("/Documents/old_folder", ct, force: true); // Walk directory tree (async streaming) await foreach (string entry in afc.LsDirectory("/", ct, depth: 1)) { Console.WriteLine(entry); } ``` ``` -------------------------------- ### Stream Syslog Lines with SyslogService Source: https://context7.com/artehe/netimobiledevice/llms.txt Stream raw syslog lines from the device in real-time using SyslogService. Supports both asynchronous (IAsyncEnumerable) and synchronous (IEnumerable) streaming. A CancellationToken is recommended for asynchronous streaming to prevent indefinite waits. ```csharp using Netimobiledevice; using Netimobiledevice.Diagnostics; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using SyslogService syslog = new SyslogService(lockdown); // Async streaming (recommended) using CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); await foreach (string line in syslog.WatchAsync(cts.Token)) { Console.WriteLine(line); } // Synchronous (blocking) streaming foreach (string line in syslog.Watch()) { if (line.Contains("ERROR")) { Console.Error.WriteLine(line); } } ``` -------------------------------- ### Restore - Mobilebackup2Service.Restore Source: https://context7.com/artehe/netimobiledevice/llms.txt Restores a previously-created backup directory to the connected device, with fine-grained control over which components are restored. ```APIDOC ## Restore — `Mobilebackup2Service.Restore` Restores a previously-created backup directory to the connected device, with fine-grained control over which components are restored. ```csharp using Netimobiledevice; using Netimobiledevice.Backup; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); using Mobilebackup2Service mb2 = new Mobilebackup2Service(lockdown); mb2.Progress += (_, e) => Console.Write($"\rRestore: {e.ProgressPercentage}%"); mb2.Completed += (_, e) => Console.WriteLine($"\nDone: {e.ResultCode}"); ResultCode result = await mb2.Restore( backupDirectory: "./MyBackups", system: false, // skip system files reboot: true, // reboot when done copy: true, // keep a copy of the backup settings: true, // restore settings remove: false, // don't remove unlisted items password: "", // password if backup is encrypted cancellationToken: CancellationToken.None); // Backup encryption management await mb2.SetBackupPassword("MySecretPassword"); // enable encryption await mb2.ChangeBackupPassword("MySecretPassword", "NewPass"); // change password await mb2.RemoveBackupPassword("NewPass"); // disable encryption ``` ``` -------------------------------- ### Pair iOS Device Asynchronously Source: https://github.com/artehe/netimobiledevice/blob/main/README.md Asynchronously pairs an iOS device using its serial number and provides progress updates. ```csharp using (UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(testDevice?.Serial ?? string.Empty)) { Progress progress = new(); progress.ProgressChanged += Progress_ProgressChanged; await lockdown.PairAsync(progress); } private void Progress_ProgressChanged(object? sender, PairingState e) { Console.WriteLine($"Pair Progress Changed: {e}"); } ``` -------------------------------- ### Connection Event Subscription — Usbmux.Subscribe / Usbmux.Unsubscribe Source: https://context7.com/artehe/netimobiledevice/llms.txt Registers a callback that fires whenever a device is attached or detached. The background monitor runs until Unsubscribe is called. ```APIDOC ## Connection Event Subscription — Usbmux.Subscribe / Usbmux.Unsubscribe ### Description Registers a callback that fires whenever a device is attached or detached. The background monitor runs until `Unsubscribe` is called. ### Method `Usbmux.Subscribe(Action onDeviceEvent, Action onError) `Usbmux.Unsubscribe()` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp using Netimobiledevice.Usbmuxd; Usbmux.Subscribe(OnDeviceEvent, OnError); static void OnDeviceEvent(UsbmuxdDevice device, UsbmuxdConnectionEventType eventType) { if (eventType == UsbmuxdConnectionEventType.Connected) { Console.WriteLine($"[+] Device connected: {device.Serial}"); } else { Console.WriteLine($"[-] Device disconnected: {device.Serial}"); } } static void OnError(Exception ex) { Console.Error.WriteLine($"Usbmux monitor error: {ex.Message}"); } // Later, stop monitoring: Usbmux.Unsubscribe(); ``` ### Response #### Success Response (200) No direct response, but callbacks are invoked upon device connection/disconnection events. #### Response Example None ``` -------------------------------- ### DiagnosticsService Source: https://context7.com/artehe/netimobiledevice/llms.txt Provides access to device diagnostics, including MobileGestalt capabilities, IORegistry, battery and storage information, and power commands. ```APIDOC ## Diagnostics — `DiagnosticsService` Queries MobileGestalt hardware capability keys, reads IORegistry entries, retrieves battery/storage info, and issues power commands (restart, shutdown, sleep). ### Methods - **GetBatteryDetails** - Description: Retrieves detailed battery information from MobileGestalt. - Parameters: - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `Task` - A DictionaryNode containing battery details. - **GetStorageDetailsAsync** - Description: Retrieves storage information from MobileGestalt. - Parameters: - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `Task>` - A dictionary mapping storage keys to their sizes in bytes. - **MobileGestaltAsync** - Description: Queries specific MobileGestalt hardware capability keys. - Parameters: - `keys` (string[]) - Required - An array of keys to query. - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `Task` - A DictionaryNode containing the requested MobileGestalt values. - **IORegistryAsync** - Description: Reads an entry from the device's IORegistry. - Parameters: - `name` (string) - Required - The name of the IORegistry entry to read. - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `Task` - A DictionaryNode representing the IORegistry entry. - **Restart** - Description: Issues a command to restart the device. - Parameters: - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `Task` - **Sleep** - Description: Issues a command to put the device to sleep. - Parameters: - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `Task` - **Shutdown** - Description: Issues a command to shut down the device. - Parameters: - `cancellationToken` (CancellationToken) - Optional - Token to monitor for cancellation requests. - Returns: `Task` ``` -------------------------------- ### NotificationProxyService Source: https://context7.com/artehe/netimobiledevice/llms.txt Allows subscribing to device-generated notifications and posting notifications to the device. ```APIDOC ## Notification Proxy — `NotificationProxyService` Subscribes to device-generated notifications (e.g., sync events, backup signals) and posts notifications to the device. ### Methods - **ObserveNotificationAsync** - Description: Subscribes to a specific type of notification. - Parameters: - `notification` (ReceivableNotification) - Required - The notification to subscribe to. - Returns: `Task` - **ObserveAllAsync** - Description: Subscribes to all built-in device notifications. - Returns: `Task` - **Start** - Description: Starts the background listener for incoming notifications. - **Stop** - Description: Stops the background listener. - **PostAsync** - Description: Posts a notification to the device. - Parameters: - `notification` (SendableNotificaton) - Required - The notification to post. - Returns: `Task` ### Events - **ReceivedNotification** - Description: Event handler for when a notification is received from the device. - Arguments: - `sender` - The object that raised the event. - `e` - An object containing the device UDID and the received event. ``` -------------------------------- ### Querying Device Values - LockdownClient.GetValue / SetValue Source: https://context7.com/artehe/netimobiledevice/llms.txt Reads arbitrary lockdownd properties. Pass `null` for both domain and key to receive all values, or supply a specific domain and/or key. ```APIDOC ## Querying Device Values — `LockdownClient.GetValue` / `SetValue` Reads arbitrary lockdownd properties. Pass `null` for both domain and key to receive all values, or supply a specific domain and/or key. ```csharp using Netimobiledevice; using Netimobiledevice.Lockdown; using Netimobiledevice.Plist; using UsbmuxLockdownClient lockdown = MobileDevice.CreateUsingUsbmux(); // Specific key from default domain string udid = lockdown.GetValue(null, "UniqueDeviceID")?.AsStringNode().Value ?? ""; Console.WriteLine($"UDID: {udid}"); // Domain-scoped key bool wifiEnabled = lockdown .GetValue("com.apple.mobile.wireless_lockdown", "EnableWifiConnections") ?.AsBooleanNode().Value ?? false; // Enable Wi-Fi connections for lockdown lockdown.SetValue("com.apple.mobile.wireless_lockdown", "EnableWifiConnections", new BooleanNode(true)); // Async variant PropertyNode? buildVersion = await lockdown.GetValueAsync(null, "BuildVersion"); Console.WriteLine($"Build: {buildVersion?.AsStringNode().Value}"); ``` ``` -------------------------------- ### Subscribe to Device Connection Events Source: https://context7.com/artehe/netimobiledevice/llms.txt Register callbacks to be notified when an iOS device is attached or detached. The monitoring service runs in the background until explicitly unsubscribed. ```csharp using Netimobiledevice.Usbmuxd; Usbmux.Subscribe(OnDeviceEvent, OnError); static void OnDeviceEvent(UsbmuxdDevice device, UsbmuxdConnectionEventType eventType) { if (eventType == UsbmuxdConnectionEventType.Connected) { Console.WriteLine($"[+] Device connected: {device.Serial}"); } else { Console.WriteLine($"[-] Device disconnected: {device.Serial}"); } } static void OnError(Exception ex) { Console.Error.WriteLine($"Usbmux monitor error: {ex.Message}"); } // Later, stop monitoring: Usbmux.Unsubscribe(); ```