Latest 1.0.0
Homepage https://github.com/vermont42/GpxLocationManager
License MIT
Platforms ios 8.0, requires ARC
Frameworks CoreLocation
Authors

DEMO

Xcode’s iOS-app simulator helpfully provides four sets of GPS data for development of apps using CLLocationManager: Apple campus, city bike ride, city run, and highway drive. I was developing an app that uses GPS and found this data deficient in two ways. First, the data contain no altitudes other than “0”. Altitude tracking is important for my app, and this inability to test my app’s altitude tracking was unacceptable. Second, the simulator provides data only at normal speed. During my develop/run/debug/run cycle, I became impatient waiting for the simulator to provide GPS data to my app, even using the relatively fast-moving highway-drive mode.

In an epic bout of yak shaving, I have remedied these deficiencies by developing GpxLocationManager. This class can replace CLLocationManager at compile- or runtime, allowing clients to access GPS data from two sources: GPX files and arrays of CLLocations. In particular, GpxLocationManager invokes its clients’ didUpdateLocation() method with GPS data from either of these two sources. GpxLocationManager can provide this data at the same speed it was recorded or sped up by an arbitrary amount.

Development of the sample app continues here. I welcome pull requests for GpxLocationManager.

I recently demonstrated GpxLocationManager to the Swift Language User Group in San Francisco. Realm was kind enough to record, transcribe, and host my talk.

Use

Here are the steps to use GpxLocationManager in your app.

  1. Obtain the framework via CocoaPods or by copying the files RaceRunner/GpxLocationManager.swift, LocationManager.swift, and GpxParser.swift to your project. If you go the CocoaPods route, you will need to import GpxLocationManager in any file using classes from that framework.

  2. Where you were declaring and instantiating a CLLocationManager, instead declare and instantiate a LocationManager. Depending on how you instantiate LocationManager, there are three possibilities: (1) No arguments: LocationManager instantiates a CLLocationManager (2) Pass a String gpxFile: LocationManager instantiates a GpxLocationManager using the GPX filename you pass in, appending .gpx to the filename. (3) Pass a [CLLocation] locations: LocationManager instantiates a GpxLocationManager using the array of CLLocations passed in. The wrapper LocationManager exists so that you can decide at run time whether you want a GpxLocationManager or CLLocationManager running under the hood. The demo uses this flexibility. If you don’t need this flexibility, you can instantiate GpxLocationManager directly, avoiding the LocationManager wrapper.

  3. Set the LocationManager’s delegate to something that implements CLLocationManagerDelegate.

  4. Optionally set the LocationManager’s secondLength property to something other than 1.0. A lower value speeds up the underlying GpxLocationManager. If the LocationManager wraps a CLLocationManager, this property has no effect.

  5. Invoke the LocationManager’s startUpdatingLocation() method. The LocationManager will start calling the delegate’s didUpdateLocations() method using data from the device’s GPS, the simulator’s GPS, the GPX file you specified, or the CLLocation array you specified.

  6. Invoke the LocationManager’s stopUpdatingLocation() method to pause the location updates.

  7. If you are running a GpxLocationManager and want to stop the NSTimer causing it to invoke didUpdateLocations(), invoke the LocationManager’s kill() method. This method has no effect if there is an underlying CLLocationManager.

Demo

The demo for GpxLocationManager is a pre-release version of my race-tracking app, RaceRunner.

Click here to watch the demo in action. In this run, GpxLocationManager gets GPS data from a GPX file, and RaceRunner plays the data back sped up ten times. Note that a 40-minute run takes four minutes to watch.

The app’s main menu currently has the following options:

  • Device GPS: This starts a run using location data from the device’s GPS or the simulator’s GPS, depending on where the app is running.
  • CLLocations: This starts a run using data from an array of CLLocations. In RaceRunner, the array is built using a GPX file, but the CLLocations can come from anywhere.
  • GPX File: This starts a run using data from a GPX file.
  • History: This allows you to see details about past runs.
  • Settings: This allows you to change the playback speed of simulated locations from 100% to 1000%. These percentages correspond to second lengths of 1.0 and 0.1 seconds, respectively.

Comments

GpxLocationManager is written in Swift 2.0.

To see examples of LocationManager being instantiated in different ways, take a look at RunModel.swift.

If you use or are intrigued by GpxLocationManager, please consider starring the repo.

GpxLocationManager is not a functionally complete replacement for CLLocationManager. The former lacks much of the latter’s functionality. GpxLocationManager’s primary function is to invoke didUpdateLocations() with arbitrary location data. That said, GpxLocationManager could certainly serve as a starting point for a functionally complete replacement for CLLocationManager.

GpxLocationManager correctly parses GPX files created by iSmoothRun, Runmeter, and Runkeeper. I have not tested GPX files from other sources.

RaceRunner can detect current temperature and weather, but only if you obtain an API key from Dark Sky and set apiKey in DarkSky.swift. I will credit Dark Sky in the UI before I release RaceRunner.

RaceRunner does not pretend to be a functionally complete race-tracking app. Rather, at this point, RaceRunner is largely a Swift translation of Matt Luedke’s MoonRunner with the addition of three features: an animated pin, colored altitude overlays, and (potentially) simulated GPS data. I plan to polish the UI, implement certain racing-oriented features, and eventually release RaceRunner into the App Store. Please let me know if you are interested in beta-testing RaceRunner.

RaceRunner does not gracefully handle massive datasets. By massive, I mean “the drive from Berkeley to Lake Tahoe”. I plan to fix this at some point.

I recognize that RaceRunner’s error handling is unfinished.

Creator

Josh Adams

Credits

GpxLocationManager does not use any third-party code, but RaceRunner is based on MoonRunner and uses MarqueeLabel and a modified version of Sweather. All three were released under the MIT license, reproduced below.

License

The MIT License (MIT)

Copyright (c) 2015 Josh Adams

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

The End

Latest podspec

{
    "name": "GpxLocationManager",
    "version": "1.0.0",
    "summary": "GPS data from GPX files",
    "description": "GpxLocationManager allows the developer to import and use GPS data from GPX files when developing code that uses CLLocationManager. Without GpxLocationManager, the developer has just four GPS datasets to choose from in the simulator. These datasets suffer the serious shortcoming that altitudes are always 0. Unlike CLLocationManager, GpxLocationManager can optionally speed up playback of GPS datasets, allowing faster testing.",
    "homepage": "https://github.com/vermont42/GpxLocationManager",
    "license": "MIT",
    "authors": {
        "vermont42": "[email protected]"
    },
    "source": {
        "git": "https://github.com/vermont42/GpxLocationManager.git",
        "tag": "1.0.0"
    },
    "social_media_url": "https://twitter.com/vermont42",
    "platforms": {
        "ios": "8.0"
    },
    "requires_arc": true,
    "source_files": [
        "RaceRunner/GpxLocationManager.swift",
        "RaceRunner/GpxParser.swift",
        "RaceRunner/LocationManager.swift"
    ],
    "frameworks": "CoreLocation"
}

Pin It on Pinterest

Share This