मुझे अपने iOS एप्लिकेशन में हर n मिनट में बैकग्राउंड लोकेशन अपडेट कैसे मिलेगा?


207

मैं अपने iOS एप्लिकेशन में प्रत्येक n मिनट में बैकग्राउंड लोकेशन अपडेट प्राप्त करने का तरीका ढूंढ रहा हूं। मैं आईओएस 4.3 का उपयोग कर रहा हूं और समाधान गैर-जेलब्रेक आईफ़ोन के लिए काम करना चाहिए।

मैंने निम्नलिखित विकल्पों की कोशिश की / विचार किया:

  • CLLocationManager startUpdatingLocation/startMonitoringSignificantLocationChanges: यह पृष्ठभूमि में कॉन्फ़िगर किए गए गुणों के आधार पर अपेक्षित रूप से काम करता है, लेकिन हर n मिनट में स्थान को अपडेट करने के लिए इसे मजबूर करना संभव नहीं लगता है
  • NSTimer: ऐप तब काम करता है जब ऐप अग्रभूमि में चल रहा होता है लेकिन पृष्ठभूमि कार्यों के लिए डिज़ाइन नहीं किया जाता है
  • स्थानीय सूचनाएं: स्थानीय सूचनाएं हर n मिनट में निर्धारित की जा सकती हैं, लेकिन वर्तमान स्थान (अधिसूचना के माध्यम से ऐप लॉन्च करने वाले उपयोगकर्ता के बिना) के लिए कुछ कोड निष्पादित करना संभव नहीं है। यह दृष्टिकोण भी एक स्वच्छ दृष्टिकोण नहीं है क्योंकि यह वह नहीं है जिसके लिए सूचनाओं का उपयोग किया जाना चाहिए।
  • UIApplication:beginBackgroundTaskWithExpirationHandler: जहां तक ​​मैं समझता हूं, इसका उपयोग पृष्ठभूमि में कुछ काम को समाप्त करने के लिए किया जाना चाहिए (समय में भी सीमित) जब किसी ऐप को "लंबे समय से चल रही" पृष्ठभूमि प्रक्रियाओं को लागू करने के बजाय पृष्ठभूमि में ले जाया जाता है।

मैं इन नियमित पृष्ठभूमि स्थान अपडेट को कैसे लागू कर सकता हूं?



उपयोगी अनुवर्ती: stackoverflow.com/questions/10235203/…
लोलो

1
यदि आप इसे iOS 7 पर काम करने की कोशिश कर रहे हैं, तो आप इस समाधान को यहाँ आज़मा सकते हैं: stackoverflow.com/questions/18946881/… यदि आपके कोई प्रश्न हैं, तो आपको यहाँ चर्चा के लिए हमारे साथ आने का स्वागत है: mobileoop.com/background -लोकेशन-अपडेट-प्रोग्रामिंग-फॉर-आयोस -7
रिकी

1
आपके सभी निष्कर्ष सही हैं (चार गोली बिंदु)। मूल्यवान जानकारी जो तब है, यह जानना कि आप मामले से मेल नहीं खाते हैं? और हां, जब SUSPENDED MODE या NOT RUNNING में, हर n-मिनट को अपडेट करने के लिए कोई अंतिम तरीका नहीं है।
लेनआर्ट

जवाबों:


113

मुझे Apple Developer Forums की मदद से इसे लागू करने का एक समाधान मिला:

  • उल्लिखित करना location background mode
  • के NSTimerसाथ पृष्ठभूमि में एक बनाएँUIApplication:beginBackgroundTaskWithExpirationHandler:
  • जब nयह छोटा है तो UIApplication:backgroundTimeRemainingयह ठीक काम करेगा। जब nहै बड़ा , location managerसक्षम किया जाना चाहिए (और विकलांग) फिर से पहले कोई समय पृष्ठभूमि कार्य से बचने के लिए शेष को मार डाला जा रहा है।

यह काम करता है क्योंकि स्थान तीन अनुमत प्रकार के पृष्ठभूमि निष्पादन में से एक है

नोट: मैं सिम्युलेटर में यह परीक्षण करके कुछ समय खो दिया है जहां यह काम नहीं करता है। हालांकि, यह मेरे फोन पर ठीक काम करता है।


24
क्या आपके पास फोरम का लिंक होना चाहिए। मैं उसी प्रकार के स्थान मैपिंग को लागू करना चाह रहा हूं और वह काम करने में सक्षम नहीं है। या कुछ नमूना कोड की बहुत सराहना की जाएगी।
उत्तविथक

4
क्या आप बता सकते हैं कि यदि आप लोकेशन मैनेजर को रोकते हैं और शुरू करते हैं तो 10 मिनट (अधिकतम अनुमत समय) के बाद भी बैकग्राउंड टास्क क्यों नहीं मारा जाता है? क्या यह किसी प्रकार की इच्छित कार्यशीलता है? अगर ऐसा होता है तो यह Apple SDK में बग जैसा लगता है। आप किस iOS संस्करण पर कोशिश कर रहे थे?
सौरभ

5
@all: हां, हमारा ऐप AppStore में उपलब्ध है। मैं सभी कोड पोस्ट नहीं करने वाला हूं, सभी उल्लिखित बुलेटप्वाइंट स्पष्ट रूप से प्रलेखित विशेषताएं हैं। यदि आपको कोई विशेष समस्या हो रही है, तो अपना स्वयं का प्रश्न बताएं कि आपने क्या प्रयास किया है और क्या गलत है।
१२

3
@ user836026: हां, पृष्ठभूमि मोड को निर्दिष्ट करने से मेरा मतलब है। स्थान अपडेट को रोकने के बाद, ऐप को समाप्त होने से बचाने के लिए इसे 10 मिनट के भीतर फिर से शुरू किया जाना चाहिए।
wjans

