【问题标题】:IOS Indefinite Background TimeIOS无限后台时间
【发布时间】:2014-03-05 13:47:15
【问题描述】:

我有一个将数据发布到服务器的应用程序。仅当用户在某个位置的一定距离内时才会发布此数据。我注册了后台位置更新,希望这能让我保持后台运行。但大约 17-18 分钟后,后台停止执行。

我认为这可能是因为 locationManager.pauseslocationupdatesautomatically。但即使我将其设置为 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

【问题讨论】:

    标签: ios iphone ios7 background core-location


    【解决方案1】:

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

    您需要设计您的应用,使其使用最少的电池来实现用户期望的行为。为此,如果您有一个您关心的边界,您应该设置一个位置区域,并且每当设备移入或移出该区域时您都会被唤醒。这比经常看 GPS 便宜得多。

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

    按照设计,无法请求“无限背景时间”​​。

    【讨论】:

    • 您的意思是在locationManagerDidPauseLocationUpdates 回调中执行locationManager.startMonitoringForRegion(region) 吗? 或者你的意思是做类似UNLocationNotificationTrigger(region: region, repeats: false)??你不再被允许做任何与地点有关的事情吗?我猜你是说你被允许然后最终使用UIApplicationLaunchOptionsLocationKey 赶上发射,就像here 提供的答案一样。对吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多