Perhaps the most indispensable tool when developing iOS applications is the iOS simulator. However, if you want to test an app whose functionality revolves around utilizing the device’s GPS, then you’re out of luck – Apple’s iOS simulator will only provide you with a single location (the location of Apple’s headquarters). Furthermore, whilst the next version of XCode promises some progress in this area, it’s still not clear if/how it’ll be able to recorded data for later playback. In this entry I’m going to detail the process we followed to create a small location simulation framework that can also record data.
Recently we needed to be able to simulate a series of GPS updates, so that these updates could then be used to alter the state of our application. After scouring the net for an existing solution we realized that we would need to roll our own.
Location Simulator: The Gory Details
It was decided that we would wrap a custom CLLocationManager in our own LocationService. As we are overriding the updates that are sent to us by the iOS simulator as they come in from the hardware, the rest of the application is only aware of the resulting processed updates.
Just as they could with any location service, interested controllers register themselves and receive the processed updates via the NSNotificationCenter.
Our CLLocationManager then contains our simulation object. This object is responsible for providing fake GPS updates to the CLLocationManager. Once it receives these, it passes them onto the LocationService in exactly the same way it would pass real GPS updates – via the CLLocationManagerDelegate protocol. With this setup we have been able to make the simulation completely indistinguishable from how the app would function when out-and-about in the real world.
Initially our simulation object was providing updates based on one of our model objects (essentially containing an array of lat\longs). This was great for simulating, however what we really needed was a way to replicate all the quirky issues that our testers were running into when they were out in the field.
Introducing the Location Recorder
The next logical step was to build in some functionality to record and playback GPS data from our tester’s excursions. Thus the Location Recorder was born. Similarly transparent to the simulation object, the location recorder would register itself with the LocationService – as any controller in the app would. It would then take the updates received and store them in an array until the tester stopped recording.
Once the recording had finished this array of CLLocations was then saved out to the device as a plain text JSON formatted file. This file could then be emailed from the device to other testers \ devs.
These files could then uploaded on a case-by-case basis to our issue tracker, from there they could be downloaded onto devices ready for playback. Once on the device you would be prompted to select from a list of location files.
The location tracker would then iterate over the saved data (the saved CLLocation objects) and forward them onto the LocationService via the same CLLocationManagerDelegate protocol. So once again, as far as the LocationService and the rest of the app is concerned, the updates being received are coming from GPS hardware.
This proved to be invaluable for replicating and solving defects, as it allowed us to playback a testers journey and have the app respond in exactly the same manner as it did when the data was being recorded.
In addition to resolving defects, the recorded location data was used to fine tune our algorithms to work more efficiently in the real world.
In the future, further improvements could be made to this setup, starting with the incorporation of the location tracker into the LocationService in a similar fashion to the way the simulation object operates. Separating the tracking and simulation components out of the project they were used for and into their own generic framework would also be beneficial, as it would be an incredibly handy tool to be able to drop into any future projects that require it.
What about the next version of XCode?
Since starting this blog post the new XCode for iOS5 was announced and put into beta. One of the new features included in this is the ability for the iOS simulator to provide simulated location data. You can currently select from several preset routes while also being able to enter in a specific location you wish to simulate, although I’ve currently been unable to find any mention of the ability to define custom routes to playback.
The aspect that sets our solution apart from the forthcoming iOS update stem mainly from the fact that we can control our simulation data from within the app itself, whether it be loading from a recorded text file or from our model objects. Our ability to simulate location data on devices also separates this solution from the upcoming iOS 5, which is limited to working within the iOS Simulator.