应用程序终止时的位置访问权限,没有互联网iOS

时间:2018-03-20 05:44:39

标签: ios swift location applet core-location

我正在开发iOS应用,我的问题如下:

  1. 每次应用程序运行时是否需要访问用户位置?
  2. 地点不依赖互联网吗?
  3. Apple会批准这种应用吗?
  4. 问题1。

    我正在使用这些行来获取用户位置

    locationManager.allowsBackgroundLocationUpdates = true
    locationManager.startUpdatingLocation()
    

    借助这些功能,我可以在应用处于前台或后台时获取位置。

    申请终止时

    locationManager.startMonitoringSignificantLocationChanges()
    

    仅当用户越过500米

    时才有效

    然后应用程序变为活动状态并更新位置

    2.这些都依赖于互联网,而我希望每次互联网存在时都能接收位置。

    3.请让我知道这类应用程序是否会被苹果批准。

    请帮助/建议。

    提前致谢。

3 个答案:

答案 0 :(得分:2)

你的答案在这里:

问题1:每次应用程序运行时是否需要访问用户位置?

答案:不,如果您正在使用应用和应用处于运行模式。您将继续更新位置,然后您应该始终检查位置辅助功能以及 UBER 应用程序等活动。

问题2:地点不依赖互联网吗?

答案取决于您应用的功能。您也可以通过互联网获取当前区域,或者您可以使用GPS获取它。

问题3 :Apple会批准这种应用吗?

答案:是的,如果你正在遵循正确的指导线,那么苹果肯定会接受它。但请确保在获得用户访问权限的同时显示用户友好的消息。

注意:继续进行位置更新会消耗更多电量,因此会快速降低电量。

“仅当用户越过500米时才能工作” 为此,您可以设置更新位置的准确度,如...

locationManager.desiredAccuracy = kCLLocationAccuracyBest

<强>参考: Get User's Current Location / Coordinates

https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/LocationBestPractices.html

答案 1 :(得分:0)

  1. 是的,您可以编写应用程序,以便它可以接收后台位置修复程序,如您自己的代码所示。您需要向用户询问背景位置许可,但是出于隐私和电池原因,许多用户通常不愿意这样做。

  2. CLLocationManager是否使用互联网(甚至只是Wifi接入点检测)与GPS相比非常依赖于设备。有关详细信息,请参阅this SO answer

  3. App Store中有许多应用程序通过CLLocationManager进行后台位置修复。我经常对有多少应用程序要求获得“始终位置”权限感到震惊。

答案 2 :(得分:0)

是的,我们可以用大于或小于500米的时间来测试它,首先我在谷歌和某个地方搜索了很多我发现它有效但我不相信它因为根据苹果安全指南它似乎不可能,所以我在我的代码中应用它并测试它。结果很棒。当应用程序被用户强制退出时,它会在本地plist中保存所有位置数据,因此您可以通过该plist查看它。我不记得在哪里看到了这个链接,但是我分享了一堆可以帮助你理解它的直接代码。

最有趣的部分我能够在应用程序处于终止状态时调用服务器,这真的很棒。 当位置发生变化时,位置管理器似乎会唤醒应用程序几毫秒。

LocationManager.h

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)

@interface LocationManager : NSObject

@property (nonatomic) CLLocationManager * anotherLocationManager;

@property (nonatomic) CLLocationCoordinate2D myLastLocation;
@property (nonatomic) CLLocationAccuracy myLastLocationAccuracy;

@property (nonatomic) CLLocationCoordinate2D myLocation;
@property (nonatomic) CLLocationAccuracy myLocationAccuracy;

@property (nonatomic) NSMutableDictionary *myLocationDictInPlist;
@property (nonatomic) NSMutableArray *myLocationArrayInPlist;

@property (nonatomic) BOOL afterResume;

+ (id)sharedManager;

- (void)startMonitoringLocation;
- (void)restartMonitoringLocation;

- (void)addResumeLocationToPList;
- (void)addLocationToPList:(BOOL)fromResume;
- (void)addApplicationStatusToPList:(NSString*)applicationStatus;

@end

LocationManager.m

#import "LocationManager.h"
#import <UIKit/UIKit.h>
#import "UpdateUserLocation.h"
#import "Constants.h"

@interface LocationManager () <CLLocationManagerDelegate>
@property (nonatomic , strong) UpdateUserLocation *updateUserLocation;
@end


@implementation LocationManager

//Class method to make sure the share model is synch across the app
+ (id)sharedManager {
    static id sharedMyModel = nil;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        sharedMyModel = [[self alloc] init];
    });

    return sharedMyModel;
}


#pragma mark - CLLocationManager