12
उन सभी वास्तविक कोड को देखने के इच्छुक लोगों के लिए जो यहाँ चर्चा की जा रही है, stackoverflow.com/questions/10235203/…
Lolo

55

IOS 8/9/10 पर हर 5 मिनट में बैकग्राउंड लोकेशन अपडेट करने के लिए निम्न कार्य करें:

  1. प्रोजेक्ट पर जाएं -> क्षमताएं -> पृष्ठभूमि मोड -> स्थान अपडेट चुनें

  2. प्रोजेक्ट पर जाएं -> जानकारी -> एक कुंजी जोड़ें NSLocationAlwaysUsageDescription रिक्त मान के साथ (या वैकल्पिक रूप से कोई भी)

  3. जब आपका ऐप बैकग्राउंड में हो तो लोकेशन काम करना और वेब सर्विस को निर्देशांक भेजना या उनके साथ कुछ भी करना हर 5 मिनट में इसे नीचे दिए गए कोड की तरह लागू करना।

मैं किसी भी पृष्ठभूमि कार्य या टाइमर का उपयोग नहीं कर रहा हूं। मैंने अपने डिवाइस के साथ iOS 8.1 के साथ इस कोड का परीक्षण किया है जो पृष्ठभूमि में चल रहे मेरे ऐप के साथ कुछ घंटों के लिए मेरे डेस्क पर पड़ा था। डिवाइस लॉक था और कोड हर समय ठीक से चल रहा था।

@interface LocationManager () <CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSDate *lastTimestamp;

@end

@implementation LocationManager

+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
        LocationManager *instance = sharedInstance;
        instance.locationManager = [CLLocationManager new];
        instance.locationManager.delegate = instance;
        instance.locationManager.desiredAccuracy = kCLLocationAccuracyBest; // you can use kCLLocationAccuracyHundredMeters to get better battery life
        instance.locationManager.pausesLocationUpdatesAutomatically = NO; // this is important
    });

    return sharedInstance;
}

- (void)startUpdatingLocation
{
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];

    if (status == kCLAuthorizationStatusDenied)
    {
        NSLog(@"Location services are disabled in settings.");
    }
    else
    {
        // for iOS 8
        if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
        {
            [self.locationManager requestAlwaysAuthorization];
        }
        // for iOS 9
        if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
        {
            [self.locationManager setAllowsBackgroundLocationUpdates:YES];
        }

        [self.locationManager startUpdatingLocation];
    }
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *mostRecentLocation = locations.lastObject;
    NSLog(@"Current location: %@ %@", @(mostRecentLocation.coordinate.latitude), @(mostRecentLocation.coordinate.longitude));

    NSDate *now = [NSDate date];
    NSTimeInterval interval = self.lastTimestamp ? [now timeIntervalSinceDate:self.lastTimestamp] : 0;

    if (!self.lastTimestamp || interval >= 5 * 60)
    {
        self.lastTimestamp = now;
        NSLog(@"Sending current location to web service.");
    }
}

@end

3
क्या यह कुछ घंटों से अधिक काम करता है? ऐसा लगता है कि भले ही ऐप को समाप्त नहीं किया गया है, डिवाइस पृष्ठभूमि पर जाने वाले ऐप के एक या एक घंटे बाद स्थान अपडेट को धक्का देना बंद कर देता है।
Myxtic

2
बैकग्राउंड फ़ेच मेरी परियोजना में अक्षम है (यह बंद या चालू होने पर कोई फर्क नहीं पड़ता)। हालाँकि pausesLocationUpdatesAutomatically ठीक से काम करने के लिए उपरोक्त उदाहरण के लिए NO पर सेट होना चाहिए। यदि आप सिस्टम द्वारा पूर्व में रोका गया था, तो एक बार फिर से चलना शुरू करने पर यह स्वचालित रूप से फिर से शुरू नहीं होगा। यही कारण है कि उपरोक्त उदाहरण में मैंने इस संपत्ति को NO पर सेट किया है।
लेसज़ेक सजरी

1
मुझे लगता है कि आप बिल्कुल सही हैं। इस मुद्दे के बारे में कुछ और जानकारी यहाँ मिली: stackoverflow.com/q/17484352/1048331
Myxtic

2
@LeszekS आपको पृष्ठभूमि के लिए iOS 9 समर्थन के लिए नीचे दिए गए कोड को जोड़ने की आवश्यकता है - if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) { [self.locationManager setAllowsBackgroundLocationUpdates:YES]; }
Fenil

2
ऐसा करने में क्या सुविधा है? आप निरंतर उच्च सटीकता होने के बावजूद बैटरी को सूखा रहे हैं। केवल एक चीज जो आप नहीं करते हैं, वह वास्तव में पहले से ही प्राप्त स्थान का उपयोग नहीं करते हैं जब तक आप 5 मिनट के अंतराल तक नहीं पहुंचते ...
Honey

34

