iOS Geo-Fencing in TimeTraveler – Part 2 of 3

Download Yahoo! TimeTraveler v2.0 for free in iTunes App Store

This is the second installment of a series on iOS Geo-Fencing in Yahoo! TimeTraveler. Please also read Part I and Part III if you find it interesting.


My heart sank deeper as more test results came pouring in. The geo-fencing feature in an QA build of TimeTraveler wasn’t working as planned, and I was clueless.

Here’re some of the reports my teammates recorded:

Exhibit #1: Walking trip from SOMA to Ferry Building, San Francisco.


Exhibit #2: Bus trip from City Hall to Jackson Square.


Exhibit #3: Could not trigger alert afterwards, no matter how close to POI.


You can imagine how I felt back then. The test couldn’t have gone any worse. I had but one night to troubleshoot the problem (raising any alarms would postpone further QA work and wouldn’t win me any favors), so there was no time to moan.

Dissecting the Problem:

In a way, it was good that the error reports were so similar. Common issues ran through the exhibits above included delayed notifications, notifications not being triggered and the wrong notifications being triggered.


Session 303 did not go into depths about how geo-fencing was implemented – in particular, when and how  locationManager:didEnterRegion gets invoked. As usual, I made the most common mistake a novice programmer would – started writing code without reading the freaking manual. Worst, I had other team members pay the price of this carelessness by having them running half way across the city testing out an unproven feature. It was time to pay the due and re-learn what the technology had to offer from the source.

Fortunately, the documentation did come to my rescue – some points really jumped out on me as I was reading through the page. They seemed to touch on, if not explain, all the issues we were facing.

“Monitoring of a region begins immediately after registration. However, do not expect to receive an event right awayOnly boundary crossings can generate an event. Thus, if at registration time the user’s location is already inside the region, the location manager does not generate an event. Instead, you must wait for the user to cross the region boundary before an event is generated and sent to the delegate”.
“…the user’s location must cross the region boundary and move away from that boundary by a minimum distance and remain at that minimum distance for at least 20 seconds before the notifications are reported”.
“…if Wi-Fi is disabled, region monitoring is significantly less accurate. However, for testing purposes, you can assume that the minimum distance is approximately 200 meters.”
“…an app can expect to receive the appropriate region entered or region exited notification within 3 to 5 minutes on average, if not sooner.”

The obvious takeaways from the excerpts above were:

  1. Triggering is based on “boundary crossings”, not current location. That means when you’re already inside a geo-fence, the didEnterRegion method would not be invoked.
  2. Notification is not instantaneous.
  3. Monitoring isn’t dead-on accurate but has a loose bound of 200 meters.


The fact that notifications weren’t being triggered most of the time got me thinking that something fundamental, likely configuration, went awry. That further got me to open up the plist file in Xcode to check if the correct parameters were in it, namely UIBackgroundModes.

plist file in xcode

Now, before reading on, please take a longer look at the plist file above, especially the highlighted section. At first, it’s unlikely you would notice anything out of the ordinary. After all, the keys and values were auto-completed by Xcode. However, I have grown really suspicious of plist files over the years and knew better how to debug them – in text mode.

same plist file in text only view

Voila! Keys in plist files aren’t meant to be legible, and the “Required Background Modes” value looked waaayy too out-of-place. Shouldn’t that key be named “UIBackgroundModes“? I went ahead and made the amendment while in text view. Out of curiosity, I switched back to formatted view and see how Xcode has handled the change.

plist file AFTER the change. “Required Background Modes” changed to “UIBackgroundModes” and value changed to “location”.
Formatted view after the save. Note Xcode is showing lower case “b” for “Background”. This inconspicuous typo was the culprit of all mayhem and panic.

Apparently that edit triggered something prominent. No longer was the value App registers for location updates or the key Required Background Modes, Xcode has updated them to location and UIBackgroundModes respectively. In the formatted view, I noticed how the “B” in Background became lower case. It seemed that the auto-completed suggestion from Xcode was incorrect right from the start – causing the app to not receive any location updates and rendering the entire geo-fencing feature broken!


Initially I set the geo-fence radius to be 30 meters, which in a densely populated city like San Francisco might be the typical length of an entire block. From #1 RTFM, it turned out iOS cannot yet handle locations to such granularity and 200 meters is considered a minimum. So that was one change I made immediately.



The biggest limitation in iOS’s implementation of geo-fencing was the mandate for boundary crossing – the imposition that a user has to enter or exit the borders of a monitored region to receive any type of triggering. I believe this restriction was imposed to prevent false positives, but it might be too stringent for a lot of real world use cases. For instance, if I want to know immediately whether a certain ice cream parlor is nearby, I shouldn’t be asked to step two mile away then return later. That just doesn’t make sense.

The workaround needed here would be for the app to do its own triggering to handle cases ignored by iOS by default. When running in foreground or background, the app could register for location updates and execute the needed logic if the current location lies within a monitored region radius. After firing the notification, it would have to unregister the region from monitoring as well.

didUpdateLocation with custom triggering (abridged source code version)

As with all workarounds there was a caveat. The app would need to be running in foreground or background mode for this logic to execute. On the other hand, the concern for battery drain is not too great, if the AutoPause feature in iOS 6 works as advertised.

Putting it all to test

All that observation and patches were done from the comfort of my laptop with help from the iOS simulator. Armed with a new build, I headed up to the city to do some field testing of my own. The outcomes of the test would decide whether the whole geo-fencing idea was a stroke of genius or a huge waste of everyone’s time.

In the next post I’ll document how the testing went and what new insights we managed to gain while shouting and waving our iPhones across the streets of San Francisco.

Extended Reading:

Hawk iMedia: Geo-Fencing – what do you do with it?
– 4 iPhone Apps That Use Geofencing (And, Geofencing, Explained)

10 thoughts on “iOS Geo-Fencing in TimeTraveler – Part 2 of 3

  1. Thanks! I have the same problem but I need your method “calculateDistanceInMetersBetweenCoord”… Could you share it please?🙂

      1. Thanks a lot! The Region Monitoring could be a headache, I made an App for be alerted when the user get closer to different places but just sometimes it works. Another question, when did you called “startUpdatingLocation” for to launch “didUpdateLocations”?

      2. In AppDelegate applicationWillEnterForeground:, I call a method that inits a separate instance of CLLocationManager dedicated to region monitoring (after making sure [CLLocationManager regionMonitoringAvailable]). I set its activityType to “CLActivityTypeFitness”, desiredAccuracy to “kCLLocationAccuracyBest”, “setPausesLocationUpdatesAutomatically” to YES and delegate to self (the AppDelegate) before calling its startUpdatingLocation.

    1. You also can use the containsCoordinate: methods of CLCircularRegion class :
      – (BOOL)containsCoordinate:(CLLocationCoordinate2D)coordinate;

  2. Hello Kensin,

    When the app is closed (not in background, but totally closed), how app can we get didEnterRegion or didExitRegion delegate method call, when user enter a region?

    Please update me as soon as possible.

    Thanks iN Advance…🙂

    1. Sorry for the late response Deepak. From apple’s doc – iOS will launch your app in the background for a short period and deliver location info to you. Make sure the correct UIBackgroundModes is set for your app.

      “In the case of a suspended app, the system wakes up the app, delivers the update to the location manager’s delegate, and then returns the app to the suspended state as soon as possible. While it is running in the background, your app should do as little work as possible to process the new location data.”

  3. Note that you can simplify distance calculation by using the containsCoordinate method of CLRegion :
    if ([region containsCoordinate:location.coordinate]) {
    [self locationManager:self.locationManager didEnterRegion:region];

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s