IOS无限期背景时间

时间:2014-02-07 23:43:06

标签: ios iphone ios7 background core-location

我有一个将数据发布到服务器的应用。仅当用户距离某个位置一定距离时才会发布此数据。我对背景位置更新进行了调整,希望能够让我保持背景。但是大约17-18分钟后,后台停止执行。

我认为可能是因为locationManager.pauseslocationupdates自动。但即使我将其设置为false,该应用程序仍然会在大约17分钟后终止。这是我的应用代表的代码。

//
//  BAAppDelegate.m
//  Beacon App
//
//  Created by Huy Ly on 2/10/13.
//  Copyright (c) 2013 Placesign. All rights reserved.
//

#import "BAAppDelegate.h"

@implementation BAAppDelegate
@synthesize backgroundAnnouncementRevision, backgroundAnnouncementText, backgroundOfferDescription, backgroundOfferName, backgroundOfferPrice, backgroundOfferRevision, isAnnouncing, isOffering, locationManager, targetLocation, currentLocation, beaconTimer;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    NSLog(@"Application will resign active");
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    NSLog(@"Application entered background");
    // 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.
    locationManager.distanceFilter = kCLDistanceFilterNone;
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    [locationManager setPausesLocationUpdatesAutomatically:YES];
    [locationManager startUpdatingLocation];
    NSLog(@"Starting timer for posting in background");
    /*
    //Runs the Timer on a background task main thread
    UIApplication *app = [UIApplication sharedApplication];


    //create new uiBackgroundTask
    __block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];*/

    //and create new timer with async call:
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //run function methodRunAfterBackground
        beaconTimer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(sendBeacon) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:beaconTimer forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];
    });

}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    NSLog(@"Application entered foreground");

    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    [beaconTimer invalidate];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSLog(@"Application became active");

    // 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.
    [beaconTimer invalidate];
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    NSLog(@"Application will terminate");
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    [beaconTimer invalidate];
}


-(void) sendBeacon{
    NSLog(@"Beacon Background Send Started");

    NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
    if ([[NSUserDefaults standardUserDefaults]valueForKey:@"PlaceID"]== nil) {
        isAnnouncing = FALSE;
        isOffering   = FALSE;
    }

    //Do a single distance check to see if user is still within bounds
    //Get the current location
    [locationManager startUpdatingLocation];

    //Compare current location with target location
    CLLocationDistance distance = [currentLocation distanceFromLocation:targetLocation];
    distance=distance/1000;

    //If user is within location boundary, posts to server
    if (distance < 0.1 || true) {
        NSLog(@"Background Sent");
        //Set Up the NSURL
        NSString *urlString = [standardUserDefaults valueForKey:@"statusUpdate"];
        NSURL *url          = [NSURL URLWithString:urlString];
        NSString *jsonString = [[NSString alloc] initWithFormat:@"{\"Announcement\":{\"Text\":\"%@\",\"ElementContext\":{\"Revision\":%@,\"Source\":{\"ID\":0,\"Type\":0}}},\"Offer\":{\"Description\":\"%@\",\"ElementContext\":{\"Revision\":%@,\"Source\":{\"ID\":0,\"Type\":0}},\"Name\":\"%@\",\"Price\":%@},\"OpStatus\":{\"ElementContext\":{\"Revision\":0,\"Source\":{\"ID\":0,\"Type\":0}},\"Value\":0},\"PlaceID\":%@,\"ResourcesOnPremise\":[{\"ElementContext\":{\"Revision\":0,\"Source\":{\"ID\":%@,\"Type\":1}},\"OnPremiseStatus\":2,\"Resource\":{\"ID\":%@,\"Type\":1}}],\"SignalSources\":[{\"LastSignal\":0,\"Source\":{\"ID\":0,\"Type\":0}}]}", backgroundAnnouncementText, backgroundAnnouncementRevision, backgroundOfferDescription, backgroundOfferRevision, backgroundOfferName, backgroundOfferPrice, [[NSUserDefaults standardUserDefaults]valueForKey:@"PlaceID"], [[NSUserDefaults standardUserDefaults]valueForKey:@"UserID"], [[NSUserDefaults standardUserDefaults]valueForKey:@"UserID"]];
        NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];

        //setup the request
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
        [request setHTTPMethod:@"POST"];
        [request setValue:[NSString stringWithFormat:@"%d", [jsonString length]] forHTTPHeaderField:@"Content-Length"];
        [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
        [request setHTTPBody:jsonData];
        NSURLConnection *requestConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

        [requestConnection start];

    }
    else{
    }
}

-(void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    NSLog(@"Location Manager failed with error %@", error);
}

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    currentLocation = [locations lastObject];
    NSLog(@"Manager did update location");
}

-(void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager{
    NSLog(@"Location Manager Paused");
}

-(void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager{
    NSLog(@"Location Manager Resumed");
}

@end

1 个答案:

答案 0 :(得分:2)

你不应该期望无限期地运行。如果您是位置应用程序,那么您应该在设备移动时调用。但是如果设备没有移动,那么操作系统没有理由给你打电话,而且它不会。

您需要设计自己的应用,以便使用最少的电池来实现用户所需的行为。为此,如果您有一个您关心的边界,则应设置一个位置区域,并且只要设备移入或移出该区域,您就会被唤醒。这比不断观看GPS便宜得多。

如果用户希望您记录每个小动作,那么您可以设置位置管理器(使用kCLLocationAccuracyBest),但您仍然只会在设备移动时被调用。由于这会导致最大的电池消耗,请确保它是实现用户目标的唯一方法。

根据设计,无法请求“无限期背景时间”​​。