मैंने यह एक एप्लीकेशन में किया है जिसे मैं विकसित कर रहा हूं। ऐप के बैकग्राउंड में होने पर टाइमर काम नहीं करते हैं लेकिन ऐप लगातार लोकेशन अपडेट प्राप्त कर रहा है। मैं प्रलेखन में कहीं पढ़ता हूं (मैं इसे अब नहीं ढूंढ सकता, मैं एक अपडेट पोस्ट करूँगा जब मैं करता हूं) कि एक विधि केवल एक सक्रिय रन लूप पर कहा जा सकता है जब ऐप पृष्ठभूमि में होता है। एप्लिकेशन प्रतिनिधि के पास bg में भी एक सक्रिय रन लूप है ताकि आपको इस काम को करने के लिए खुद को बनाने की आवश्यकता न हो। [मुझे यकीन नहीं है कि अगर यह सही व्याख्या है, लेकिन यह है कि मैं कैसे पढ़ा से समझा

सबसे पहले, अपने ऐप के info.plist में locationकुंजी के लिए ऑब्जेक्ट जोड़ें UIBackgroundModes। अब, आपको अपने ऐप में कहीं भी स्थान अपडेट शुरू करने की आवश्यकता है:

    CLLocationManager locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;//or whatever class you have for managing location
    [locationManager startUpdatingLocation];

अगला, -(void)didUpdateToLocation:(CLLocation*)locationएप्लिकेशन प्रतिनिधि में , स्थान अपडेट को संभालने के लिए एक विधि लिखें । फिर उस वर्ग की विधि locationManager:didUpdateLocation:fromLocationको लागू करें CLLocationManagerDelegateजिसमें आपने स्थान प्रबंधक शुरू किया था (क्योंकि हमने स्थान प्रबंधक प्रतिनिधि को 'स्वयं' में सेट किया है)। इस पद्धति के अंदर आपको यह जांचना होगा कि समय अंतराल जिसके बाद आपको स्थान अपडेट संभालना है, समाप्त हो गया है। आप हर बार वर्तमान समय की बचत करके ऐसा कर सकते हैं। यदि वह समय समाप्त हो गया है, तो अपने ऐप के प्रतिनिधि से विधि अद्यतन की कॉल करें:

NSDate *newLocationTimestamp = newLocation.timestamp;
NSDate *lastLocationUpdateTiemstamp;

int locationUpdateInterval = 300;//5 mins

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if (userDefaults) {

        lastLocationUpdateTiemstamp = [userDefaults objectForKey:kLastLocationUpdateTimestamp];

        if (!([newLocationTimestamp timeIntervalSinceDate:lastLocationUpdateTiemstamp] < locationUpdateInterval)) {
            //NSLog(@"New Location: %@", newLocation);
            [(AppDelegate*)[UIApplication sharedApplication].delegate didUpdateToLocation:newLocation];
            [userDefaults setObject:newLocationTimestamp forKey:kLastLocationUpdateTimestamp];
        }
    }
}

जब आपका ऐप बैकग्राउंड में होगा तब भी यह आपका तरीका हर 5 मिनट में कॉल करेगा। Imp: यदि आपके स्थान डेटा की सटीकता महत्वपूर्ण नहीं है, तो यह कार्यान्वयन बैटरी को सूखा देता है[locationManager startMonitoringSignificantLocationChanges]

इसे अपने ऐप में जोड़ने से पहले, कृपया अवेयरनेस प्रोग्रामिंग गाइड पढ़ें


3
इस तरह से स्थान सेवाएं लगातार सक्षम होती हैं (वास्तव में बैटरी निकास), मैं ऐसा नहीं चाहता। मैं हर n मिनट में लोकेशन सेवा को सक्षम करना चाहता हूं और जब मुझे एक अच्छा फिक्स होता है तो तुरंत इसे निष्क्रिय कर देता है (बस ध्यान दिया कि मैंने इसे स्पष्ट रूप से अपने प्रश्न में स्पष्ट नहीं किया है)। इस व्यवहार को मैं वर्णित समाधान में प्राप्त कर सकता हूं।
11:24 पर जुआन

3
आप स्थान प्रबंधक की सटीकता 1 किमी पर सेट कर सकते हैं - इससे आपकी बैटरी लगभग बरकरार रहेगी। 5 मिनट के बाद आपने 1 मी तक सटीकता निर्धारित की। जब आपको संतोषजनक स्थान मिलता है (आमतौर पर 5s के बाद) तो सटीकता 1 किमी पर वापस सेट करें।
नगोडे

knagode, मैंने बैटरी डलवाने के मुद्दे के लिए आपके सुझाए गए समाधान की कोशिश की, लेकिन एन मिनट के बाद सटीकता में वृद्धि के बावजूद, स्थान प्रबंधक: didUpdateLocations विधि को फिर से नहीं कहा जाता है। , DidUpdateLocations विधि एन मिनट के बाद, लेकिन पृष्ठभूमि मोड में काम नहीं कर रहा ...: मैं startUpdating और stopUpdating की कोशिश की, वृद्धि और कमी सटीकता के बजाय, इसे सफलतापूर्वक बुलाया प्रतिनिधि locationManager है
हार्दिक Darji

प्रलेखन के लिंक के लिए के रूप में। यहां देखें : "आपके प्रतिनिधि ऑब्जेक्ट के तरीकों को उस थ्रेड से बुलाया जाता है जिसमें आपने संबंधित स्थान सेवाओं को शुरू किया था। उस थ्रेड में एक सक्रिय रन लूप होना चाहिए, जैसे आपके एप्लिकेशन के मुख्य थ्रेड में पाया गया।"
हनी

24

अब जब iOS6 सबसे अच्छा तरीका है जो हमेशा के लिए चलने वाली लोकेशन सेवाओं के लिए है ...

- (void)applicationWillResignActive:(UIApplication *)application
{
/*
 Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
 Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
 */

NSLog(@"to background");

app.isInBackground = TRUE;

UIApplication *app = [UIApplication sharedApplication];

// Request permission to run in the background. Provide an
// expiration handler in case the task runs long.
NSAssert(bgTask == UIBackgroundTaskInvalid, nil);

bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    // Synchronize the cleanup call on the main thread in case
    // the task actually finishes at around the same time.
    dispatch_async(dispatch_get_main_queue(), ^{

        if (bgTask != UIBackgroundTaskInvalid)
        {
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }
    });
}];

// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // Do the work associated with the task.

    locationManager.distanceFilter = 100;
    locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    [locationManager startMonitoringSignificantLocationChanges];
    [locationManager startUpdatingLocation];

    NSLog(@"App staus: applicationDidEnterBackground");
    // Synchronize the cleanup call on the main thread in case
    // the expiration handler is fired at the same time.
    dispatch_async(dispatch_get_main_queue(), ^{
        if (bgTask != UIBackgroundTaskInvalid)
        {
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }
    });
});

NSLog(@"backgroundTimeRemaining: %.0f", [[UIApplication sharedApplication] backgroundTimeRemaining]);

}

बस इसे इस तरह से परीक्षण किया:

मैंने ऐप शुरू किया, पृष्ठभूमि जाओ और कुछ मिनटों तक कार में चले जाओ। फिर मैं 1 घंटे के लिए घर जाता हूं और फिर से चलना शुरू कर देता हूं (फिर से ऐप को खोले बिना)। स्थान फिर से शुरू हो गए। फिर दो घंटे रुका और फिर शुरू हो गया। सब कुछ फिर से ...

IOS6 में नई लोकेशन सेवाओं का उपयोग न करें

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{   
    CLLocation *loc = [locations lastObject];

    // Lat/Lon
    float latitudeMe = loc.coordinate.latitude;
    float longitudeMe = loc.coordinate.longitude;
}

1
यदि ऐप क्रैश हो जाता है या मारा जाता है, तो सिस्टम पुनः आरंभ नहीं होता है, है ना?
केन

1
अधिक पठनीय कोड के लिए, आप एक [स्थान lastObject] कर सकते हैं; इसके बजाय [स्थानों objectAtIndex: [स्थानों की गिनती] - 1]
axello

आपकी विधि केवल ios6 पर है?
पेंगवांग

क्या हमें इसका उपयोग करना है? मुझे लगा कि क्लास के व्यूडीडलड में सिर्फ लोकेशन मैनेजर कोड है, और प्लिस्ट फाइल में एक बैकग्राउंड कुंजी सेट की है, जो कि लोकेशन अपडेट के लिए ऐप रजिस्टर पर्याप्त होना चाहिए? कृपा करके आप इस बारे में मेरी मदद कर सकते हैं!
नितिनरेड्डी

हां, यह आकर्षण नितिनरेड्डी की तरह काम करेगा लेकिन यह 10 मिनट के बाद काम करना बंद कर देगा क्योंकि iOS उस अवधि के बाद लंबे धागे को मारता है। यदि आप उन सेवाओं को हमेशा के लिए शुरू करना चाहते हैं तो मेरा समाधान सही है। मैंने दो दिन पहले कुछ परीक्षण किए हैं और यह प्रत्येक घंटे में 6% बैटरी की निकासी करता है। [स्थान प्रबंधक का उपयोग करना शुरू करना] इसके बजाय १
एलेजांद्रो लुएंगो

13

दुःस्वप्न वाले किसी और को यह पता लगाने के लिए। मेरे पास एक सरल उपाय है।

  1. इस उदाहरण को raywenderlich.com से देखें -> नमूना कोड है, यह पूरी तरह से काम करता है, लेकिन दुर्भाग्य से पृष्ठभूमि स्थान के दौरान कोई टाइमर नहीं है। यह अनिश्चित काल तक चलेगा।
  2. टाइमर का उपयोग करके जोड़ें:

    -(void)applicationDidEnterBackground {
    [self.locationManager stopUpdatingLocation];
    
    UIApplication*    app = [UIApplication sharedApplication];
    
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
    
     self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate
                                                  target:self.locationManager
                                                selector:@selector(startUpdatingLocation)
                                                userInfo:nil
                                                 repeats:YES];
    
    }
  3. बस info.plist में "स्थान अपडेट के लिए ऐप रजिस्टर" जोड़ने के लिए मत भूलना।


क्या यह 3 मिनट से अधिक समय के लिए स्थान प्राप्त करता है?
नाइटनॉट

क्षमताओं में स्थान सेट करना होगा -> पृष्ठभूमि मोड।
सर्जियो आंद्रेओटी

यह काम नहीं कर रहा है!! ? मैंने iOS 8 ans iOS 10
कीर्ति

यदि मैं गलत हूं तो मुझे सही करों। मैंने जो पढ़ा है, उसके आधार पर, आप केवल एक बार ही स्थान प्रबंधन शुरू करें। उसके बाद सभी अंतराल बेमानी हैं। चूंकि यह पहले से ही शुरू किया गया है
हनी

यह काम कर रहा है लेकिन यह 170 सेकंड के बाद बंद हो रहा है। मैं अपने काम को असीमित समय के लिए पृष्ठभूमि में चलाना चाहता हूं
अंशुमान ब्यूरोमैन

8

यहाँ मेरा उपयोग है:

import Foundation
import CoreLocation
import UIKit

class BackgroundLocationManager :NSObject, CLLocationManagerDelegate {

    static let instance = BackgroundLocationManager()
    static let BACKGROUND_TIMER = 150.0 // restart location manager every 150 seconds
    static let UPDATE_SERVER_INTERVAL = 60 * 60 // 1 hour - once every 1 hour send location to server

    let locationManager = CLLocationManager()
    var timer:NSTimer?
    var currentBgTaskId : UIBackgroundTaskIdentifier?
    var lastLocationDate : NSDate = NSDate()

