iOS Tutorial Background location tracking

iLocation library allows you to track the device location when your app is in the foreground.

Using the code posted in this tutorial you can mark your app as a special kind of app that requires background location updates and then your app will continue to run in the background and receive location updates until you call LocationManager.Stop or until the user kills the app.

Apple's documentation: https://developer.apple.com/library...n.html#//apple_ref/doc/uid/TP40009497-CH2-SW3

The first step is to mark the app for background execution:
B4X:
#PlistExtra: <key>UIBackgroundModes</key><array><string>location</string></array>
We also need to describe the reason for the location usage:
B4X:
#PlistExtra:<key>NSLocationAlwaysUsageDescription</key><string>Track your location in the background for better ad revenue.</string>
#PlistExtra:<key>NSLocationUsageDescription</key><string>Used to display the current navigation data.</string>
On iOS 7 the NSLocationUsageDescription string will be used. On iOS 8+ the NSLocationAlwaysUsageDescription string will be used. This replaces the standard NSLocationWhenInUseUsageDescription string. Make sure to update the strings as needed.

Two additional changes:
1. You need to call StartBackground sub instead of Location.Start
2. (optional) Call AllowPauseLocationAutomatically sub and set the activity sub. The OS will use this information to pause the location updates when the location is not expected to change.
You can read more about the activities types: https://developer.apple.com/library.../index.html#//apple_ref/c/tdef/CLActivityType

Edit: It is recommended to disable the AllowPauseLocationAutomatically as explained in post #10.

See the code in the attached project.
Note that the debugger will eventually disconnect when the app is in the background.

Edit: September 2018 - Added new required usage key:
B4X:
#PlistExtra:<key>NSLocationAlwaysAndWhenInUseUsageDescription</key><string>Track your location in the background for better ad revenue.</string>
 

Attachments

  • BackgroundLocation.zip
    2.6 KB · Views: 947
Last edited:

borofan

Member
Licensed User
Longtime User
does this type of service start at boot, or will need the app need to be opened manually?
 

fbritop

Active Member
Licensed User
Longtime User
What could be happening that my app crashes exactly 3 minutes after y press the home button.

Can't endBackgroundTask: no background task exists with identifier xxxxxx, or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.

I'm not using location manager.
 

moster67

Expert
Licensed User
Longtime User
Just some questions:
1) Does this support "Significant-Change Location Service"?
2) According to the documentation:
Note: If your app is terminated either by a user or by the system, the system doesn’t automatically restart your app when new location updates arrive. A user must explicitly relaunch your app before the delivery of location updates resumes. The only way to have your app relaunched automatically is to use region monitoring or the significant-change location service.
Will your implementation (and if the usage of "Significant-Change Location Service" is possible) permit my app to be relaunched automatically or perhaps I am just swimming.. :)
3) when the "Significant-Change Location Service" triggers, can I execute arbitrary code such as calling a webserver to obtain some data (it would only need 1 second to do so)

Thanks!
 

moster67

