簡體   English   中英

即使應用程序終止,iOS 9 如何獲取位置

[英]iOS 9 how get locations even if app terminated

我了解如何在后台檢索位置。 而且我知道即使終止了連續位置更新,即使應用程序在 iOS 中終止,也有機會獲取位置

但。 我有應用程序 Moves 和 Foursquare。 如果這個應用程序甚至沒有運行(我終止了所有應用程序並且沒有運行任何應用程序),然后我轉到“隱私”並更改此應用程序的位置以禁用(從不),我可以看到狀態欄中的箭頭消失了。 但是當我啟用位置更新(始終)時,箭頭再次出現在狀態欄和此時未運行的應用程序中。 所以這個應用程序開始獲取有關位置的信息。 如何? 即使幾天沒有啟動 MOves,這個應用程序也會向我顯示過去幾天的正確路線。 他們如何檢索過去幾天的位置信息,甚至應用程序沒有啟動?

我為此找到了解決方案。 這在 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

我的自定義位置管理器。

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM