paint-brush
Simulating user location and navigation route on iPhone without Xcode.by@manish.katoch
7,198 reads
7,198 reads

Simulating user location and navigation route on iPhone without Xcode.

by Manish KatochDecember 6th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Recently, as a part of a proof of concept for certain personalized interface around user’s location, we realized that the best way to showcase the feature would be to simulate a users journey. on an iPhone. without any cables connecting to a <a href="https://hackernoon.com/tagged/xcode" target="_blank">Xcode</a> instance.<em> So, we set out to figure out what it takes to</em><strong><em> simulate</em></strong><em> a user location and </em><strong><em>user’s journey from point A to point B, on an actual device on demand, without using Xcode to simulate location</em></strong><em>.</em>

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Simulating user location and navigation route on iPhone without Xcode.
Manish Katoch HackerNoon profile picture

The Problem Statement:

Recently, as a part of a proof of concept for certain personalized interface around user’s location, we realized that the best way to showcase the feature would be to simulate a users journey. on an iPhone. without any cables connecting to a Xcode instance. So, we set out to figure out what it takes to simulate a user location and user’s journey from point A to point B, on an actual device on demand, without using Xcode to simulate location.

Step 1: The GPX file

The logical step would be to first setup the route to simulate. The easiest way would be to get directions on google map and then convert it to a .gpx file here. If you are simulating navigation route, make sure you select track points options.

The gpx file created looks something like this:

a sample gpx file showing trackpoints!

save this gpx file to your XCode project for later use.

Step 2: GPX Parser

Next step is to be able to parse this gpx file as a collection of CLLocation structures which can be then simulated. The following gist shows how it can be done.

The class which is responsible for invoking GpxParser, also conforms to the GpxParsing protocol which allows it to proceed further once the parsing completes. The output of this parsing is a Queue<CLLocation>. Implementing a Queue should be trivial (or a good exercise to do :) ).

3. MockCLLocationManager

CLLocationManager (from CoreLocation module) is THE primary class which provides all the location specific functionality to an iOS application. If you are writing a location aware application, you would implement a CLLocationManager. If you are using MKMapView to show maps, MKMapView would internally rely on CLLocationManager to provide location details. So, It makes sense for us to create a MockCLLocationManager and mimic CLLocationManager using the parsed gpx file locations and serve them at intervals.

MockCLLocationManager provides some sugar methods like startMocks using a gpx file’s name, or stop it.

4. OK, So what’s the plan now?

As a recap, we now have capability to express a route as a queue of CLLocation structures. We also have capability to mock CLLocationManager and mimic change of locations. All we need to do now is redirect all the requests to CLLocationManager to this MockCLLocationManager.

Sounds simple. But How?

One word: Swizzling!

NSHipster has an excellent blog explaining swizzling. Simply put, it is a way to change behavior of a class (specifically it’s methods) at runtime. Idea is that whenever runtime tries to access CLLocationManager, our method which we have “swizzled” executes same on MockCLLocationManager and calls appropriate delegates so that the caller gets the requested location.

The swizzling is completed in DLAppDelegate by calling CLLocationManager.classInit (this is the place you would check for debug or production build).

Enough of the words. here’s the gist:

One may argue that why Swizzle and not just use MockCLLocationManager instance?. There are two issues with that approach. It won’t help in simulating location updates on MKMapView as it uses internal instance of CLLocationManager ( thank you Apple! :| ). Secondly, we have just one location to toggle this behavior. Honestly, you wouldn’t want to even accidentally ship this code to production!

So, I assume you had this working?

word.

below’s the view controller gist. You would see there are no traces of any mocking.

And here’s code in action!

Thank you for reading! If you liked this article, please share/recommend. If not, please comment/critique so I can improve and learn more! :)