    private override init(){
        super.init()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
        locationManager.activityType = .Other;
        locationManager.distanceFilter = kCLDistanceFilterNone;
        if #available(iOS 9, *){
            locationManager.allowsBackgroundLocationUpdates = true
        }

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.applicationEnterBackground), name: UIApplicationDidEnterBackgroundNotification, object: nil)
    }

    func applicationEnterBackground(){
        FileLogger.log("applicationEnterBackground")
        start()
    }

    func start(){
        if(CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedAlways){
            if #available(iOS 9, *){
                locationManager.requestLocation()
            } else {
                locationManager.startUpdatingLocation()
            }
        } else {
                locationManager.requestAlwaysAuthorization()
        }
    }
    func restart (){
        timer?.invalidate()
        timer = nil
        start()
    }

    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        switch status {
        case CLAuthorizationStatus.Restricted:
            //log("Restricted Access to location")
        case CLAuthorizationStatus.Denied:
            //log("User denied access to location")
        case CLAuthorizationStatus.NotDetermined:
            //log("Status not determined")
        default:
            //log("startUpdatintLocation")
            if #available(iOS 9, *){
                locationManager.requestLocation()
            } else {
                locationManager.startUpdatingLocation()
            }
        }
    }
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        if(timer==nil){
            // The locations array is sorted in chronologically ascending order, so the
            // last element is the most recent
            guard let location = locations.last else {return}

            beginNewBackgroundTask()
            locationManager.stopUpdatingLocation()
            let now = NSDate()
            if(isItTime(now)){
                //TODO: Every n minutes do whatever you want with the new location. Like for example sendLocationToServer(location, now:now)
            }
        }
    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        CrashReporter.recordError(error)

        beginNewBackgroundTask()
        locationManager.stopUpdatingLocation()
    }

    func isItTime(now:NSDate) -> Bool {
        let timePast = now.timeIntervalSinceDate(lastLocationDate)
        let intervalExceeded = Int(timePast) > BackgroundLocationManager.UPDATE_SERVER_INTERVAL
        return intervalExceeded;
    }

    func sendLocationToServer(location:CLLocation, now:NSDate){
        //TODO
    }

    func beginNewBackgroundTask(){
        var previousTaskId = currentBgTaskId;
        currentBgTaskId = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
            FileLogger.log("task expired: ")
        })
        if let taskId = previousTaskId{
            UIApplication.sharedApplication().endBackgroundTask(taskId)
            previousTaskId = UIBackgroundTaskInvalid
        }

        timer = NSTimer.scheduledTimerWithTimeInterval(BackgroundLocationManager.BACKGROUND_TIMER, target: self, selector: #selector(self.restart),userInfo: nil, repeats: false)
    }
}

मैं इस तरह AppDelegate में ट्रैकिंग शुरू करता हूं:

BackgroundLocationManager.instance.start()

धन्यवाद। हमारी परियोजना को उपयोगकर्ता स्थान ट्रैक करने की आवश्यकता है + पृष्ठभूमि में PubNub घटनाओं को भेजें और आपका समाधान वास्तव में अच्छी तरह से काम कर रहा है।
user921509

हाय Hmitkov, जहाँ मैं SendLocationToServer विधि को सर्वर पर उपयोगकर्ता स्थान भेजने के लिए कह सकता हूँ
AmanGupta007

@ AmanGupta007 आप sendLocationToServer को func locationManager (प्रबंधक: didUpdateLocations :) में कॉल कर सकते हैं। // TODO टिप्पणी को कोड में नोट करें।
हितमकोव

@hmitkov क्या यह संभव है कि ऐप के बैकग्राउंड में होने पर इसके साथ लोकेशन सर्विसेज को शुरू और बंद किया जा सके? उदाहरण, पुश नोटिफिकेशन से लोकेशन सर्विस शुरू करें, कुछ लेट / लॉन्ग पकड़ें, वेबसर्विस को भेजें, फिर लोकेशन अपडेट करना बंद करें। प्रत्येक बार पुश-बॉडी में 'सामग्री-उपलब्ध' = 1 को शामिल करें।
DookieMan

1
मैंने इस कोड की कोशिश की है, लेकिन ऐसा लगता है कि यह iOS11 पर काम नहीं कर रहा है? (मैंने इसे किसी अन्य संस्करण पर परीक्षण नहीं किया है।)
टॉम

6

दुर्भाग्य से, आपकी सभी धारणाएँ सही लगती हैं, और मुझे नहीं लगता कि ऐसा करने का कोई तरीका है। बैटरी जीवन को बचाने के लिए, iPhone की स्थान सेवाएं आंदोलन पर आधारित हैं। यदि फ़ोन एक स्थान पर बैठता है, तो यह स्थान सेवाओं के लिए अदृश्य है।

CLLocationManagerकेवल फोन करेगा locationManager:didUpdateToLocation:fromLocation:फोन स्थान अपडेट है, जो केवल तब होता है तीन स्थान सेवाओं में से एक (सेल टॉवर, GPS, WiFi) एक परिवर्तन मानते अगर को प्राप्त होने वाली।

कुछ अन्य चीजें जो आगे के समाधानों को सूचित करने में मदद कर सकती हैं:

  • सेवाओं को शुरू करने और बंद करने से didUpdateToLocationप्रतिनिधि पद्धति को बुलाया जाता है, लेकिन newLocationएक पुराना टाइमस्टैम्प हो सकता है।

  • क्षेत्र की निगरानी में मदद मिल सकती है

  • जब पृष्ठभूमि में चल रहा हो, तो ध्यान रखें कि Apple द्वारा अनुमोदित "पूर्ण" स्थान सेवा समर्थन प्राप्त करना मुश्किल हो सकता है। मैंने जो देखा है, वे विशेष startMonitoringSignificantLocationChangesरूप से उन ऐप्स के लिए कम शक्ति विकल्प के रूप में डिज़ाइन किए गए हैं, जिन्हें पृष्ठभूमि स्थान समर्थन की आवश्यकता होती है, और डेवलपर्स को इसका उपयोग करने के लिए प्रोत्साहित करते हैं जब तक कि ऐप बिल्कुल इसकी आवश्यकता न हो।

