feat!: replace node-ios-device with devicectl (CoreDevice) - #261
Merged
Merged
Conversation
Device detection, install and launch now go through `xcrun devicectl` (Xcode 15+). The native node-ios-device module is removed: iOS 17+ devices connect exclusively through CoreDevice/RemoteXPC and are invisible to the old MobileDevice.framework API, even over USB. - device.detect() shells out to `devicectl list devices` and returns paired physical iOS devices (incl. Wi-Fi/local network devices); failures degrade to an empty device list with a warning issue instead of failing the whole ioslib.detect() call - device.install() installs via `devicectl device install app`; the logPort TCP relay is gone - new device.launch() launches with an attached console and emits log lines, waiting for a locked device to be unlocked first - new device.lockState() exposes the device lock state BREAKING CHANGE: requires Xcode 15+ command line tools. The device info shape changed (deviceColor, hardwareModel, modelNumber and serialNumber are gone; identifier, marketingName and connectionType are new) and device.install() no longer relays app logs via options.logPort - use device.launch() instead.
Verified against a physical iPhone over wifi: - buffer the app's stderr until stdout activity confirms the launch, so a failed launch's devicectl error block never leaks into the app log stream (devicectl routes the app's stderr - i.e. all NSLog output - to its own stderr, together with its error blocks) - filter devicectl's own progress lines from the log stream and emit the restored app-started event when the launch is confirmed - recognize SpringBoard's 'Locked' denial in the devicectl output and return to waiting instead of erroring; lockState can time out on locked devices over wifi - only a definitive 'unlocked' lockState answer triggers a launch attempt while waiting, an unknown state keeps polling - TestApp: stop redirecting stderr to a file (the console capture needs it), log to both stdout and stderr, and exit after 10s so the full launch/log/quit cycle is testable
cb1kenobi
requested changes
Aug 8, 2026
Uses --json-output - as suggested in the PR review; the dash makes devicectl stream the JSON directly, while /dev/stdout would break subcommands like 'device info' that save their output atomically.
cb1kenobi
approved these changes
Aug 9, 2026
cb1kenobi
left a comment
Member
There was a problem hiding this comment.
Tested and works! Nice job!
Contributor
Author
|
Appreciate it a lot, Chris! Thank you! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Warning
BREAKING CHANGE — released as 6.0.0. Requires Xcode 15+, changes the device info shape and removes the
install()log relay (uselaunch()instead). Details under Breaking changes below.Summary
Reimplements the
devicemodule on top ofxcrun devicectl(CoreDevice, Xcode 15+) and removes the nativenode-ios-devicemodule — along with its Node-ABI-specific prebuilt binaries. iOS 17+ devices connect exclusively through CoreDevice/RemoteXPC and are invisible to the old MobileDevice.framework API, even over USB.Ported APIs
devices()device.detect()— viadevicectl list devices; now also detects Wi-Fi / local-network devicesinstallApp()device.install()— viadevicectl device install app; also works over Wi-Filog(udid, port)device.launch()— launches the app with an attached console and relays log lines (app-started/log/app-quitevents); waits for a locked device to be unlocked firsttrackDevices()New:
device.lockState(udid, cb)exposes the device lock state.Breaking changes
deviceColor,hardwareModel,modelNumber,serialNumberremoved;identifier,marketingName,connectionTypeaddeddevice.install()no longer relays app logs viaoptions.logPort— usedevice.launch()insteaddevice.detect()failures now degrade to an empty device list plus a warning issue instead of failing the entireioslib.detect()callTesting
Verified against a physical iPhone (iOS 27) over Wi-Fi: detection, lock state, install (~6s), launch with full console capture (stdout + stderr/NSLog incl. multi-line messages), locked-device wait → unlock → launch, and clean
app-quitpropagation. The bundledtest/TestAppfixture was modernized for this flow (no stderr file redirect, self-quits after 10s).