菜鸟教程小白 发表于 2022-12-12 23:04:34

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


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

<p>我正在尝试的是 <code>startMonitoringSignificantLocationChanges</code> 和 <code>regionMonitoring</code> 的组合。</p>

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

<p>我哪里错了?</p>

<p>我的代码:</p>

<p>AppDelegate.m:</p>

<pre><code>- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSSetUncaughtExceptionHandler(&amp;uncaughtExceptionHandler);

    .launchOptions = launchOptions;
    [ stopMonitoringAllRegions];

    if ( ) {
      [ startMonitoringSignificantLocationChanges];
    } else {
      NSLog(@&#34;Significant location change service not available.&#34;);
    }

    if (launchOptions) {

      ; // Handle new location event

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

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

    }
    else {
      // ...
    }

    return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{   
    ;

    .applicationIconBadgeNumber = 0;

    if (.launchOptions) {
      return;
    }
}   

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

    if (!) return;
    if (.applicationState == UIApplicationStateActive) return;

    SendLocalPushNotification(@&#34;handleNewLocationEvet&#34;);
}
</code></pre>

<p>RegionMonitoringService.h:</p>

<pre><code>#import &lt;Foundation/Foundation.h&gt;
#import &lt;CoreLocation/CoreLocation.h&gt;
#import &#34;ServerApiManager.h&#34;

@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
</code></pre>

<p>RegionMonitoringService.m:</p>

<pre><code>#import &#34;RegionMonitoringService.h&#34;

static CLLocationDistance const kFixedRadius = 250.0;

@interface RegionMonitoringService () &lt;CLLocationManagerDelegate&gt;
- (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(&amp;onceToken, ^{
      _sharedInstance = [ init];
    });
    return _sharedInstance;
}

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

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

    return self;
}

- (void)startMonitoringForRegion:(CLRegion *)region
{
    NSLog(@&#34;%s&#34;, __PRETTY_FUNCTION__);
    ;
}

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

    if (!) {
      NSLog(@&#34;Warning: Region monitoring not supported on this device.&#34;);
      return;
    }

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

    SendLocalPushNotification();
}

- (void)stopMonitoringAllRegions
{
    NSLog(@&#34;%s&#34;, __PRETTY_FUNCTION__);

    if (_locationManager.monitoredRegions.allObjects.count &gt; 1) {
      for (int i=0; i&lt;_locationManager.monitoredRegions.allObjects.count; i++) {
            if (i == 0) {
                NSLog(@&#34;stop monitor region at index %d&#34;, i);
                CLRegion *region = (CLRegion *)_locationManager.monitoredRegions.allObjects;
                ;
            }
      }
    }
}

- (void)startMonitoringSignificantLocationChanges
{
    NSLog(@&#34;%s&#34;, __PRETTY_FUNCTION__);

    ;
}

- (void)stopMonitoringSignificantLocationChanges
{
    NSLog(@&#34;%s&#34;, __PRETTY_FUNCTION__);

   ;
}

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

    return ;
}

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

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

    if (state == CLRegionStateUnknown) {
      return @&#34;CLRegionStateUnknown&#34;;
    } else if (state == CLRegionStateInside) {
      return @&#34;CLRegionStateInside&#34;;
    } else if (state == CLRegionStateOutside) {
      return @&#34;CLRegionStateOutside&#34;;
    } else {
      return ;
    }
}

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

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

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

    NSTimeInterval seconds = fabs(); // Calculate how seconds passed
    NSInteger minutes = seconds * 60; // Calculate how minutes passed

    if (lastLocation &amp;&amp; self.oldLocation) { // New &amp; old location are good
      if ( &gt;= 200 || minutes &gt;= 30) { // Distance &gt; 200 or 30 minutes passed
            [ saveLocation:lastLocation]; // Send location to server
      }
    }
    else { // We just starting location updates
      [ 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(@&#34;%s, %@&#34;, __PRETTY_FUNCTION__, locations);
    CLLocation *lastLocation = (CLLocation *)locations.lastObject;
    CLLocationCoordinate2D coordinate = lastLocation.coordinate;

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

    ];

    ;
}

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

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
    NSLog(@&#34;%s, REGION: %@&#34;, __PRETTY_FUNCTION__, region);
    ;
}

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

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

    ;
    ];

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

    ;
}

@end
</code></pre>

<p> <img src="/image/qLZCM.png" alt="enter image description here"/> </p>

<p> <img src="/image/QXSkM.png" alt="enter image description here"/> </p>

<p><strong>编辑 1:</strong></p>

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

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

<p><strong>编辑 2:</strong></p>

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

<p>我的代码中有错误吗?</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>来自苹果 <a href="https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html#//apple_ref/occ/instm/CLLocationManager/startMonitoringSignificantLocationChanges" rel="noreferrer noopener nofollow">docs</a>可以看出,更新的发送频率并不高于每 <strong>5 分钟</strong> 和 <strong>500 米</strong> 的位置变化:</p>

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

<p>即使应用处于非事件状态,您也会收到更新。对您的另一个提示可能是 oyu 可以在模拟器中测试位置,而不是使用真实设备,这样您就不必到外面进行测试并且仍然可以检查您的日志。在模拟器菜单中,选择<em>Debug --> Location</em>。</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 应用程序处于非事件状态时获取位置更新在 2 次更新后停止,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/24277690/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/24277690/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 应用程序处于非事件状态时获取位置更新在 2 次更新后停止