• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

ios - 应用程序处于非事件状态时获取位置更新在 2 次更新后停止

[复制链接]
菜鸟教程小白 发表于 2022-12-12 23:04:34 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

我正在尝试在我的应用处于非事件状态时获取位置更新(用户关闭了应用)。 2 次位置更新后,位置更新停止启动我的应用程序。 这方面的指标是我的应用中位置服务设置中的灰色箭头。

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

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

我哪里错了?

我的代码:

AppDelegate.m:

- (BOOL)applicationUIApplication *)application didFinishLaunchingWithOptionsNSDictionary *)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)applicationDidEnterBackgroundUIApplication *)application
{    
    [defaults synchronize];

    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;

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

- (void)applicationUIApplication *)application handleNewLocationEvetNSDictionary *)launchOptions
{
    NSLog(@"%s, launchOptions: %@", __PRETTY_FUNCTION__, launchOptions);

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

    SendLocalPushNotification(@"handleNewLocationEvet");
}

RegionMonitoringService.h:

#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)startMonitoringForRegionCLRegion *)region;
- (void)startMonitoringRegionWithCoordinateCLLocationCoordinate2D)coordinate andRadiusCLLocationDirection)radius;
- (void)stopMonitoringAllRegions;
- (void)startMonitoringSignificantLocationChanges;
- (void)stopMonitoringSignificantLocationChanges;
FOUNDATION_EXPORT NSString *NSStringFromCLRegionState(CLRegionState state);

@end

RegionMonitoringService.m:

#import "RegionMonitoringService.h"

static CLLocationDistance const kFixedRadius = 250.0;

@interface RegionMonitoringService () <CLLocationManagerDelegate>
- (NSString *)identifierForCoordinateCLLocationCoordinate2D)coordinate;
- (CLLocationDistance)getFixRadiusCLLocationDistance)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

enter image description here

enter image description here

编辑 1:

经过几次测试后,我用多种设备(iPhone 5s、iPad mini、iPhone 4)对汽车进行了很多实时测试,结果如下:

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

编辑 2:

好的,经过大量的驾驶和四处走动并对其进行测试,到目前为止,它的工作原理就像一个魅力。 我设法使它工作,结合 significantLocationChanges 和区域监控,总是在我当前位置周围注册一个地理围栏,并总是在新的 UIApplicationLaunchOptionsLocationKey 到来时开始重大的位置更改。 请注意,关闭 wifi 会使准确性非常低,甚至有时无法正常工作。

我的代码中有错误吗?



Best Answer-推荐答案


来自苹果 docs可以看出,更新的发送频率并不高于每 5 分钟500 米 的位置变化:

只要设备从之前的通知移动 500 米或更远,应用程序就会收到通知。它不应期望通知的频率超过每五分钟一次。如果设备能够从网络中检索数据,则位置管理器更有可能及时发送通知。

即使应用处于非事件状态,您也会收到更新。对您的另一个提示可能是 oyu 可以在模拟器中测试位置,而不是使用真实设备,这样您就不必到外面进行测试并且仍然可以检查您的日志。在模拟器菜单中,选择Debug --> Location

关于ios - 应用程序处于非事件状态时获取位置更新在 2 次更新后停止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24277690/

回复

使用道具 举报

懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝2

帖子830918

发布主题
阅读排行 更多
广告位

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap