Capture location in all states app

后端 未结 1 622
萌比男神i
萌比男神i 2020-12-09 23:29

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 duplica

相关标签:
1条回答
  • 2020-12-10 00:25

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

    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

    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.

    Hope could make you understand

    0 讨论(0)
提交回复
热议问题