class FastlaneCore::DeviceManager

Public Class Methods

all(requested_os_type = "") click to toggle source
# File fastlane_core/lib/fastlane_core/device_manager.rb, line 10
def all(requested_os_type = "")
  return connected_devices(requested_os_type) + simulators(requested_os_type)
end
connected_devices(requested_os_type) click to toggle source
# File fastlane_core/lib/fastlane_core/device_manager.rb, line 68
def connected_devices(requested_os_type)
  UI.verbose("Fetching available connected devices")

  device_types = if requested_os_type == "tvOS"
                   ["AppleTV"]
                 elsif requested_os_type == "iOS"
                   ["iPhone", "iPad", "iPod"]
                 else
                   []
                 end

  devices = [] # Return early if no supported devices are being searched for
  if device_types.count == 0
    return devices
  end

  usb_devices_output = ''
  Open3.popen3("system_profiler SPUSBDataType -xml") do |stdin, stdout, stderr, wait_thr|
    usb_devices_output = stdout.read
  end

  device_uuids = []
  result = Plist.parse_xml(usb_devices_output)

  discover_devices(result[0], device_types, device_uuids) if result[0]

  if device_uuids.count > 0 # instruments takes a little while to return so skip it if we have no devices
    instruments_devices_output = ''
    Open3.popen3("instruments -s devices") do |stdin, stdout, stderr, wait_thr|
      instruments_devices_output = stdout.read
    end

    instruments_devices_output.split(/\n/).each do |instruments_device|
      device_uuids.each do |device_uuid|
        match = instruments_device.match(/(.+) \(([0-9.]+)\) \[(\h{40}|\h{8}-\h{16})\]?/)
        if match && match[3].delete("-") == device_uuid
          devices << Device.new(name: match[1], udid: match[3], os_type: requested_os_type, os_version: match[2], state: "Booted", is_simulator: false)
          UI.verbose("USB Device Found - \"" + match[1] + "\" (" + match[2] + ") UUID:" + match[3])
        end
      end
    end
  end

  return devices
end
discover_devices(usb_item, device_types, discovered_device_udids) click to toggle source

Recursively handle all USB items, discovering devices that match the desired types.

# File fastlane_core/lib/fastlane_core/device_manager.rb, line 116
def discover_devices(usb_item, device_types, discovered_device_udids)
  (usb_item['_items'] || []).each do |child_item|
    discover_devices(child_item, device_types, discovered_device_udids)
  end

  is_supported_device = device_types.any?(usb_item['_name'])
  serial_num = usb_item['serial_num'] || ''
  has_serial_number = serial_num.length == 40 || serial_num.length == 24

  if is_supported_device && has_serial_number
    discovered_device_udids << serial_num
  end
end
latest_simulator_version_for_device(device) click to toggle source
# File fastlane_core/lib/fastlane_core/device_manager.rb, line 130
def latest_simulator_version_for_device(device)
  simulators.select { |s| s.name == device }
            .sort_by { |s| Gem::Version.create(s.os_version) }
            .last
            .os_version
end
simulators(requested_os_type = "") click to toggle source
# File fastlane_core/lib/fastlane_core/device_manager.rb, line 14
def simulators(requested_os_type = "")
  UI.verbose("Fetching available simulator devices")

  @devices = []
  os_type = 'unknown'
  os_version = 'unknown'
  output = ''
  Open3.popen3('xcrun simctl list devices') do |stdin, stdout, stderr, wait_thr|
    output = stdout.read
  end

  runtime_info = ''
  Open3.popen3('xcrun simctl list runtimes') do |stdin, stdout, stderr, wait_thr|
    # This regex outputs the version info in the format "<platform> <version><exact version>"
    runtime_info = stdout.read.lines.map { |v| v.sub(/(\w+ \S+)\s*\((\S+)\s[\S\s]*/, "\\1 \\2") }.drop(1)
  end
  exact_versions = Hash.new({})
  runtime_info.each do |r|
    platform, general, exact = r.split
    exact_versions[platform] = {} unless exact_versions.include?(platform)
    exact_versions[platform][general] = exact
  end

  unless output.include?("== Devices ==")
    UI.error("xcrun simctl CLI broken, run `xcrun simctl list devices` and make sure it works")
    UI.user_error!("xcrun simctl not working.")
  end

  output.split(/\n/).each do |line|
    next if line =~ /unavailable/
    next if line =~ /^== /
    if line =~ /^-- /
      (os_type, os_version) = line.gsub(/-- (.*) --/, '\1').split
    else
      next if os_type =~ /^Unavailable/

      # "    iPad (5th generation) (852A5796-63C3-4641-9825-65EBDC5C4259) (Shutdown)"
      # This line will turn the above string into
      # ["iPad (5th generation)", "(852A5796-63C3-4641-9825-65EBDC5C4259)", "(Shutdown)"]
      matches = line.strip.scan(/^(.*?) (\([^)]*?\)) (\([^)]*?\))$/).flatten.reject(&:empty?)
      state = matches.pop.to_s.delete('(').delete(')')
      udid = matches.pop.to_s.delete('(').delete(')')
      name = matches.join(' ')

      if matches.count && (os_type == requested_os_type || requested_os_type == "")
        # This is disabled here because the Device is defined later in the file, and that's a problem for the cop
        @devices << Device.new(name: name, os_type: os_type, os_version: (exact_versions[os_type][os_version] || os_version), udid: udid, state: state, is_simulator: true)
      end
    end
  end

  return @devices
end