Geolocation

All iOS devices can help you determine user's location. You can show user's location on a map like we already did in a previous chapter where we were working with Mapkit, or you can get user's location in a form of Latitude and Longitude coordinates.

To get user's location, we need to ask user's permission first. Then we can initialize location manager object that gets user's location and calls its delegate method to pass results to the app. You can simplify your code by using BubbleWrap gem. With it, you need only two lines of code to get user's location. However in this example, we will use plain Objective-C-style code.

Except actual code that will get user's location, we need to modify Rakefile a little bit. Location services are not included in your application by default, and we need to import CoreLocation framework first. Also, since iOS8 Apple wants developers to provide location usage description.

Let's start. We will use superapp as an example. We will get location each time user want to track his mood. In the future, we will use this location to get weather forecast in a Networking Chapter, but for now, we are only interested in printing user's latitude and longitude into the console.

Let's start with Rakefile. First we are going to provide usage description. It will be stored in the Info.plist, and will be shown when the app will ask for location permissions. Also, we need to include CoreLocation framework:

        # Beginning of Rakefile ...
        Motion::Project::App.setup do |app|
          # Use `rake config' to see complete project settings.
          app.name = 'superapp'
          app.device_family = [ :iphone, :ipad ]

          message = "We need your location to get weather forecasts"
          app.info_plist["NSLocationAlwaysUsageDescription"] = message
          app.info_plist["NSLocationWhenInUseUsageDescription"] = message

          app.frameworks += [ 'CoreLocation' ]

          # rest of Rakefile ...
        end
      

Now we can add code to get user's location. Since we want to track it only when a user wants to add new Mood object, let's do it in MoodSelectorScreen. In the will_appear method, we will add a call to a get_location method, which will create location manager object, and will get user's position for us. When we finally will have user's position, we will stop location manager and save user's position in an instance variable. If Location Manager fails to get location for some reason, it will try to call locationManager(manager, didFailWithError: error) method, so we will implement it as well:

        class MoodSelectorScreen < PM::Screen
          title "Mood Selector"

          # your MoodSelectorScreen code ...

          def will_appear
            get_location
          end

          def get_location
            @location_manager ||= CLLocationManager.alloc.init
            @location_manager.delegate = self
            @location_manager.requestWhenInUseAuthorization

            @location_manager.startUpdatingLocation
          end

          def locationManager(manager, didUpdateLocations: locations)
            # locations is an array of all user locations. Last is the newest one:
            location = locations.last
            manager.stopUpdatingLocation

            @location = {
              lat: location.coordinate.latitude,
              lng: location.coordinate.longitude,
            }

            NSLog "Location:"
            NSLog "#{@location}"
          end

          def locationManager(manager, didFailWithError: error)
            NSLog "#{error}"
          end

          # rest of MoodSelectorScreen code ...
      

If you are going to test app in Simulator, you can set a custom location to it. To do it, open Debug -> Location menu of iOS Simulator, and choose whatever location you like best. And after let's start the app:

Don't forget to commit all changes!

        git add .
        git commit -m "get user location"
      

Summary

Getting user's location is pretty easy, and can be done in 5-6 strings even without any gems. First you need to add CoreLocation framework and to provide usage description in your Rakefile - this info will be shown when an app will ask for Location Permissions.

When ready, you can create Location Manager object, set its properties if needed, and tell it to start updating locations. When location manager has some results, it will call its delegate method to pass you location values.

I would also suggest you to check Apple's CLLocationManager docs. It will help you to set desired accuracy, distance filters, and other essential properties.

Book Index | Next