शुभ लाभ!

अद्यतन: ये विचार अब तक पुराने हो सकते हैं। ऐसा लगता है कि लोग @wjans के उत्तर के साथ सफलता पा रहे हैं, ऊपर।


1
AppStore (उदाहरण के लिए "My Locus") में उपलब्ध एप्लिकेशन हैं जो पृष्ठभूमि में स्थान अपडेट प्राप्त करना संभव बनाते हैं। वे स्थान सेवा को सक्रिय नहीं रखते हैं, लेकिन यह परिभाषित अंतराल के अनुसार शीघ्र ही सक्षम हो जाता है। वे ऐसा कैसे करते हैं?
6

2
आपके द्वारा बताई गई स्थिति में, एप्लिकेशन सबसे अधिक संभावना है, जो प्रारंभकर्ता का उपयोग कर रहा है। SignificantLocationChanges दृष्टिकोण। यहां, स्थान अपडेट प्राप्त होने पर फ़ोन अस्थायी रूप से 'वॉक्ड अप' हो जाता है, लेकिन कोई अंतराल नहीं है जिसे आप पृष्ठभूमि में इस सेवा को 'पिंग' करने के लिए सेट कर सकते हैं। जब फोन चलता है (या सेलुलर से जीपीएस या वाईफाई पर स्विच करता है), तो यह एक अद्यतन को चालू करता है। इस विषय पर स्टैनफोर्ड आईट्यून्स यू लेक्चर वास्तव में मेरे लिए मददगार था - उम्मीद है कि इससे आपको वर्कअराउंड ढूंढने में मदद मिल सकती है: itunes.apple.com/us/itunes-u/iphone-application-development/…
Chazbot

2
सूचक के लिए Thx। हालाँकि, मुझे अभी भी समझ नहीं आ रहा है कि ऐप क्या कर रहा है। यहां तक ​​कि अगर मेरा फोन मेरे डेस्क पर है, तो बिल्कुल भी नहीं, मैं हर 10 मिनट (बिल्कुल) ट्रिगर की जा रही लोकेशन सर्विस देख सकता हूं। अगर मैं सही तरीके से समझूं, startMonitoringSignificantLocationChangesतो उस मामले में कोई अपडेट नहीं दूंगा।
१11

1
@wans आपके फोन की बैटरी की खपत कैसे है, क्या आपने देखा कि शायद यह Mylocus ऐप के कारण है?
user836026

6

मैंने स्थान सेवाओं का उपयोग करके एक ऐप लिखा है, ऐप को प्रत्येक 10s पर स्थान भेजना होगा। और इसने बहुत अच्छा काम किया।

बस Apple के डॉक्स के बाद " allowDeferredLocationUpdatesUntilTraveled: टाइमआउट " विधि का उपयोग करें ।

मैंने क्या किया:

आवश्यक: अद्यतन स्थान के लिए रजिस्टर पृष्ठभूमि मोड।

1. बनाएँ LocationMangerऔर startUpdatingLocation, के साथ accuracyऔर filteredDistanceजो आप चाहते हैं:

-(void) initLocationManager    
{
    // Create the manager object
    self.locationManager = [[[CLLocationManager alloc] init] autorelease];
    _locationManager.delegate = self;
    // This is the most important property to set for the manager. It ultimately determines how the manager will
    // attempt to acquire location and thus, the amount of power that will be consumed.
    _locationManager.desiredAccuracy = 45;
    _locationManager.distanceFilter = 100;
    // Once configured, the location manager must be "started".
    [_locationManager startUpdatingLocation];
}

2.allowDeferredLocationUpdatesUntilTraveled:timeout बैकग्राउंड में विधि का उपयोग करके ऐप को हमेशा के लिए चालू रखने के लिए , आपको updatingLocationऐप को पृष्ठभूमि में ले जाते समय नए पैरामीटर के साथ पुनरारंभ करना होगा , जैसे:

- (void)applicationWillResignActive:(UIApplication *)application {
     _isBackgroundMode = YES;

    [_locationManager stopUpdatingLocation];
    [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [_locationManager setDistanceFilter:kCLDistanceFilterNone];
    _locationManager.pausesLocationUpdatesAutomatically = NO;
    _locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    [_locationManager startUpdatingLocation];
 }

3. एप्लिकेशन को locationManager:didUpdateLocations:कॉलबैक के साथ सामान्य रूप से अपडेट किया जाता है :

-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
//  store data
    CLLocation *newLocation = [locations lastObject];
    self.userLocation = newLocation;

   //tell the centralManager that you want to deferred this updatedLocation
    if (_isBackgroundMode && !_deferringUpdates)
    {
        _deferringUpdates = YES;
        [self.locationManager allowDeferredLocationUpdatesUntilTraveled:CLLocationDistanceMax timeout:10];
    }
}

4. लेकिन आपको locationManager:didFinishDeferredUpdatesWithError:अपने उद्देश्य के लिए कॉलबैक में डेटा को संभालना चाहिए

- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error {

     _deferringUpdates = NO;

     //do something 
}

5. नोट: मुझे लगता है कि हमें LocationManagerबैकग्राउंड / फोरग्राउंड मोड के बीच हर बार ऐप स्विच के मापदंडों को रीसेट करना चाहिए ।


