首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当应用程序在2次更新后停止时,获取位置更新

当应用程序在2次更新后停止时,获取位置更新
EN

Stack Overflow用户
提问于 2014-06-18 05:31:18
回答 1查看 1.6K关注 0票数 2

我试图获得位置更新,而我的应用程序是不活跃的(用户关闭应用程序)。在两个位置更新后,位置更新停止启动我的应用程序。指示符是我的应用程序中的位置服务设置中的灰色箭头。

我正在尝试的是startMonitoringSignificantLocationChangesregionMonitoring的结合。

  • 我在iPhone 4 iOS 7.1.1上进行了测试,在两个更新之后位置更新就停止了。
  • 我在iPad mini WiFi+Cellular iOS 7.1.1中进行了测试,在1次更新和区域监视仅发送1个位置之后,位置更新就停止了。

我哪里错了?

我的代码:

附件代表:

代码语言:javascript
运行
复制
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);

    [RegionMonitoringService sharedInstance].launchOptions = launchOptions;
    [[RegionMonitoringService sharedInstance] stopMonitoringAllRegions];

    if ( [CLLocationManager significantLocationChangeMonitoringAvailable] ) {
        [[RegionMonitoringService sharedInstance] startMonitoringSignificantLocationChanges];
    } else {
        NSLog(@"Significant location change service not available.");
    }

    if (launchOptions[UIApplicationLaunchOptionsLocationKey]) {

        [self application:application handleNewLocationEvet:launchOptions]; // Handle new location event

        UIViewController *controller = [[UIViewController alloc] init];
        controller.view.frame = [UIScreen mainScreen].bounds;
        UINavigationController *nvc = [[UINavigationController alloc] initWithRootViewController:controller];

        dispatch_async(dispatch_get_main_queue(), ^{
            appDelegate.window.rootViewController = nvc;
            [appDelegate.window makeKeyAndVisible];
        });

    }
    else {
        // ...
    }

    return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{    
    [defaults synchronize];

    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;

    if ([RegionMonitoringService sharedInstance].launchOptions[UIApplicationLaunchOptionsLocationKey]) {
        return;
    }
}    

- (void)application:(UIApplication *)application handleNewLocationEvet:(NSDictionary *)launchOptions
{
    NSLog(@"%s, launchOptions: %@", __PRETTY_FUNCTION__, launchOptions);

    if (![launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) return;
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) return;

    SendLocalPushNotification(@"handleNewLocationEvet");
}

区域监测服务h:

代码语言:javascript
运行
复制
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import "ServerApiManager.h"

@interface RegionMonitoringService : NSObject

@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSDictionary *launchOptions;
@property (strong, nonatomic) NSDate *oldDate;
@property (strong, nonatomic) CLLocation *oldLocation;

+ (RegionMonitoringService *)sharedInstance;
- (void)startMonitoringForRegion:(CLRegion *)region;
- (void)startMonitoringRegionWithCoordinate:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDirection)radius;
- (void)stopMonitoringAllRegions;
- (void)startMonitoringSignificantLocationChanges;
- (void)stopMonitoringSignificantLocationChanges;
FOUNDATION_EXPORT NSString *NSStringFromCLRegionState(CLRegionState state);

@end

区域监测服务:

代码语言:javascript
运行
复制
#import "RegionMonitoringService.h"

static CLLocationDistance const kFixedRadius = 250.0;

@interface RegionMonitoringService () <CLLocationManagerDelegate>
- (NSString *)identifierForCoordinate:(CLLocationCoordinate2D)coordinate;
- (CLLocationDistance)getFixRadius:(CLLocationDistance)radius;
- (void)sortLastLocation:(CLLocation *)lastLocation;
@end

@implementation RegionMonitoringService

+ (RegionMonitoringService *)sharedInstance
{
    static RegionMonitoringService *_sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

- (instancetype)init
{
    self = [super init];
    if (!self) {
        return nil;
    }

    _locationManager = [[CLLocationManager alloc] init];
    _locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    _locationManager.distanceFilter = kCLDistanceFilterNone;
//    _locationManager.activityType = CLActivityTypeFitness;
    _locationManager.delegate = self;

    return self;
}

- (void)startMonitoringForRegion:(CLRegion *)region
{
    NSLog(@"%s", __PRETTY_FUNCTION__);
    [_locationManager startMonitoringForRegion:region];
}

- (void)startMonitoringRegionWithCoordinate:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDirection)radius
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    if (![CLLocationManager regionMonitoringAvailable]) {
        NSLog(@"Warning: Region monitoring not supported on this device.");
        return;
    }

    if (__iOS_6_And_Heigher) {
        CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:coordinate
                                                                   radius:radius
                                                               identifier:[self identifierForCoordinate:coordinate]];
        [_locationManager startMonitoringForRegion:region];
    }
    else {
        CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:coordinate
                                                                     radius:radius
                                                                 identifier:[self identifierForCoordinate:coordinate]];
        [_locationManager startMonitoringForRegion:region];
    }

    SendLocalPushNotification([NSString stringWithFormat:@"StartMonitor: {%f, %f}", coordinate.latitude, coordinate.longitude]);
}

- (void)stopMonitoringAllRegions
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    if (_locationManager.monitoredRegions.allObjects.count > 1) {
        for (int i=0; i<_locationManager.monitoredRegions.allObjects.count; i++) {
            if (i == 0) {
                NSLog(@"stop monitor region at index %d", i);
                CLRegion *region = (CLRegion *)_locationManager.monitoredRegions.allObjects[i];
                [_locationManager stopMonitoringForRegion:region];
            }
        }
    }
}

