[英]iOS 9 how get locations even if app terminated
我了解如何在后台檢索位置。 而且我知道即使終止了連續位置更新,即使應用程序在 iOS 中終止,也有機會獲取位置
但。 我有應用程序 Moves 和 Foursquare。 如果這個應用程序甚至沒有運行(我終止了所有應用程序並且沒有運行任何應用程序),然后我轉到“隱私”並更改此應用程序的位置以禁用(從不),我可以看到狀態欄中的箭頭消失了。 但是當我啟用位置更新(始終)時,箭頭再次出現在狀態欄和此時未運行的應用程序中。 所以這個應用程序開始獲取有關位置的信息。 如何? 即使幾天沒有啟動 MOves,這個應用程序也會向我顯示過去幾天的正確路線。 他們如何檢索過去幾天的位置信息,甚至應用程序沒有啟動?
我為此找到了解決方案。 這在 IOS 9 中對我有用。即使重新啟動 IOS 設備,也會繼續運行。
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
我的自定義位置管理器。
@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。
我只是遵循@Busata 的回答,它在 iOS 12 上運行良好。
在這里,我將在 Swift 中發布答案。
位置管理器類:
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()
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.