fix(ios): open Device Hub when Simulator.app is unavailable
Xcode 27 removes Simulator.app and replaces it with Device Hub. The new app lives at Xcode.app/Contents/Applications/DeviceHub.app, which is outside the developer directory returned by xcode-select -p, and the old Contents/Developer/Applications/ directory is gone entirely.
runOnSimulator() hardcodes ${xCodePath}/Applications/Simulator.app, so native-run ios (and therefore npx cap run ios) fails on Xcode 27:
✖ Deploying App.app to 96D5F2F5-8067-4D50-84B7-BD2E2CA80DE5 - failed!
[error] ERR_UNKNOWN: There was an error opening simulator: The file
/Applications/Xcode.app/Contents/Developer/Applications/Simulator.app does not exist.
This is distinct from #401, which was the same error message caused by xcode-select pointing at CommandLineTools. Here xcode-select -p is 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:
- If
Simulator.appexists at the current location, keep using it, so behavior is unchanged on Xcode 26 and earlier. - Otherwise open Device Hub by bundle id (
com.apple.dt.Devices).
--args -CurrentDeviceUDID <udid> is accepted by both apps, so device targeting is preserved either way. A debug line 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:
- Before: fails with the error above (exit 1).
- After: full
boot → install → open → launchpipeline completes (exit 0), Device Hub opens, and the app installs and launches on the target simulator.
native-run:ios:utils:simulator Running simulator 96D5F2F5-...
native-run:ios:utils:simulator Simulator.app not found at /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app, falling back to Device Hub
native-run:ios:utils:simulator Launching .../App.app on 96D5F2F5-...
npm run build, npm test (40/40), and npm run lint all pass, with no new eslint or Prettier findings.
I don't have an Xcode 26 install available to exercise the Simulator.app branch directly, but that path is byte-for-byte the previous behavior and is gated purely on the file existing.