2

I would like to clarify a few moments about traking user location while app is suspended. I have read a lot of articles about it but didn't find any clear answer.

  • Is it possible to create a local notification based on a user's location when application is suspended?
  • If it's possible, how my app's architecture has look like? Is my CLLocationManager subclass instance needs to be declared in AppDelegate file or it can be created as variable of some controller?
RomanHouse
  • 2,552
  • 3
  • 23
  • 44
  • about tracking user location while app is suspended? It wold huge violation of the user privacy . User Kills the app expecting that it won't perform any actions in the background. – ProblemSlover Nov 22 '16 at 18:12
  • @ProblemSlover not true. You can track user locations in the background, but only for significant location changes. You can do this all through the AppDelegate, just register for background location updates. Take a look at this example for an idea, he is using geofences for updating locations in the background then registering for new geofences when one of the geofences has been entered: http://stackoverflow.com/a/30789632/3543861 – MSU_Bulldog Nov 22 '16 at 18:17
  • @MSU_Bulldog Not true what? If I correctly understand the question is about if it's possible to do it while app is suspended. Suspended means being terminated by the user am I correct.? You can for sure receive the location updates as long as the app remains in the background. – ProblemSlover Nov 22 '16 at 18:22
  • 1
    Your question is unclear. First you say "terminated". Then you say "suspended". Those are two completely different things! Which are you asking about? – matt Nov 22 '16 at 18:50

3 Answers3

2

There are a couple of different ways to handle this.

You can set up a region-based local notification. That displays a message to the user if your app is not in the foreground. Your app only gets notified/launched if the user taps the action button on the local notification.

Another way to handle it:

You use the Core Location manager to create "geofence" regions that the system monitors on your app's behalf.

When your app is launched you should create an instance of the location manager and set up a delegate. You need to handle the process of asking the user for permission for location updates, and permission for always monitoring the user's location. That is a fussy, multi-step process, and if you miss a step it doesn't work. See the docs for more information. (I always have to back and re-read them when I'm setting up a new app with location services, and usually don't get it right the first time.)

When you've done that, the system will launch your app if it's not running when you receive a region enter/exit event. Once you create the location manager and set up a delegate, that delegate gets notified about the region enter/exit event.

In your handler for region enter/exit events you can post a local notification to yourself if you want to.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • Right? I would forget `NSLocationWhenInUseUsageDescription`/ `NSLocationAlwaysUsageDescription` and the continued lack of console errors would leave me scratching my head! – Nathaniel Nov 22 '16 at 18:51
  • System can monitor maximum 20 regions. But what in case when I have more when 20 regions to monitor? – RomanHouse Dec 08 '16 at 15:28
1

You can register the user for a local notifications using the region property.

    //latitude & longitude come from your CLLocationManager delegates
    let region = CLCircularRegion(center: CLLocationCoordinate2DMake(45.5017, 73.5673), radius: 1500, identifier: "identifier") 
    region.notifyOnExit = false
    region.notifyOnEntry = true

    let notification = UILocalNotification()
    notification.region = region
    notification.regionTriggersOnce = true //only show this notification once
    notification.alertTitle = "Foo"
    notification.alertBody = "Hello World"
    UIApplication.shared.scheduleLocalNotification(notification)

Note that you can have at most 64 local notifications: https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/

UPDATE: "You can only monitor a maximum of 20 location regions at one time. (and that's a combined total of 20 geofence regions and beacon regions.)" - DuncanC

Nathaniel
  • 836
  • 9
  • 19
  • @DuncanC I was showing how you can create a local notification based on the user's location, which was the first question. OP already mentioned they know about CLLocationManager and can use the last-known coordinate to create the notification. – Nathaniel Nov 22 '16 at 18:43
  • 1
    Ok, I see what you were talking about. Region-based local notifications. That notifies the user rather than launching your app. Note that while you can have up to 64 local notifications pending, you can only monitor a maximum of 20 location regions at one time. (and that's a combined total of 20 geofence regions and beacon regions.) – Duncan C Nov 22 '16 at 18:52
  • @DuncanC True. Perhaps `func locationManagerDidPauseLocationUpdates(_ manager: CLLocationManager)` could be used for when the application is suspended. then `manager.location` will provide _The last location received. Will be nil until a location has been received._ – Nathaniel Nov 22 '16 at 18:54
1

Is it possible to create a local notification based on a user's location when application is suspended?

Yes. When you use background location monitoring, if your app is not active, it is woken in the background long enough to receive an event from the runtime. Thus, your app is now temporarily running. At that moment, creating a local notification is legal.

If it's possible, how my app's architecture has look like? Is my CLLocationManager subclass instance needs to be declared in AppDelegate file or it can be created as variable of some controller?

The event from the runtime is going to be sent to your location manager's delegate. Therefore your location manager needs to exist and it needs to have a delegate. It doesn't have to be a property of the app delegate, but it certainly needs to be a property of some instance that actually exists, so it if is a view controller, it had better not be a view controller that is not always present.

Note that if your app has been terminated while suspended (which is always a possibility), it will be launched from scratch (in the background) in order to receive this event. In that case, you can learn from the options: dictionary in didFinishLaunchingWithOptions: that this is because of an incoming location event, and thus you can respond by doing whatever is necessary in order to get yourself a location manager and a delegate.

matt
  • 515,959
  • 87
  • 875
  • 1,141