diff --git a/lib/xcode.js b/lib/xcode.js index 9b2cc38..ea180ee 100644 --- a/lib/xcode.js +++ b/lib/xcode.js @@ -576,64 +576,41 @@ exports.detect = function detect(options, callback) { } }); - var deviceTypesPaths = [ - path.join(xc.path, 'Platforms', 'iPhoneSimulator.platform', 'Developer', 'Library', 'CoreSimulator', 'Profiles'), - path.join(xc.path, 'Platforms', 'WatchSimulator.platform', 'Developer', 'Library', 'CoreSimulator', 'Profiles'), - - // Xcode 9 moved CoreSimulator into the "OS" directory instead of the "Simulator" directory - path.join(xc.path, 'Platforms', 'iPhoneOS.platform', 'Developer', 'Library', 'CoreSimulator', 'Profiles'), - path.join(xc.path, 'Platforms', 'WatchOS.platform', 'Developer', 'Library', 'CoreSimulator', 'Profiles'), - - // Xcode 11 moved CoreSimulator into the "Library/Developer" directory instead of the "Developer/Library" directory - path.join(xc.path, 'Platforms', 'iPhoneOS.platform', 'Library', 'Developer', 'CoreSimulator', 'Profiles'), - path.join(xc.path, 'Platforms', 'WatchOS.platform', 'Library', 'Developer', 'CoreSimulator', 'Profiles') - ]; - - deviceTypesPaths.forEach(function (deviceTypePath) { - // read in the device types - var deviceTypesDir = path.join(deviceTypePath, 'DeviceTypes'); - fs.existsSync(deviceTypesDir) && fs.readdirSync(deviceTypesDir).forEach(function (name) { - var plist = readPlist(path.join(deviceTypesDir, name, 'Contents', 'Info.plist')), - devId = plist && plist.CFBundleIdentifier; - if (plist) { - var deviceType = xc.simDeviceTypes[devId] = { - name: plist.CFBundleName, - model: 'unknown', - supportsWatch: false - }; - - plist = readPlist(path.join(deviceTypesDir, name, 'Contents', 'Resources', 'profile.plist')); - if (plist) { - deviceType.model = plist.modelIdentifier; - } + // Read the device types and devices in one call using the `xcrun simctl list --json` + // command. This not only improves performance (no device I/O required), but also combines + // two command (`simctl list` and `simctl list devices`) into one. + simctl.list({ simctl: xc.executables.simctl }, function (err, info) { + if (err) { + return next(err); + } - plist = readPlist(path.join(deviceTypesDir, name, 'Contents', 'Resources', 'capabilities.plist')); - if (plist) { - deviceType.supportsWatch = !!plist.capabilities['watch-companion']; - } + const devices = info.devices; + const deviceTypes = info.devicetypes; + + deviceTypes.forEach(function(deviceType) { + if (!xc.simDeviceTypes[deviceType.identifier]) { + xc.simDeviceTypes[deviceType.identifier] = { + name: deviceType.name, + model: deviceType.modelIdentifier || 'unknown', + // Assume devices with Watch in name or model support watch pairing + supportsWatch: /watch/i.test(deviceType.name) ? false : true + }; } }); - simctl.listDevices({ simctl: xc.executables.simctl }, function (err, info) { - if (err) { - return next(err); - } - - // Map the platform and version from CoreSimulator string like: - // - com.apple.CoreSimulator.SimRuntime.iOS-17-0 - // - com.apple.CoreSimulator.SimRuntime.watchOS-10-0 - for (const key of Object.keys(info.devices)) { - const [_, platform, rawVersion] = key.match(/\.SimRuntime\.(.*?)\-(.*)$/); - const version = rawVersion.replace(/-/g, '.'); - - const mapping = { - name: `${platform} ${version}`, - version - } - appc.util.mix(xc.simRuntimes, { [key]: mapping }); + // Map the platform and version from CoreSimulator string like: + // - com.apple.CoreSimulator.SimRuntime.iOS-17-0 + // - com.apple.CoreSimulator.SimRuntime.watchOS-10-0 + for (const key of Object.keys(devices)) { + const [_, platform, rawVersion] = key.match(/\.SimRuntime\.(.*?)\-(.*)$/); + const version = rawVersion.replace(/-/g, '.'); + const mapping = { + name: `${platform} ${version}`, + version } - }); + appc.util.mix(xc.simRuntimes, { [key]: mapping }); + } }); ['Simulator', 'iOS Simulator'].some(function (name) {