- (void)startMonitoringLocation {
    if (_anotherLocationManager)
        [_anotherLocationManager stopMonitoringSignificantLocationChanges];

    self.anotherLocationManager = [[CLLocationManager alloc]init];
    _anotherLocationManager.delegate = self;
    _anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    _anotherLocationManager.activityType = CLActivityTypeOtherNavigation;

    if(IS_OS_8_OR_LATER) {
        [_anotherLocationManager requestAlwaysAuthorization];
    }
    [_anotherLocationManager startMonitoringSignificantLocationChanges];
}

- (void)restartMonitoringLocation {
    [_anotherLocationManager stopMonitoringSignificantLocationChanges];

    if (IS_OS_8_OR_LATER) {
        [_anotherLocationManager requestAlwaysAuthorization];
    }
    [_anotherLocationManager startMonitoringSignificantLocationChanges];
}


#pragma mark - CLLocationManager Delegate

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{

    NSLog(@"locationManager didUpdateLocations: %@",locations);

    for (int i = 0; i < locations.count; i++) {

        CLLocation * newLocation = [locations objectAtIndex:i];
        CLLocationCoordinate2D theLocation = newLocation.coordinate;
        CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;

        self.myLocation = theLocation;
        self.myLocationAccuracy = theAccuracy;
    }

    [self addLocationToPList:_afterResume];
}



#pragma mark - Plist helper methods

// Below are 3 functions that add location and Application status to PList
// The purpose is to collect location information locally

- (NSString *)appState {
    UIApplication* application = [UIApplication sharedApplication];

    NSString * appState;
    if([application applicationState]==UIApplicationStateActive)
        appState = @"UIApplicationStateActive";
    if([application applicationState]==UIApplicationStateBackground)
        appState = @"UIApplicationStateBackground";
    if([application applicationState]==UIApplicationStateInactive)
        appState = @"UIApplicationStateInactive";

    return appState;
}

- (void)addResumeLocationToPList {

    NSLog(@"addResumeLocationToPList");

    NSString * appState = [self appState];

    self.myLocationDictInPlist = [[NSMutableDictionary alloc]init];
    [_myLocationDictInPlist setObject:@"UIApplicationLaunchOptionsLocationKey" forKey:@"Resume"];
    [_myLocationDictInPlist setObject:appState forKey:@"AppState"];
    [_myLocationDictInPlist setObject:[NSDate date] forKey:@"Time"];

    [self saveLocationsToPlist];
}



- (void)addLocationToPList:(BOOL)fromResume {
    NSLog(@"addLocationToPList");

    NSString * appState = [self appState];

    self.myLocationDictInPlist = [[NSMutableDictionary alloc]init];
    [_myLocationDictInPlist setObject:[NSNumber numberWithDouble:self.myLocation.latitude]  forKey:@"Latitude"];
    [_myLocationDictInPlist setObject:[NSNumber numberWithDouble:self.myLocation.longitude] forKey:@"Longitude"];
    [_myLocationDictInPlist setObject:[NSNumber numberWithDouble:self.myLocationAccuracy] forKey:@"Accuracy"];

    [_myLocationDictInPlist setObject:appState forKey:@"AppState"];

    if (fromResume) {
        [_myLocationDictInPlist setObject:@"YES" forKey:@"AddFromResume"];
        [self updatePreferredUserLocation:[NSString stringWithFormat:@"%f",self.myLocation.latitude] withLongitude:[NSString stringWithFormat:@"%f",self.myLocation.longitude]];
    } else {
        [_myLocationDictInPlist setObject:@"NO" forKey:@"AddFromResume"];
    }

    [_myLocationDictInPlist setObject:[NSDate date] forKey:@"Time"];

    [self saveLocationsToPlist];
}

- (void)addApplicationStatusToPList:(NSString*)applicationStatus {

    NSLog(@"addApplicationStatusToPList");

    NSString * appState = [self appState];

    self.myLocationDictInPlist = [[NSMutableDictionary alloc]init];
    [_myLocationDictInPlist setObject:applicationStatus forKey:@"applicationStatus"];
    [_myLocationDictInPlist setObject:appState forKey:@"AppState"];
    [_myLocationDictInPlist setObject:[NSDate date] forKey:@"Time"];

    [self saveLocationsToPlist];
}

