Skip to content

Commit

Permalink
Add Xcode 9 support (#5)
Browse files Browse the repository at this point in the history
* Add Xcode 9 support

With the large number of simulator changes in Xcode 9 came a change
where the notification we're hijacking needs to send along the UDIDs of
the simulators where the change should take effect. This is because you
can have multiple running simulators with different locations.

To do this, for now, we're just reading the output of `simctl list` and
sending all booted UDIDs along.

* Use JSON output instead
  • Loading branch information
Keith Smiley authored Aug 10, 2017
1 parent dad22eb commit a52b6bf
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 3 deletions.
8 changes: 6 additions & 2 deletions sources/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ guard let command = commands[flag] else {

switch command(Array(arguments)) {
case .success(let coordinate) where coordinate.isValid:
print("Setting location to \(coordinate.latitude) \(coordinate.longitude)")
postNotification(for: coordinate)
do {
postNotification(for: coordinate, to: try getBootedSimulators())
print("Setting location to \(coordinate.latitude) \(coordinate.longitude)")
} catch let error as SimulatorFetchError {
exitWithUsage(error: error.rawValue)
}
case .success(let coordinate):
exitWithUsage(error: "Coordinate: \(coordinate) is invalid")
case .failure(let error):
Expand Down
3 changes: 2 additions & 1 deletion sources/notification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import Foundation

private let kNotificationName = "com.apple.iphonesimulator.simulateLocation"

func postNotification(for coordinate: CLLocationCoordinate2D) {
func postNotification(for coordinate: CLLocationCoordinate2D, to simulators: [String]) {
let userInfo: [AnyHashable: Any] = [
"simulateLocationLatitude": coordinate.latitude,
"simulateLocationLongitude": coordinate.longitude,
"simulateLocationDevices": simulators,
]

let notification = Notification(name: Notification.Name(rawValue: kNotificationName), object: nil,
Expand Down
42 changes: 42 additions & 0 deletions sources/simulators.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Foundation

enum SimulatorFetchError: String, Error {
case simctlFailed = "Running `simctl list` failed"
case failedToReadOutput = "Failed to read output from simctl"
case noBootedSimulators = "No simulators are currently booted"
}

func getBootedSimulators() throws -> [String] {
let task = Process()
task.launchPath = "/usr/bin/xcrun"
task.arguments = ["simctl", "list", "-j", "devices"]

let pipe = Pipe()
task.standardOutput = pipe

task.launch()

let data = pipe.fileHandleForReading.readDataToEndOfFile()
task.waitUntilExit()
pipe.fileHandleForReading.closeFile()

if task.terminationStatus != 0 {
throw SimulatorFetchError.simctlFailed
}

guard let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] else {
throw SimulatorFetchError.failedToReadOutput
}

let devices = json["devices"] as? [String: [[String: String]]] ?? [:]
let bootedIDs = devices
.flatMap { $1 }
.filter { $0["state"] == "Booted" }
.flatMap { $0["udid"] }

if bootedIDs.isEmpty {
throw SimulatorFetchError.noBootedSimulators
}

return bootedIDs
}

0 comments on commit a52b6bf

Please sign in to comment.