- (void)startMonitoringSignificantLocationChanges
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    [_locationManager startMonitoringSignificantLocationChanges];
}

- (void)stopMonitoringSignificantLocationChanges
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

     [_locationManager stopMonitoringSignificantLocationChanges];
}

- (NSString *)identifierForCoordinate:(CLLocationCoordinate2D)coordinate
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    return [NSString stringWithFormat:@"{%f, %f}", coordinate.latitude, coordinate.longitude];
}

FOUNDATION_EXPORT NSString *NSStringFromCLRegionState(CLRegionState state)
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    if (__iOS_6_And_Heigher) {
        return @"Support only iOS 7 and later.";
    }

    if (state == CLRegionStateUnknown) {
        return @"CLRegionStateUnknown";
    } else if (state == CLRegionStateInside) {
        return @"CLRegionStateInside";
    } else if (state == CLRegionStateOutside) {
        return @"CLRegionStateOutside";
    } else {
        return [NSString stringWithFormat:@"Undeterminded CLRegionState"];
    }
}

- (CLLocationDistance)getFixRadius:(CLLocationDistance)radius
{
    if (radius > _locationManager.maximumRegionMonitoringDistance) {
        radius = _locationManager.maximumRegionMonitoringDistance;
    }
    return radius;
}

- (void)sortLastLocation:(CLLocation *)lastLocation
{
    NSLog(@"%s, %@", __PRETTY_FUNCTION__, lastLocation);

    self.oldDate = lastLocation.timestamp; // Get new date

    NSTimeInterval seconds = fabs([self.oldLocation.timestamp timeIntervalSinceDate:self.oldDate]); // Calculate how seconds passed
    NSInteger minutes = seconds * 60; // Calculate how minutes passed

    if (lastLocation && self.oldLocation) { // New & old location are good
        if ([lastLocation distanceFromLocation:self.oldLocation] >= 200 || minutes >= 30) { // Distance > 200 or 30 minutes passed
            [[ServerApiManager sharedInstance] saveLocation:lastLocation]; // Send location to server
        }
    }
    else { // We just starting location updates
        [[ServerApiManager sharedInstance] saveLocation:lastLocation]; // Send new location to server
    }
    self.oldLocation = lastLocation; // Set old location
}

#pragma mark - CLLocationManagerDelegate Methods

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    NSLog(@"%s, %@", __PRETTY_FUNCTION__, locations);
    CLLocation *lastLocation = (CLLocation *)locations.lastObject;
    CLLocationCoordinate2D coordinate = lastLocation.coordinate;

    if (lastLocation == nil || coordinate.latitude  == 0.0 || coordinate.longitude == 0.0) {
        return;
    }

    [self startMonitoringRegionWithCoordinate:coordinate andRadius:[self getFixRadius:kFixedRadius]];

    [self sortLastLocation:lastLocation];
}

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    NSLog(@"%s, currentLocation: %@, regionState: %@, region: %@",
          __PRETTY_FUNCTION__, manager.location, NSStringFromCLRegionState(state), region);
}

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
    NSLog(@"%s, REGION: %@", __PRETTY_FUNCTION__, region);
    [manager requestStateForRegion:region];
}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
}

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    NSLog(@"%s, REGION: %@", __PRETTY_FUNCTION__, region);

    [self stopMonitoringAllRegions];
    [self startMonitoringRegionWithCoordinate:manager.location.coordinate andRadius:[self getFixRadius:kFixedRadius]];

    CLLocation *lastLocation = manager.location;
    CLLocationCoordinate2D coordinate = lastLocation.coordinate;
    if (lastLocation == nil || coordinate.latitude  == 0.0 || coordinate.longitude == 0.0) {
        return;
    }

    [self sortLastLocation:manager.location];
}

@end

编辑1:

经过几次测试之后,我在几个设备(iPhone 5s、iPad mini、iPhone 4)的汽车上做了很多实时测试,我得出了以下结论:

  1. 在一种情况下,iPad mini & iPhone 4在应用程序没有运行并且小箭头变成灰色时,在几分钟后停止更新位置。
  2. 当WiFi关闭时,准确性很差,位置很少更新。

编辑2:

好吧,经过了大量的驾驶和走动,并测试了它的工作方式,就像一个魅力到目前为止。我成功地将significantLocationChanges和区域监视结合起来,始终在当前位置附近注册地理信息,并在新的UIApplicationLaunchOptionsLocationKey出现时总是启动重要的位置更改。请注意,关闭wifi使准确性非常低,甚至有时不起作用。

我的代码里有错误吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-18 07:03:16

从苹果的文档可以看出,更新发送的频率并不比每一个5分钟500米的位置变化更频繁:

Apps can expect a notification as soon as the device moves 500 meters or more from its previous notification. It should not expect notifications more frequently than once every five minutes. If the device is able to retrieve data from the network, the location manager is much more likely to deliver notifications in a timely manner.

即使应用程序是不活动的,你也会收到更新。另一个提示可能是,oyu可以使用真正的设备来测试模拟器中的位置,这样您就不必外出进行测试,并且仍然可以检查日志。在模拟器菜单中,选择Debug -> Location。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24277690

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档