- (void)saveLocationsToPlist {
    NSString *plistName = [NSString stringWithFormat:@"LocationArray.plist"];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docDir = [paths objectAtIndex:0];
    NSString *fullPath = [NSString stringWithFormat:@"%@/%@", docDir, plistName];

    NSMutableDictionary *savedProfile = [[NSMutableDictionary alloc] initWithContentsOfFile:fullPath];

    if (!savedProfile) {
        savedProfile = [[NSMutableDictionary alloc] init];
        self.myLocationArrayInPlist = [[NSMutableArray alloc]init];
    } else {
        self.myLocationArrayInPlist = [savedProfile objectForKey:@"LocationArray"];
    }

    if(_myLocationDictInPlist) {
        [_myLocationArrayInPlist addObject:_myLocationDictInPlist];
        [savedProfile setObject:_myLocationArrayInPlist forKey:@"LocationArray"];
    }

    if (![savedProfile writeToFile:fullPath atomically:FALSE]) {
        NSLog(@"Couldn't save LocationArray.plist" );
    }
}

Appdelegate.m

#import "LocationManager.h"

@property (strong,nonatomic) LocationManager * locationShareModel;

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // 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.

     enable when use track location at force quit
    [self.locationShareModel restartMonitoringLocation];
    [self.locationShareModel addApplicationStatusToPList:@"applicationDidEnterBackground"];
   }

- (void)applicationDidBecomeActive:(UIApplication *)application
{

    // 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.

     enable when use track location at force quit
    [self.locationShareModel addApplicationStatusToPList:@"applicationDidBecomeActive"];

    //Remove the "afterResume" Flag after the app is active again.
    self.locationShareModel.afterResume = NO;
    [self.locationShareModel startMonitoringLocation];

}
- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
      enable when use track location at force quit
    [self.locationShareModel addApplicationStatusToPList:@"applicationWillTerminate"];

}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

    NSLog(@"AG_Didfinishlaunching");

     //enable when use track location at force quit
    [self trackLocation:launchOptions];

}

- (void)trackLocation:(NSDictionary *)launchOptions {
    self.locationShareModel = [LocationManager sharedManager];
    self.locationShareModel.afterResume = NO;

    [self.locationShareModel addApplicationStatusToPList:@"didFinishLaunchingWithOptions"];

    //UIAlertView * alert;

    //We have to make sure that the Background App Refresh is enable for the Location updates to work in the background.
    if ([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusDenied) {
 ///////// delete this alert view if no need
        alert = [[UIAlertView alloc]initWithTitle:@""
                                          message:@"The app doesn't work without the Background App Refresh enabled. To turn it on, go to Settings > General > Background App Refresh"
                                         delegate:nil
                                cancelButtonTitle:@"Ok"
                                otherButtonTitles:nil, nil];
        [alert show];

        UIAlertController *showMsgAlertController = [UIAlertController alertControllerWithTitle: @"Eventseeker" message: @"To use all location servies. Please turn on Background App Refresh, go to Settings > General > Background App Refresh" preferredStyle: UIAlertControllerStyleAlert];
        UIAlertAction *showMsgAlertControllerOkAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                                               handler:nil];
        [showMsgAlertController addAction:showMsgAlertControllerOkAction];
        dispatch_async(dispatch_get_main_queue(), ^{

            [self presentViewController:showMsgAlertController animated:YES completion:nil];
        });
 /////////
    } else if ([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusRestricted) {
        ///////// delete this alert view if no need
        alert = [[UIAlertView alloc]initWithTitle:@""
                                          message:@"The functions of this app are limited because the Background App Refresh is disable."
                                         delegate:nil
                                cancelButtonTitle:@"Ok"
                                otherButtonTitles:nil, nil];
        [alert show];
       /////////////////

    } else {

        // When there is a significant changes of the location,
        // The key UIApplicationLaunchOptionsLocationKey will be returned from didFinishLaunchingWithOptions
        // When the app is receiving the key, it must reinitiate the locationManager and get
        // the latest location updates

        // This UIApplicationLaunchOptionsLocationKey key enables the location update even when
        // the app has been killed/terminated (Not in th background) by iOS or the user.

        NSLog(@"UIApplicationLaunchOptionsLocationKey : %@" , [launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]);
        if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {

            // This "afterResume" flag is just to show that he receiving location updates
            // are actually from the key "UIApplicationLaunchOptionsLocationKey"
            self.locationShareModel.afterResume = YES;

            [self.locationShareModel startMonitoringLocation];
            [self.locationShareModel addResumeLocationToPList];
        }
    }
}

最后但并非最不要忘记在plist中添加始终访问位置的权限。当应用程序强制退出时,这是访问它的非常重要的一步。用户必须选择始终使用位置访问权限,并且必须关闭节电模式,因为它会禁用后台刷新模式。 请记住此应用的位置始终访问和后台刷新模式必须为开才能访问处于已终止状态的位置。

对于离线模式,我没有测试它。但我认为它有效。