Repository navigation
fix(ios): open Device Hub when Simulator.app is unavailable - #405
aihdene-genetec wants to merge 1 commit into
Conversation
Xcode 27 removes Simulator.app and replaces it with Device Hub, which
lives at Xcode.app/Contents/Applications rather than under the developer
directory returned by `xcode-select -p`. `runOnSimulator` hardcodes
`${xCodePath}/Applications/Simulator.app`, so `native-run ios` fails on
Xcode 27 with:
ERR_UNKNOWN: There was an error opening simulator: The file
/Applications/Xcode.app/Contents/Developer/Applications/Simulator.app
does not exist.
Resolve the app at run time instead: keep using Simulator.app when it is
present, so behavior is unchanged on Xcode 26 and earlier, and otherwise
open Device Hub by its bundle id (com.apple.dt.Devices). The
-CurrentDeviceUDID argument is accepted by both.
|
Thanks for this! One suggestion on how Device Hub is located. The doc comment says it "lives outside the developer directory and so can only be located by bundle id", but it sits at a fixed position relative to that directory: Resolving it from The bundle id still makes a good last resort, so something like: async function getSimulatorOpenArgs(): Promise<string[]> {
const xCodePath = await getXCodePath();
const simulatorAppPath = `${xCodePath}/Applications/Simulator.app`;
if (await pathExists(simulatorAppPath)) {
return [simulatorAppPath];
}
// Xcode 27+: Device Hub sits beside Developer/, not inside it.
const deviceHubPath = `${xCodePath}/../Applications/DeviceHub.app`;
if (await pathExists(deviceHubPath)) {
debug(`Simulator.app not found, opening Device Hub at ${deviceHubPath}`);
return [deviceHubPath];
}
debug(`Device Hub not found at ${deviceHubPath}, falling back to bundle id`);
return ['-b', DEVICE_HUB_BUNDLE_ID];
}Tested on macOS 27.0 / Xcode 27.1 beta (27A9269): |
|
@pjaudiomv I tested the approach you suggested, resolving DeviceHub.app relative to getXCodePath() and passing -CurrentDeviceUDID. With Xcode 27, Device Hub opens successfully, but it does not select the simulator specified by the UDID. It opens the last simulator used instead, and in the expanded Device Hub view. I also tested devices://device/open?id=, which does select the requested simulator and opens it in the compact simulator view, making it much closer to the previous Simulator.app behavior. I ended up using this approach in #408. |
Nice catch, can confirm — opening DeviceHub.app with
|
|
Cool, if there's another PR open that does this better then I shall close mine. Thank you. |
Xcode 27 removes
Simulator.appand replaces it with Device Hub. The new app lives atXcode.app/Contents/Applications/DeviceHub.app, which is outside the developer directory returned byxcode-select -p, and the oldContents/Developer/Applications/directory is gone entirely.runOnSimulator()hardcodes${xCodePath}/Applications/Simulator.app, sonative-run ios(and thereforenpx cap run ios) fails on Xcode 27:This is distinct from #401, which was the same error message caused by
xcode-selectpointing atCommandLineTools. Herexcode-select -pis correctly set to/Applications/Xcode.app/Contents/Developer— the target simply no longer exists under any Xcode path, so fixing the Locations setting can't help.Changes
Resolve the app at run time rather than assuming a fixed path:
Simulator.appexists at the current location, keep using it, so behavior is unchanged on Xcode 26 and earlier.com.apple.dt.Devices).--args -CurrentDeviceUDID <udid>is accepted by both apps, so device targeting is preserved either way. Adebugline records which path was taken.Testing
Tested against a Capacitor project on Xcode 27.0 (27A266a) / macOS 26.6.2, booting an iPad (A16) simulator on the iOS 27.0 runtime:
boot → install → open → launchpipeline completes (exit 0), Device Hub opens, and the app installs and launches on the target simulator.npm run build,npm test(40/40), andnpm run lintall pass, with no new eslint or Prettier findings.I don't have an Xcode 26 install available to exercise the
Simulator.appbranch directly, but that path is byte-for-byte the previous behavior and is gated purely on the file existing.