@ सभी जो इस या उससे ऊपर के समाधान के बारे में बताते हैं कि क्या मुझे डिवाइस बैटरी को बचाना पसंद करना चाहिए या दोनों एक ही को प्रभावित करेंगे?
यश

2
मैंने आपके द्वारा बताए गए दोनों समाधानों की कोशिश की, और देखा कि @ wjans की एक छोटी सी बैटरी बचती है। लेकिन, iOS 8 के आने के बाद, ऐसा लगता है कि यह समाधान अब ठीक से काम नहीं करता है। अधिक विवरण के लिए: ज्यादातर समय, ऐप पृष्ठभूमि मोड में लंबे समय तक नहीं रह सकता है।
samthui7

@ samthui7 आप pausesLocationUpdatesAutomatically = false क्यों सेट करते हैं?
सेड्रिकसब्री सेप

pausesLocationUpdatesAutomatically = trueयदि कोई स्थान परिवर्तन ( Apple के doc ) प्रतीत नहीं होता है, तो अपडेट करने के लिए स्थान प्रबंधक को बताता है कि मेरे ऐप की आवश्यकता प्रत्येक 10s उपयोगकर्ता को भेजते रहना है । वैसे भी, मैंने स्पष्ट रूप से location manager pauses updatesअभी तक के मामले का परीक्षण नहीं किया: डी।
samthui7

@CedricSoubrie: सेटिंग के pausesLocationUpdatesAutomatically = trueकारण मेरे ऐप को अपडेट करने का स्थान रोकना पड़ता है ।
samthui7

5
if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
    [self.locationManager setAllowsBackgroundLocationUpdates:YES];
}

IOS 9 से बैकग्राउंड लोकेशन ट्रैकिंग के लिए इसकी जरूरत है।


1
इससे मेरा दिन बच गया! iOS9 डिवाइस के साथ iOS8 परिनियोजन लक्ष्य का उपयोग करना
Yaro

4

मैंने xs2bush का अंतराल प्राप्त करने की विधि का उपयोग किया (उपयोग करना timeIntervalSinceDate) और उस पर थोड़ा विस्तार किया। मैं यह सुनिश्चित करना चाहता था कि मुझे आवश्यक सटीकता मिल रही थी जिसकी मुझे आवश्यकता थी और यह भी कि मैं जीपीएस को आवश्यकता से अधिक रेडियो पर रखकर बैटरी से नीचे नहीं चल रहा था।

मैं निम्नलिखित सेटिंग्स के साथ लगातार स्थान रखता हूं:

locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
locationManager.distanceFilter = 5;

यह बैटरी पर एक अपेक्षाकृत कम नाली है। जब मैं अपना अगला आवधिक स्थान प्राप्त करने के लिए तैयार होता हूं, तो मैं पहले यह देखने के लिए जांच करता हूं कि क्या स्थान मेरी वांछित सटीकता के भीतर है, यदि यह है, तो मैं स्थान का उपयोग करता हूं। यदि यह नहीं है, तो मैं इसके साथ सटीकता बढ़ाता हूं:

locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.distanceFilter = 0;

मेरा स्थान प्राप्त करें और फिर एक बार मेरे पास स्थान होने के बाद मैं बैटरी पर नाली को कम करने के लिए सटीकता को फिर से नीचे मोड़ देता हूं। मैंने इसका पूरा काम करने का नमूना लिखा है और मैंने स्थान डेटा एकत्र करने के लिए सर्वर साइड कोड के लिए स्रोत भी लिखा है, इसे डेटाबेस में संग्रहित किया है और उपयोगकर्ताओं को वास्तविक समय में जीपीएस डेटा देखने या पूर्व में संग्रहीत मार्गों को पुनः प्राप्त करने और देखने की अनुमति दी है। मेरे पास आईओएस, एंड्रॉइड, विंडोज़ फोन और जावा के लिए क्लाइंट हैं। सभी क्लाइंट मूल रूप से लिखे गए हैं और वे सभी पृष्ठभूमि में ठीक से काम करते हैं। परियोजना एमआईटी लाइसेंस प्राप्त है।

IOS प्रोजेक्ट को iOS 6 के बेस SDK का उपयोग करके iOS 6 के लिए लक्षित किया गया है। आप यहां कोड प्राप्त कर सकते हैं

यदि आप इसके साथ कोई समस्या देखते हैं तो कृपया github पर एक समस्या दर्ज करें। धन्यवाद।


मैंने आपके समाधान की कोशिश की, लेकिन काम नहीं कर रहा है ... जब ऐप बैकग्राउंड में जाता है, तब भी सटीकता बढ़ाने के बावजूद, ऐप को मेरे मामले में didUpdateToLocation मेथड नहीं मिलता है
हार्दिक दरजी

@ हार्दिकदार्जी महत्वपूर्ण प्रश्न क्या तुम चल रहे हो? यदि नहीं, तो स्थान अपडेट रुक सकते हैं। टहलने या ड्राइव के लिए अपने फोन को बाहर निकालने की कोशिश करें और देखें कि क्या यह ठीक करता है।
निकोक्स

अपनी त्वरित प्रतिक्रिया के लिए धन्यवाद। लेकिन मुझे हर 2 मिनट में लोकेशन अपडेट चाहिए, बिना इस बात की परवाह किए कि मेरा फोन घूम रहा है या नहीं। इस परिदृश्य में didUpdateToLocation पद्धति को नहीं कहा जाता है। मैं यहाँ देख रहा हूँ: मुझे हर n मिनट में स्थान अपडेट कैसे मिलेगा !!!
हार्दिक दरजी

