即使应用程序终止,iOS 9 如何获取位置
Posted
技术标签:
【中文标题】即使应用程序终止,iOS 9 如何获取位置【英文标题】:iOS 9 how get locations even if app terminated 【发布时间】:2015-12-21 08:32:15 【问题描述】:我了解如何在后台检索位置。而且我知道即使终止Continious location updates even if app is terminated in ios
,也有机会获得位置但是。我有应用程序 Moves 和 Foursquare。如果这个应用程序甚至没有运行(我终止所有应用程序并且没有应用程序正在运行)然后我转到“隐私”并更改这个应用程序的位置以禁用(从不),我可以看到状态栏中的箭头消失了。但是当我启用位置更新(始终)时,状态栏中再次出现箭头,此时应用程序未运行。所以这个应用程序开始获取有关位置的信息。如何?即使有几天没有启动 MOves,这个应用程序也会向我显示过去几天的正确路线。他们如何检索过去几天的位置信息,甚至应用程序没有启动?
【问题讨论】:
这不是一个真正的编程问题,更多的是关于操作系统的工作原理。在基本层面上,应用程序告诉系统在用户授予权限后它将“始终”使用位置。系统将决定何时告诉您的应用该位置,并通过使用方法允许您对该位置执行某些操作。 你找到解决这个问题的方法了吗? 如果您愿意使用 VOIP 推送,请查看此链接 - appcaretaker.com/2018/06/05/… 【参考方案1】:我找到了解决方案。 这在 IOS 9 中对我有用。即使重新启动 IOS 设备,它也会继续运行。
http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended
GitHub 示例: https://github.com/voyage11/GettingLocationWhenSuspended
更新
您必须使用[myLocationManager startMonitoringSignificantLocationChanges]
,而不是[myLocationManager startUpdatingLocation]
。
下面是我的 AppDelegate。
@implementation LocationAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
NSLog(@"didFinishLaunchingWithOptions");
self.shareModel = [LocationManager sharedManager];
self.shareModel.afterResume = NO;
[self.shareModel 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)
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];
else if ([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusRestricted)
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.shareModel.afterResume = YES;
[self.shareModel startMonitoringLocation];
[self.shareModel addResumeLocationToPList];
return YES;
- (void)applicationDidEnterBackground:(UIApplication *)application
NSLog(@"applicationDidEnterBackground");
[self.shareModel restartMonitoringLocation];
[self.shareModel addApplicationStatusToPList:@"applicationDidEnterBackground"];
- (void)applicationDidBecomeActive:(UIApplication *)application
NSLog(@"applicationDidBecomeActive");
[self.shareModel addApplicationStatusToPList:@"applicationDidBecomeActive"];
//Remove the "afterResume" Flag after the app is active again.
self.shareModel.afterResume = NO;
[self.shareModel startMonitoringLocation];
- (void)applicationWillTerminate:(UIApplication *)application
NSLog(@"applicationWillTerminate");
[self.shareModel addApplicationStatusToPList:@"applicationWillTerminate"];
@end
我的自定义 LocationManager。
@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.allowsBackgroundLocationUpdates = true;
_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"];
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" );
@end
不要忘记在 plist 文件中启用背景位置。
并将消息设置为 LocationAlwaysUsageDescription。
【讨论】:
为什么在这种情况下需要后台提取? 嗨@SMKS。因为该应用程序将在后台模式下运行。【参考方案2】:我只是按照@Busata 的回答,它在 iOS 12 上运行良好。
在这里,我将用 Swift 发布答案。
LocationManager 类:
class NABackgroundRideLocationTrackingManager:
NSObject,CLLocationManagerDelegate
var locationManager: CLLocationManager?
private static var privateShared :
NABackgroundRideLocationTrackingManager?
var traveledDistance: Double = 0
class func shared() -> NABackgroundRideLocationTrackingManager
guard let uwShared = privateShared else
privateShared = NABackgroundRideLocationTrackingManager()
return privateShared!
return uwShared
class func destroy()
privateShared = nil
func startMonitoringLocation()
if locationManager != nil
locationManager?.stopMonitoringSignificantLocationChanges()
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.allowsBackgroundLocationUpdates = true
locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager?.activityType = CLActivityType.otherNavigation
locationManager?.requestAlwaysAuthorization()
locationManager?.startMonitoringSignificantLocationChanges()
func restartMonitoringLocation()
locationManager?.stopMonitoringSignificantLocationChanges()
locationManager?.requestAlwaysAuthorization()
locationManager?.startMonitoringSignificantLocationChanges()
func postLocations(userLocation: CLLocation)
var params: [String:String] = [:]
params["latitude"] = String(userLocation.coordinate.latitude)
params["longitude"] = String(userLocation.coordinate.longitude)
NAAppManager.postLocationOnBackground(params, success: (success) in
print("location Posted")
) (failure) in
print("Failed")
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
let location = locations.last
self.postLocations(userLocation: location!)
Appdelegate:
class AppDelegate: UIResponder, UIApplicationDelegate
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
if UIApplication.shared.backgroundRefreshStatus == .restricted
else if UIApplication.shared.backgroundRefreshStatus == .denied
else
if ((launchOptions?[UIApplication.LaunchOptionsKey.location]) != nil)
NABackgroundRideLocationTrackingManager.shared().startMonitoringLocation()
func applicationDidEnterBackground(_ application: UIApplication)
NABackgroundRideLocationTrackingManager.shared().restartMonitoringLocation()
func applicationDidBecomeActive(_ application: UIApplication)
NABackgroundRideLocationTrackingManager.shared().startMonitoringLocation()
【讨论】:
以上是关于即使应用程序终止,iOS 9 如何获取位置的主要内容,如果未能解决你的问题,请参考以下文章