I want to implement a background service which sends geolocations to a server. Therefore I used the plugin cordova-plugin-background-mode from https://github.com/katzer/cordova-plugin-background-mode, which works with android.
But if I run the app on iOS 8.3 and push the home button the app stops sending the geolocations to the server. In the documentation of the plugin it says:
Supported Platforms
- iOS (including iOS8)
- Android (SDK >=11)
- WP8
Am I missing something?
Edit: Here is some code from my controller
$ionicPlatform.ready(function() {
var watchOptions = {
frequency : 1000,
timeout : 5*60*1000,
enableHighAccuracy: true
};
var watch = $cordovaGeolocation.watchPosition(watchOptions);
watch.then(
null,
function(err) {
alert("WatchPosition failed: "+JSON.stringify(err));
},
function(position) {
$scope.position = position;
});
});
While i was exploring the same stuff, there's essentially no pure Hybrid way to achieve background location tracking. But, if you're interested, you can implement the same using native iOS implementation.
Before you go ahead with Apple Background location tracking, you must get a few details upon the possible approaches.
An apple app can track location in two way, and they are as follows :
StartUpdatingLocations is a location tracking initiation method that will cause the callback for location change being invoked every second until and unless you’re app is in foreground/background.
The callback will be called every second regardless of the fact whether the location has changed or not, it is up to the method to handle and decide the location change, and that in fact it is a location change.
StartUpdatingLocations will have no effect when the app is in suspended/terminated. This essentially means that even if StartUpdatingLocations has been called when the app started, as soon as the app moves in background, the callback will no longer be invoked, even if there’s any location change.
StartUpdatingLocations provides most accurate location updates.
- startMonitoringSignificantLocationChanges
StartMonitoringSignificantLocationChanges is a location tracking initiation method that will cause the callback for location change being invoked whenever there’s a SIGNIFICANT CHANGE IN THE USER LOCATION.
This method pro-actively uses Cellular tower location changes, and as documented provides location updates every 500-1000 meters.
StartMonitoringSignificantLocationChanges can continue updating locations even when the app is in background/terminated/suspended.
Location updates from this method ain’t very reliable and personal usage indicates that the location updates are a bit haphazard and are heavily dependent on cellular location updates.
Now what you're trying to do is quite easy in Android, but it ain't in iOS.
I would not reinvent the cycle, but you can explore the complete details here
The method to get the location in the background continuously for iOS 7 and 8 is using the method “startUpdatingLocation”
[myLocationManager startUpdatingLocation];
and then the next trick would be on the delegate method “didUpdateLocations“. You will have to use a timer and handle the Background Task appropriately. Any missing steps and the location will not be updated continuously.
But in the case of getting the location when the app is terminated/suspended, You can not use [myLocationManager startUpdatingLocation]; The only way to make it work is to use:-
[anotherLocationManager startMonitoringSignificantLocationChanges];
Another important trick is, you will have to know how to handle the key “UIApplicationLaunchOptionsLocationKey” on the app delegate “didFinishLaunchingWithOptions“. Here is the sample code:-
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.shareModel = [LocationShareModel sharedModel];
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
self.shareModel.anotherLocationManager = [[CLLocationManager alloc]init];
self.shareModel.anotherLocationManager.delegate = self;
self.shareModel.anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.shareModel.anotherLocationManager.activityType = CLActivityTypeOtherNavigation;
if(IS_OS_8_OR_LATER) {
[self.shareModel.anotherLocationManager requestAlwaysAuthorization];
}
[self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];
}
return YES;
}
In addition to the didFinishLaunchingWithOptions method, You have to create a locationManager Instance when the app is active. Here are some code examples:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.shareModel.anotherLocationManager stopMonitoringSignificantLocationChanges];
if(IS_OS_8_OR_LATER) {
[self.shareModel.anotherLocationManager requestAlwaysAuthorization];
}
[self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(self.shareModel.anotherLocationManager)
[self.shareModel.anotherLocationManager stopMonitoringSignificantLocationChanges];
self.shareModel.anotherLocationManager = [[CLLocationManager alloc]init];
self.shareModel.anotherLocationManager.delegate = self;
self.shareModel.anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.shareModel.anotherLocationManager.activityType = CLActivityTypeOtherNavigation;
if(IS_OS_8_OR_LATER) {
[self.shareModel.anotherLocationManager requestAlwaysAuthorization];
}
[self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];
}
I found out that I have to add the background mode in the projectname-Info.plist under resources in xcode like here:
Now it sending the geolocation even if the app is in background or the device is locked.