टाइमलाइन सेट करने का प्रयास करें ।InIneconds to 120 और इस लाइन को अनइंस्टॉल करें: locationManager.pausesLocationUpdatesAutomatically = NO;
निकॉक्स

1
क्या उपरोक्त टिप्पणी में आपके द्वारा पोस्ट किया गया समाधान बैटरी जीवन को मारता है, या आप अभी भी उसके लिए कुछ अनुकूलन कर रहे हैं?
समर

2

ऐसा लगता है कि stopUpdatingLocation पृष्ठभूमि चौकी टाइमर को ट्रिगर करता है, इसलिए मैंने इसे didUpdateLocation में बदल दिया:

     [self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
     [self.locationManager setDistanceFilter:99999];

जो जीपीएस को प्रभावी ढंग से बिजली देने के लिए प्रकट होता है। तब NSTimer पृष्ठभूमि के लिए चयनकर्ता बन जाता है:

- (void) changeAccuracy {
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager setDistanceFilter:kCLDistanceFilterNone];
}

मैं जो कुछ भी कर रहा हूं वह हर कुछ मिनटों में उच्च सटीकता प्राप्त करने के लिए समय-समय पर सटीकता से टॉगल कर रहा है और क्योंकि लोकेशन मैनजर को रोका नहीं गया है, बैकग्राउंड टाइम रीमेकिंग अपने अधिकतम मूल्य पर रहता है। इसने मेरे डिवाइस पर बैटरी की खपत को ~ 10% प्रति घंटे (निरंतर kCLLocationAccuracyBest के साथ) से घटाकर ~ 2% प्रति घंटा कर दिया है


2

एक कोकोपोड APScheduledLocationManager है जो वांछित स्थान सटीकता के साथ हर n सेकंड में पृष्ठभूमि स्थान अपडेट प्राप्त करने की अनुमति देता है ।

let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)

रिपॉजिटरी में स्विफ्ट 3 में लिखा एक उदाहरण ऐप भी है।


क्या आपके पास ऑब्जेक्टिव c में ऐसा कुछ है?
मोक्षार्थ

1

IOS 9 और वॉचओएस 2.0 में CLLocationManager पर एक नया तरीका है जो आपको वर्तमान स्थान का अनुरोध करने की अनुमति देता है: CLLocationManager: requestLocation ()। यह तुरंत पूरा होता है और फिर CLLocationManager प्रतिनिधि को स्थान लौटाता है।

अब आप इस विधि के साथ हर मिनट एक स्थान का अनुरोध करने के लिए एक NSTimer का उपयोग कर सकते हैं और startUpdatingLocation और stopUpdatingLocation विधियों के साथ काम नहीं करना है।

हालाँकि यदि आप अंतिम स्थान से X मीटर के परिवर्तन के आधार पर स्थानों को कैप्चर करना चाहते हैं, तो बस CLLocationManger की दूरी का गुण निर्धारित करें और X call startUpdatingLocation () को कॉल करें।


-1

संलग्न एक स्विफ्ट समाधान में आधारित है:

Info.plist App registers for location updatesमें परिभाषित करें

स्थान प्रबंधक को हर समय चालू रखें

(5 सेकंड के लिए स्थान पाने के लिए) और बैटरी की निकासी से बचने के लिए प्रतीक्षा अवधि के बाकी हिस्सों के kCLLocationAccuracyबीच स्विच करेंBestForNavigationThreeKilometers

यह उदाहरण फ़ोरग्राउंड में हर 1 मिनट और बैकग्राउंड में हर 15 मिनट में स्थान अपडेट करता है।

IOS 7 डिवाइस में चल रहे Xcode 6 Beta 6 के साथ उदाहरण ठीक काम करता है।

ऐप डेलिगेट में (mapView मैप व्यू कंट्रोलर का एक वैकल्पिक संकेत है)

func applicationDidBecomeActive(application: UIApplication!) {
    if appLaunched! == false { // Reference to mapView used to limit one location update per timer cycle
        appLaunched = true
        var appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        var window = appDelegate.window
        var tabBar = window?.rootViewController as UITabBarController
        var navCon = tabBar.viewControllers[0] as UINavigationController
        mapView = navCon.topViewController as? MapViewController
    }
    self.startInitialPeriodWithTimeInterval(60.0)
}

func applicationDidEnterBackground(application: UIApplication!) {
    self.startInitialPeriodWithTimeInterval(15 * 60.0)
}

func startInitialPeriodWithTimeInterval(timeInterval: NSTimeInterval) {
    timer?.invalidate() // reset timer
    locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
    timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("getFirstLocationUpdate:"), userInfo: timeInterval, repeats: false)
}

func getFirstLocationUpdate(sender: NSTimer) {
    let timeInterval = sender.userInfo as Double
    timer?.invalidate()
    mapView?.canReportLocation = true
    timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: Selector("waitForTimer:"), userInfo: timeInterval, repeats: true)
}

func waitForTimer(sender: NSTimer) {
    let time = sender.userInfo as Double
    locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
    finalTimer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("getLocationUpdate"), userInfo: nil, repeats: false)
}

func getLocationUpdate() {
    finalTimer?.invalidate()
    mapView?.canReportLocation = true
}

MapView में (स्थान प्रबंधक ऑब्जेक्ट को AppDelegate में इंगित करता है)

override func viewDidLoad() {
    super.viewDidLoad()
    var appDelegate = UIApplication.sharedApplication().delegate! as AppDelegate
    locationManager = appDelegate.locationManager!
    locationManager.delegate = self
    canReportLocation = true
}

  func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        if canReportLocation! {
            canReportLocation = false
            locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
        } else {
            //println("Ignore location update")
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.