Expert
Licensed User
Longtime User
OK, this confirms what I thought.
I guess I got confused when I saw your reply in this thread (https://www.b4x.com/android/forum/threads/location-change-in-the-background.49748/#post-313731) where a user asked if "Significant-Change Location Service" was supported and you referred to this thread but I guess you meant background location tracking in general.

I noted that you posted the source code of the iLocation-library in your tutorial about writing libraries for B4i but that is way too difficult for me.

Therefore, is there any chance the "Significant-Change Location Service" can be added, especially since Apple themselves recommends it? Or can it be obtained by using the NativeObject-library with some inline Objective C code? Edit: perhaps already supported? - see my post below

Since I am mentioning locations, I noted that there was already a wish for Monitoring Beacon Regions. If you would do that, could you please also add support for Monitoring Geographical Regions/Geofencing (https://developer.apple.com/library...html#//apple_ref/doc/uid/TP40009497-CH9-SW1)? Edit: posted a request in the Wish-section of the forum
 
Last edited:

moster67

Expert
Licensed User
Longtime User
An update, I just found a library by @marcel named iLocationPlus Library (https://www.b4x.com/android/forum/threads/ilocationplus-library.47618/#content) and by having a look at the xml-file, it seems like he added support for the Significant-Change Location Service. However, I cannot test it now since I am in the office and I have no access to my (local) MAC but if it works, then it will fulfill my request and only my request for Monitoring Geographical Regions/Geofencing would remain...
 

moster67

Expert
Licensed User
Longtime User
Another update: The iLocationPlus library by @marcel does support the Significant-Change Location Service. I have tested it and it works.

However, you can use the Significant-Change Location Service also with the standard iLocation library as follows:

B4X:
Sub StartBackground(lm As LocationManager, MinimumDistance As Double)
    Dim no As NativeObject = lm
    no = no.GetField("manager")
    If App.OSVersion >= 8 Then
        no.RunMethod("requestAlwaysAuthorization", Null)
    End If
    no.SetField("distanceFilter", MinimumDistance)
    Dim NativeMe As NativeObject = Me
    Dim isSignLocAvailable As Boolean = NativeMe.RunMethod("isSignificantLocationAvailable", Null).AsBoolean

    If isSignLocAvailable = True Then
        no.RunMethod("startMonitoringSignificantLocationChanges",Null)
    Else
        'do something......
        'no.RunMethod("startUpdatingLocation", Null)
    End If
  
End Sub

#If OBJC

- (BOOL) isSignificantLocationAvailable {
    if ([CLLocationManager significantLocationChangeMonitoringAvailable]) return YES;
    return NO;
}

#end if

I added a verification (using inline OBJC) checking if the Significant-Change Location Service is available on the device. From what I have understood it requires a device with telephone-features.

The advantage with the Significant-Change Location Service is that it saves battery. Another advantage is that location gets updated even when the app has been killed/terminated by iOS or the user. It starts working again even when device has been rebooted. I have tested this and it works!
The disadvantage is that the location data gets updated less frequently. Apps can expect a notification as soon as the device moves 500 meters or more from its previous notification. It should not expect notifications more frequently than once every five minutes. If the device is able to retrieve data from the network, the location manager is much more likely to deliver notifications in a timely manner.

So it depends what you want to do with your locations.

To test without moving from your desk, make sure you are connected to a WIFI access point and then toggle Flight-mode on and off a few times and a location update should trigger in the LocManager_LocationChanged sub.

EDIT: You may come across this if you are reading Apple's documentation:
If you start this service and your app is subsequently terminated, the system automatically relaunches the app into the background if a new event arrives. In such a case, the options dictionary passed to theapplication:willFinishLaunchingWithOptions: and application:didFinishLaunchingWithOptions: methods of your app delegate contains the key UIApplicationLaunchOptionsLocationKey to indicate that your app was launched because of a location event. Upon relaunch, you must still configure a location manager object and call this method to continue receiving location events. When you restart location services, the current event is delivered to your delegate immediately. In addition, the location property of your location manager object is populated with the most recent location object even before you start location services.

so it seemed I needed to get hold of the UIApplicationLaunchOptionsLocationKey in order to restart the Significant-Change Location Service after the app was killed/terminated by iOS or the user (or if the device was rebooted). However, I noted that even if I don't look for the presence of the UIApplicationLaunchOptionsLocationKey (its value will be 1) and don't do something with it, the app will restart nicely and continue working. If you, however, are interested in getting the UIApplicationLaunchOptionsLocationKey, you can do so by using the following code in the AppStart event (thanks to Erel for explaining how):

B4X:
Dim mymap As Map
    mymap.Initialize
    mymap = App.LaunchOptions
    For Each key As String In mymap.Keys
        If key = "UIApplicationLaunchOptionsLocationKey" Then
            Log("Key is : " & key & " and the value is: " & mymap.Get(key))
        End If   
    Next

But as I said (and as far as I understand), it is not really needed.
 
Last edited:

moster67

Expert
Licensed User
Longtime User
I edited my previous post with some notes you may find interesting.
 

moster67

Expert
Licensed User
Longtime User
Here is another tip which may or not interest you:

You may have noted that when you use the example code in the first post of this thread (using the normal location tracking service), the location tracking will end when the app gets killed/terminated by the the user/the iOS (and definitely when the device has been rebooted) and if you want to get location tracking working again, the user must restart you app. That is fine and what is expected.

However, I noted that by taking advantage of the Significant-Change Location Service mentioned and explained in my earlier posts, you can actually get your app and the normal location tracking service to work again even after the app has been killed/terminated or the device has been rebooted ;)

To do this, just start the Significant-Change Location Service in the Application_Background sub as follows:
B4X:
Private Sub Application_Background
    'perhaps a setting in the app that user wants the app to be
    'restarted if app gets killed/terminated or the device reboots
    If RestartLocationService = True Then
        Dim no As NativeObject = locManager
        Dim MinimumDistance As Double = 0
        no = no.GetField("manager")
        If App.OSVersion >= 8 Then
            no.RunMethod("requestAlwaysAuthorization", Null)
        End If
        no.SetField("distanceFilter", MinimumDistance)
        no.RunMethod("startMonitoringSignificantLocationChanges",Null)
    End If
End Sub

I have tested it and when the app restarts, the normal location tracking service will start working again. This works because the Significant-Change Location Service foresees this feature.

I have read about other developers using this strategy and that their apps have been approved (after all, the APIs are official) but of course if your app is being examined and the examiner believe you are not using the APIs the way they were meant to be implemented, your app could be rejected.

Hope it helped someone.
 
D

Deleted member 103

Guest
Hi,

I use in my app this code:
B4X:
Private Sub Application_Background
    If GPS1.LocationServicesEnabled Then
        Log("GPS ausschalten")
        GPS1.stop
    End If
End Sub

Now when I use this code
B4X:
Private Sub StartBackground(lm As LocationManager, MinimumDistance As Double)
    Dim no As NativeObject = lm
    no = no.GetField("manager")
    If App.OSVersion >= 8 Then
        no.RunMethod("requestAlwaysAuthorization", Null)
    End If
    no.SetField("distanceFilter", MinimumDistance)
    no.RunMethod("startUpdatingLocation", Null)
End Sub

then I may in the sub "Application_Background" no longer stop the LocationManager (GPS1), right?
 

moster67

Expert
Licensed User
Longtime User
As far as I understand, using the standard location tracking service, your code will work in background and foreground.
If you stop the service (like you do with GPS1.stop in Application_Background sub), you will kill the monitoring service. It will start again when user restarts your app.
If you delete "GPS1.stop" in your Application_Background sub, you app will continue monitoring the location even when the app is in background.
If your user or iOS terminates (kill) the app, the monitoring service will not restart until user restarts app.
 
D

Deleted member 103

Guest
1000 grazie moster67! :)
What happens during my app in background is running and the user launches another app where GPS is needed?
 

schimanski

Well-Known Member
Licensed User
Longtime User
I want to change my app, to track the location in the background and send the data to a server. Where do I have to put the code for this? Do I have to put all the code in the StartBackground-Sub or is it enough to call the existing subs out of the StartBackground-Sub?

I saw, that somebody tried the same before:)
 
Top