Capture location in all states app
Asked Answered
C

1

5

I wonder how to capture the location when the app is not running and save the database. Already followed several tutorials but none worked. Please, before scoring as duplicate, I ask you to read the complete question as it can not be.

I tried the following tutorials:

Assuming that I have no implementation for the capture location. I need every day at noon, capture the user's location and save the database then send to a web service. This capture location must be made regardless of whether the app is active in the background or not running (two rings on the middle button and dragging).

I tried some tutorials found on the internet and even some suggested here by the community, but still rather not worked.

  • I have added background modes - Location.
  • I allowed to get location requestAlwaysAuthorization.

The language can be in objective-c or swift, Most importantly, I learn how to capture this location when app in all states.

Cliquish answered 4/9, 2015 at 8:11 Comment(4)
To see what you've got so far and how you put all together your researches, please also show your code.Raffaello
Well first off when the app is not running there is no way to get the location. You will need background mode to get the location when the app is not in the foreground mode.Nettienetting
Done making the final edit This is the complete code i answered and worked for me ios7 and ios8 o retrieve location details when app is terminated/ background and activeTorey
Changes for iOS 13 developer.apple.com/videos/play/wwdc2019/705Camorra
T
6

OK i am going to make this as simple as possible..Enable Background Modes and tick background fetch like thisenter image description here

Follow this methods for every step

When app is TERMINATED

AppDelegate.h

 #import <UIKit/UIKit.h>
 #import <CoreLocation/CoreLocation.h>

 @interface AppDelegate : UIResponder  <UIApplicationDelegate,CLLocationManagerDelegate>

  @property (strong, nonatomic) UIWindow *window;
  @property (strong,nonatomic) CLLocationManager *locationManager;

  @end

AppDelegate.m

#define userDef [NSUserDefaults standardUserDefaults]
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)


#import "AppDelegate.h"
#import <CoreLocation/CoreLocation.h>
#import "AFNetworking.h"
#import <GoogleMaps/GoogleMaps.h>


@implementation AppDelegate{
    BOOL fromTerminated;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
   fromTerminated = NO;
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
    fromTerminated = YES;
    self.locationManager = [[CLLocationManager alloc]init];
    self.locationManager.delegate = self;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    self.locationManager.activityType = CLActivityTypeOtherNavigation;
    [self.locationManager startUpdatingLocation];
}

    return YES;
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
if(self.locationManager){
    [self.locationManager stopMonitoringSignificantLocationChanges];
    self.locationManager = nil;
    self.locationManager.delegate = nil;

}

self.locationManager = [[CLLocationManager alloc]init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.locationManager.activityType = CLActivityTypeOtherNavigation;

if(IS_OS_8_OR_LATER) {
    [self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startMonitoringSignificantLocationChanges];
}

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{

NSLog(@"locationManager didUpdateLocations: %@",locations);


if(fromTerminated){

    CLLocation * newLocation = [locations lastObject];
    CLLocationCoordinate2D theLocation = newLocation.coordinate;
    CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;

    [userDef setObject:[NSString stringWithFormat:@"%f",theLocation.longitude] forKey:@"LONGITUDE"];
    [userDef setObject:[NSString stringWithFormat:@"%f",theLocation.latitude] forKey:@"LATITUDE"];
    self.myLocation = theLocation;
    self.myLocationAccuracy = theAccuracy;
    [self updateLocation];
   }
}


-(void)updateLocation{
// call your webservice for updating
}

@end

This code will do the following--> Background fetch will trigger a location change and will launch the application and didFInishLaunchingWithOptions will be called with a UIApplicationLaunchOptionsLocationKey in the option dictionary. If it finds this that means the application is TERMINATED and woke up for background fetch. Now you got 30 seconds or so to do your stuff. So you create a location manager object and start updating, which will trigger your didUpdateLocations delegate method and then you can call your method to trigger that changed location in your server or database.

In your normal VC create another Location Manager object just like you created in the didFinishiLaunchingWithOptions method and implement the delegate method didUpdateLocation this will run untill the application is in foreground or background. The app delegate method hack will trigger the application when its terminated.

Cheers :)

[EDIT]

When app is in foreground or Background

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface ViewController ()<CLLocationManagerDelegate>
@property (nonatomic,strong) CLLocationManager *locationManager;

@end

@implementation ViewController{
}


 -(void)viewDidAppear:(BOOL)animated{
   if(self.locationManager == nil){
    _locationManager = [CLLocationManager new];
   }
    _locationManager.delegate = self;
    _locationManager.distanceFilter = kCLDistanceFilterNone;
    _locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;

    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0 &&     [CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
    [_locationManager requestAlwaysAuthorization];
    } else {
        [_locationManager startUpdatingLocation];
     }
  }


 - (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {

    _locationManager = nil;
    CLLocation *location = [locations lastObject];
    theUser.latitude = [NSString stringWithFormat:@"%f",location.coordinate.latitude];
    theUser.longitude = [NSString stringWithFormat:@"%f",location.coordinate.longitude];

   }
}


- (void)locationManager:(CLLocationManager*)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
  {
switch (status) {
    case kCLAuthorizationStatusNotDetermined: {
    } break;
    case kCLAuthorizationStatusDenied: {
    } break;
    case kCLAuthorizationStatusAuthorizedWhenInUse:
    case kCLAuthorizationStatusAuthorizedAlways: {
        [_locationManager startUpdatingLocation]; //Will update location immediately
    } break;
    default:
        break;
   }
}


@end

[EDIT]

TO check that app is getting launched after terminated state do this change and hit the run button and change the location of the device from the storyboard enter image description here

Do this change, and Run the project (Do this in debug mode of a device) and change location by this and then stick a breakpoint in applicationDidFinishLaunchingWithOptions and you will see the breakpoint is hit, meaning the app was in terminated state but this location change has triggered the OS to launch the application. enter image description here

Hope could make you understand

Torey answered 4/9, 2015 at 8:27 Comment(6)
Editing to post the Full state answerTorey
Thank you, I understand perfectly, I will do the code to see if it will work. A single doubt: In brackground Modes, only "Background Fetch" or "Background fetch" and "Updates Location"Cliquish
Apply both the process i mentioned to get location update for all states.Torey
the app not become "active" again, the location never was updated after app was terminatedCliquish
Location will become updated when terminated the app wont be active but that chunk of code will get activated by the OS, do the test by walking a bit and then checking your backend , i checked this myself and by testing in simulator, Change the scheme of the app am editing the answer as to how to check that even when app is terminatedTorey
Breakpoint wont get hit as your app will be in a suspended state. Try adding a writing mechanism, where new location gets written to a plist or core data storage and see the resultaTorey

© 2022 - 2024 — McMap. All rights reserved.