当应用程序处于后台并且网络连接丢失时,位置更新计时器不起作用?

Posted

技术标签:

【中文标题】当应用程序处于后台并且网络连接丢失时,位置更新计时器不起作用?【英文标题】:when app is in background and network connection lost then location update timer not work? 【发布时间】:2015-08-27 09:29:46 【问题描述】:

要求:我想每 2 分钟后向服务器发送位置详细信息。为此,我使用了 2 分钟的计时器将位置发送到服务器。 我正在从位置管理器获取当前位置并将坐标发送到服务器。

下面是获取后台位置和处理后台应用刷新的代码

//Background location update
    self.shareModel = [LocationShareModel sharedModel];
    self.shareModel.afterResume = NO;
    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 change 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.

        if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) 
            DebugLog(@"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.anotherLocationManager = [[CLLocationManager alloc]init];
            self.shareModel.anotherLocationManager.delegate = self;
            self.shareModel.anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
            self.shareModel.anotherLocationManager.activityType = CLActivityTypeOtherNavigation;

            if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) 
                [self.shareModel.anotherLocationManager requestAlwaysAuthorization];
            

            [self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];
        
    



-(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.myLoc = newLocation;
    

//    self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
//    [self.shareModel.bgTask beginNewBackgroundTask];



-(CLLocation *)getCurrentLocation

    if(locationManager.location)
    
        return locationManager.location;
    
    else if(currentLoaction)
    
        return currentLoaction;
    
//    return locationManager.location;
    return self.myLoc;




- (void)applicationDidEnterBackground:(UIApplication *)application

    firstDate=[NSDate date];
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    [ud setValue:firstDate forKey:@"FirstDate"];
    [ud synchronize];

    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

    DebugLog(@"applicationDidEnterBackground");
    [self.shareModel.anotherLocationManager stopMonitoringSignificantLocationChanges];

    if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) 
        [self.shareModel.anotherLocationManager requestAlwaysAuthorization];
    
    [self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];





- (void)applicationDidBecomeActive:(UIApplication *)application


    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    [[UIApplication sharedApplication] ignoreSnapshotOnNextApplicationLaunch];

     DebugLog(@"applicationDidBecomeActive");

    //Remove the "afterResume" Flag after the app is active again.
    self.shareModel.afterResume = NO;

    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([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) 
        [self.shareModel.anotherLocationManager requestAlwaysAuthorization];
    
    [self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];


这里是将位置发送到服务器的代码

#pragma pingDriver Location webservice call
-(void)pingdriverLocation

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    CLLocation *currentLocation = [appDelegate getCurrentLocation];

    if (appDelegate.internetStatus==0)
    

        NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
        NSMutableArray *driverLocationUpdatesInfo;
        if([userDefaults valueForKey:@"driverLocationInfo"])
            driverLocationUpdatesInfo = [[NSMutableArray alloc]initWithArray:[CommonUtility fetchArrayFrompListWithKey:@"driverLocationInfo" keyToStoreArrayInDict:@"LocationData"]];
        else
            driverLocationUpdatesInfo = [[NSMutableArray alloc]init];
        
        if(currentLocation)
            [driverLocationUpdatesInfo addObject:currentLocation];
        
        [CommonUtility storeArrayInpListWithKey:@"driverLocationInfo" keyToStoreArrayInDict:@"LocationData" array:driverLocationUpdatesInfo];
    
    else
    
        offlineDriverLocationDataUpload = NO;
        objDriverPing = [[pingDriverLocationwebService alloc]init];
        objDriverPing.delegate = self;
        [objDriverPing pingDriverLocationWebService:self latitude:[NSString stringWithFormat:@"%f",currentLocation.coordinate.latitude] longitude:[NSString stringWithFormat:@"%f",currentLocation.coordinate.longitude]];
    



#pragma mark - ping driver location web service response

-(void)serverResponseForPingDriverLocationWebSerivce:(BOOL)proceed responseDict:(NSDictionary *)responseDict

    DebugLog(@"%@",responseDict);
    if(proceed)
    
        if(offlineDriverLocationDataUpload)
        
            NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
            if([userDefaults valueForKey:@"driverLocationInfo"])
            

                NSMutableArray *driverLocationUpdatesInfo = [[NSMutableArray alloc]initWithArray:[CommonUtility fetchArrayFrompListWithKey:@"driverLocationInfo" keyToStoreArrayInDict:@"LocationData"]];

                NSArray *tempArray = [[NSArray alloc]initWithArray:driverLocationUpdatesInfo];

                //to remove object of currentOfflineLocation
                for(CLLocation *location in tempArray)
                
                    if(location.coordinate.latitude == currentOfflineLocation.coordinate.latitude && location.coordinate.longitude == currentOfflineLocation.coordinate.longitude)
                    
                        [driverLocationUpdatesInfo removeObject:location];
                        break;
                    
                

                currentOfflineLocation = nil;
                [CommonUtility storeArrayInpListWithKey:@"driverLocationInfo" keyToStoreArrayInDict:@"LocationData" array:driverLocationUpdatesInfo];

                if(driverLocationUpdatesInfo.count > 0)
                
                    [self uploadOfflineDriverLocationData];
                
                else
                
                    [userDefaults removeObjectForKey:@"driverLocationInfo"];
                    [userDefaults synchronize];
                    [self pingdriverLocation];
                
            
        
        else
        
            if([[responseDict valueForKey:@"Next"] integerValue] > 0)
            

                if([[responseDict valueForKey:@"Notification"] isEqualToString:@"Y"])
                
                    [[[UIAlertView alloc]initWithTitle:@"Alert" message:[responseDict valueForKey:@"Message"] delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil] show];
                


                if (self.locationUpdateTimer) 
                    [self.locationUpdateTimer invalidate];
                

                if([[responseDict valueForKey:@"Next"] integerValue] != 0)
                
                    self.locationUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:2 * 60 target:self selector:@selector(updateLocation) userInfo:nil repeats:YES];
                
            
        
    

目前,当应用程序处于前台状态时,它能够每两分钟将位置发送到服务器。当没有互联网连接时,我会存储位置坐标并在我再次连接后将它们上传到服务器。

问题:考虑到我启动了 ping 服务,30 分钟后我的应用程序进入后台状态,并且在该状态下连接丢失,它将位置存储在 plist 中,当我进入前台时,它会将所有数据上传到服务器,但是之后它不会再次开始发送位置。

请帮助我,因为我现在没有解决方案。

我也学过这个教程

location in ios 7 and ios 8

【问题讨论】:

【参考方案1】:

我猜你需要再次触发 applicationDidBecomeActive 中的计时器: 因为你的计时器没有恢复。顺便说一句,记得先让你的计时器失效:

[self.locationUpdateTimer invalidate];
self.locationUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:2 * 60 target:self selector:@selector(updateLocation) userInfo:nil repeats:YES];

【讨论】:

我总是在创建第二个计时器之前使计时器无效。 您是否尝试将这两行添加到 applicationDidBecomeActive 方法?结果如何? 感谢 Artur,我对此做了很多测试,所有结果都是正确的。非常感谢。

以上是关于当应用程序处于后台并且网络连接丢失时,位置更新计时器不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序处于后台时,带有 PendingIntent 的 Android FusedLocationClient 未收到位置更新

当位置发生变化并且我的应用程序处于后台时,我可以获得本地通知吗?

当应用程序处于后台/挂起状态时,CLLocation 不断更新

当应用程序处于后台时,在反应本机后台计时器 setInterval 中调用 await

当 UpdatePanel 在计时器上更新自身时,css 样式会丢失

应用程序在后台时的 NSURLConnection