iOS 9 how get locations even if app terminated

前端 未结 2 1979
刺人心
刺人心 2020-12-18 11:28

I understand how retrieve locations in background. And I understand that there is a chance to get locations even if terminated Continious location updates even if app is ter

相关标签:
2条回答
  • 2020-12-18 11:58

    i jus followed @Busata's answer and it worked well with iOS 12.

    Here i will post the answer in Swift.

    LocationManager Class:

    class NABackgroundRideLocationTrackingManager: 
    NSObject,CLLocationManagerDelegate {
        var locationManager: CLLocationManager?
        private static var privateShared : 
    NABackgroundRideLocationTrackingManager?
        var traveledDistance: Double = 0
        class func shared() -> NABackgroundRideLocationTrackingManager {
        guard let uwShared = privateShared else {
            privateShared = NABackgroundRideLocationTrackingManager()
            return privateShared!
        }
        return uwShared
    }
    class func destroy() {
        privateShared = nil
    }
    
    func startMonitoringLocation(){
        if locationManager != nil{
            locationManager?.stopMonitoringSignificantLocationChanges()
        }
        locationManager = CLLocationManager()
        locationManager?.delegate = self
        locationManager?.allowsBackgroundLocationUpdates = true
        locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        locationManager?.activityType = CLActivityType.otherNavigation
        locationManager?.requestAlwaysAuthorization()
        locationManager?.startMonitoringSignificantLocationChanges()
    }
    func restartMonitoringLocation(){
        locationManager?.stopMonitoringSignificantLocationChanges()
        locationManager?.requestAlwaysAuthorization()
        locationManager?.startMonitoringSignificantLocationChanges()
    }
    func postLocations(userLocation: CLLocation){
        var params: [String:String] = [:]
        params["latitude"] = String(userLocation.coordinate.latitude)
        params["longitude"] = String(userLocation.coordinate.longitude)
        NAAppManager.postLocationOnBackground(params, success: { (success) in
            print("location Posted")
        }) { (failure) in
            print("Failed")
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
        let location = locations.last
        self.postLocations(userLocation: location!)
    }
    }
    
    
    Appdelegate:
    
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
        if UIApplication.shared.backgroundRefreshStatus == .restricted {
    
        }else if UIApplication.shared.backgroundRefreshStatus == .denied {
    
        }else{
            if ((launchOptions?[UIApplication.LaunchOptionsKey.location]) != nil){
                NABackgroundRideLocationTrackingManager.shared().startMonitoringLocation()
            }
        }
    
    }
    func applicationDidEnterBackground(_ application: UIApplication) {
        NABackgroundRideLocationTrackingManager.shared().restartMonitoringLocation()
    
    }
    func applicationDidBecomeActive(_ application: UIApplication) {
        NABackgroundRideLocationTrackingManager.shared().startMonitoringLocation()
    }
    }
    
    0 讨论(0)
  • 2020-12-18 12:13

    I found a solutions for this. This worked for me in IOS 9. Even restarting the IOS device, keeps running.

    http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended

    The GitHub sample: https://github.com/voyage11/GettingLocationWhenSuspended

    UPDATED

    You must use [myLocationManager startMonitoringSignificantLocationChanges], and not [myLocationManager startUpdatingLocation].

    Below, the my AppDelegate.

    @implementation LocationAppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        NSLog(@"didFinishLaunchingWithOptions");
    
        self.shareModel = [LocationManager sharedManager];
        self.shareModel.afterResume = NO;
    
        [self.shareModel addApplicationStatusToPList:@"didFinishLaunchingWithOptions"];
    
         UIAlertView * alert;
    
        //We have to make sure that the Background App Refresh is enable for the Location updates to work in the background.
        if ([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusDenied) {
    
            alert = [[UIAlertView alloc]initWithTitle:@""
                                              message:@"The app doesn't work without the Background App Refresh enabled. To turn it on, go to Settings > General > Background App Refresh"
                                             delegate:nil
                                    cancelButtonTitle:@"Ok"
                                    otherButtonTitles:nil, nil];
            [alert show];
    
        } else if ([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusRestricted) {
    
            alert = [[UIAlertView alloc]initWithTitle:@""
                                              message:@"The functions of this app are limited because the Background App Refresh is disable."
                                             delegate:nil
                                    cancelButtonTitle:@"Ok"
                                    otherButtonTitles:nil, nil];
            [alert show];
    
        } else {
    
            // When there is a significant changes of the location,
            // The key UIApplicationLaunchOptionsLocationKey will be returned from didFinishLaunchingWithOptions
            // When the app is receiving the key, it must reinitiate the locationManager and get
            // the latest location updates
    
            // This UIApplicationLaunchOptionsLocationKey key enables the location update even when
            // the app has been killed/terminated (Not in th background) by iOS or the user.
    
            NSLog(@"UIApplicationLaunchOptionsLocationKey : %@" , [launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]);
            if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
    
                // This "afterResume" flag is just to show that he receiving location updates
                // are actually from the key "UIApplicationLaunchOptionsLocationKey"
                self.shareModel.afterResume = YES;
    
                [self.shareModel startMonitoringLocation];
                [self.shareModel addResumeLocationToPList];
            }
        }
    
        return YES;
    }
    
    - (void)applicationDidEnterBackground:(UIApplication *)application {
        NSLog(@"applicationDidEnterBackground");
        [self.shareModel restartMonitoringLocation];
    
        [self.shareModel addApplicationStatusToPList:@"applicationDidEnterBackground"];
    }
    
    
    
    - (void)applicationDidBecomeActive:(UIApplication *)application {
        NSLog(@"applicationDidBecomeActive");
    
        [self.shareModel addApplicationStatusToPList:@"applicationDidBecomeActive"];
    
        //Remove the "afterResume" Flag after the app is active again.
        self.shareModel.afterResume = NO;
    
        [self.shareModel startMonitoringLocation];
    }
    
    
    - (void)applicationWillTerminate:(UIApplication *)application {
        NSLog(@"applicationWillTerminate");
        [self.shareModel addApplicationStatusToPList:@"applicationWillTerminate"];
    }
    
    
    @end
    

    My custom LocationManager.

    @implementation LocationManager
    
    //Class method to make sure the share model is synch across the app
    + (id)sharedManager {
        static id sharedMyModel = nil;
        static dispatch_once_t onceToken;
    
        dispatch_once(&onceToken, ^{
            sharedMyModel = [[self alloc] init];
        });
    
        return sharedMyModel;
    }
    
    
    #pragma mark - CLLocationManager
    
    - (void)startMonitoringLocation {
        if (_anotherLocationManager)
            [_anotherLocationManager stopMonitoringSignificantLocationChanges];
    
        self.anotherLocationManager = [[CLLocationManager alloc]init];
        _anotherLocationManager.delegate = self;
        _anotherLocationManager.allowsBackgroundLocationUpdates = true;
        _anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
        _anotherLocationManager.activityType = CLActivityTypeOtherNavigation;
    
        if(IS_OS_8_OR_LATER) {
            [_anotherLocationManager requestAlwaysAuthorization];
        }
        [_anotherLocationManager startMonitoringSignificantLocationChanges];
    }
    
    - (void)restartMonitoringLocation {
        [_anotherLocationManager stopMonitoringSignificantLocationChanges];
    
        if (IS_OS_8_OR_LATER) {
            [_anotherLocationManager requestAlwaysAuthorization];
        }
        [_anotherLocationManager startMonitoringSignificantLocationChanges];
    }
    
    
    #pragma mark - CLLocationManager Delegate
    
    - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    
        NSLog(@"locationManager didUpdateLocations: %@",locations);
    
        for (int i = 0; i < locations.count; i++) {
    
            CLLocation * newLocation = [locations objectAtIndex:i];
            CLLocationCoordinate2D theLocation = newLocation.coordinate;
            CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;
    
            self.myLocation = theLocation;
            self.myLocationAccuracy = theAccuracy;
        }
    
        [self addLocationToPList:_afterResume];
    }
    
    
    
    #pragma mark - Plist helper methods
    
    // Below are 3 functions that add location and Application status to PList
    // The purpose is to collect location information locally
    
    - (NSString *)appState {
        UIApplication* application = [UIApplication sharedApplication];
    
        NSString * appState;
        if([application applicationState]==UIApplicationStateActive)
            appState = @"UIApplicationStateActive";
        if([application applicationState]==UIApplicationStateBackground)
            appState = @"UIApplicationStateBackground";
        if([application applicationState]==UIApplicationStateInactive)
            appState = @"UIApplicationStateInactive";
    
        return appState;
    }
    
    - (void)addResumeLocationToPList {
    
        NSLog(@"addResumeLocationToPList");
    
        NSString * appState = [self appState];
    
        self.myLocationDictInPlist = [[NSMutableDictionary alloc]init];
        [_myLocationDictInPlist setObject:@"UIApplicationLaunchOptionsLocationKey" forKey:@"Resume"];
        [_myLocationDictInPlist setObject:appState forKey:@"AppState"];
        [_myLocationDictInPlist setObject:[NSDate date] forKey:@"Time"];
    
        [self saveLocationsToPlist];
    }
    
    
    
    - (void)addLocationToPList:(BOOL)fromResume {
        NSLog(@"addLocationToPList");
    
        NSString * appState = [self appState];
    
        self.myLocationDictInPlist = [[NSMutableDictionary alloc]init];
        [_myLocationDictInPlist setObject:[NSNumber numberWithDouble:self.myLocation.latitude]  forKey:@"Latitude"];
        [_myLocationDictInPlist setObject:[NSNumber numberWithDouble:self.myLocation.longitude] forKey:@"Longitude"];
        [_myLocationDictInPlist setObject:[NSNumber numberWithDouble:self.myLocationAccuracy] forKey:@"Accuracy"];
    
        [_myLocationDictInPlist setObject:appState forKey:@"AppState"];
    
        if (fromResume) {
            [_myLocationDictInPlist setObject:@"YES" forKey:@"AddFromResume"];
        } else {
            [_myLocationDictInPlist setObject:@"NO" forKey:@"AddFromResume"];
        }
    
        [_myLocationDictInPlist setObject:[NSDate date] forKey:@"Time"];
    
        [self saveLocationsToPlist];
    }
    
    - (void)addApplicationStatusToPList:(NSString*)applicationStatus {
    
        NSLog(@"addApplicationStatusToPList");
    
        NSString * appState = [self appState];
    
        self.myLocationDictInPlist = [[NSMutableDictionary alloc]init];
        [_myLocationDictInPlist setObject:applicationStatus forKey:@"applicationStatus"];
        [_myLocationDictInPlist setObject:appState forKey:@"AppState"];
        [_myLocationDictInPlist setObject:[NSDate date] forKey:@"Time"];
    
        [self saveLocationsToPlist];
    }
    
    - (void)saveLocationsToPlist {
        NSString *plistName = [NSString stringWithFormat:@"LocationArray.plist"];
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *docDir = [paths objectAtIndex:0];
        NSString *fullPath = [NSString stringWithFormat:@"%@/%@", docDir, plistName];
    
        NSMutableDictionary *savedProfile = [[NSMutableDictionary alloc] initWithContentsOfFile:fullPath];
    
        if (!savedProfile) {
            savedProfile = [[NSMutableDictionary alloc] init];
            self.myLocationArrayInPlist = [[NSMutableArray alloc]init];
        } else {
            self.myLocationArrayInPlist = [savedProfile objectForKey:@"LocationArray"];
        }
    
        if(_myLocationDictInPlist) {
            [_myLocationArrayInPlist addObject:_myLocationDictInPlist];
            [savedProfile setObject:_myLocationArrayInPlist forKey:@"LocationArray"];
        }
    
        if (![savedProfile writeToFile:fullPath atomically:FALSE]) {
            NSLog(@"Couldn't save LocationArray.plist" );
        }
    }
    
    
    @end
    

    Do not forget of enable backgound location in plist file.

    And set message to LocationAlwaysUsageDescription.

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