Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delayed background task sometimes runs only when app returns to foreground

I am writing an iOS app for scanning barcodes at participating retail locations, where that location would donate to charity on the customer's behalf after the customer scans a QRcode printed on the receipt.

I would like to send a local notification to a user if they are in a participating location for 60 seconds or longer, reminding them to scan any receipts they might get from purchases they made there.

My issue is that I would like to delay a call for 60 seconds when a user enters a region - if after those 60 seconds they are still in that region fire off the local notification - however, sometimes that call to sendLocalNotification within stillInRegion doesn't fire until the app returns to the foreground. I believe this has to do with the thread sometimes ending before the delay is up, but I am not sure. I have tried about every approach I could find on stackoverflow and elsewhere (blocks, nstimers, etc.) but to no avail. Any ideas about how to better approach this problem?

- (void) sendLocalNotification:(NSString *)regionId {
NSLog(@"we entered %@ and we're currently in %@", regionId, self.currentRegionId);
if ([regionId isEqualToString:self.currentRegionId]) {// if we're still in the region, send a local notification
    UILocalNotification *localNotif = [[UILocalNotification alloc] init];
    if (localNotif == nil) return;
    NSDate *fireTime = [[NSDate date] addTimeInterval:2]; // adds 2 secs
    localNotif.fireDate = fireTime;
    localNotif.alertBody = [NSString stringWithFormat:@"Did you just visit %@? If so, don't forget to scan your receipt!", regionId];
    localNotif.applicationIconBadgeNumber = [UIApplication sharedApplication].applicationIconBadgeNumber+1;
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
    [localNotif release];
}
}

- (void) stillInRegion:(CLRegion *)region {

NSLog(@"did enter region: %@", region.identifier);

[self performSelector:@selector(sendLocalNotification:) withObject:region.identifier afterDelay:60];
}

- (void) locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
if (self.didLaunchForRegionUpdate) {
    NSString *path = [DGGeofencingHelper applicationDocumentsDirectory];
    NSString *finalPath = [path stringByAppendingPathComponent:@"notifications.dg"];
    NSMutableArray *updates = [NSMutableArray arrayWithContentsOfFile:finalPath];

    if (!updates) {
        updates = [NSMutableArray array];
    }

    NSMutableDictionary *update = [NSMutableDictionary dictionary];

    [update setObject:region.identifier forKey:@"fid"];
    [update setObject:[NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]] forKey:@"timestamp"];
    [update setObject:@"enter" forKey:@"status"];

    [updates addObject:update];

    [updates writeToFile:finalPath atomically:YES];
} else {
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setObject:@"enter" forKey:@"status"];
    [dict setObject:region.identifier forKey:@"fid"];
    NSString *jsStatement = [NSString stringWithFormat:@"DGGeofencing.regionMonitorUpdate(%@);", [dict JSONString]];
    [self.webView stringByEvaluatingJavaScriptFromString:jsStatement];
}
self.currentRegionId = region.identifier;
self.cRegionEnterTime =[NSDate date];
[self stillInRegion:region];
}
like image 240
James Dickman Avatar asked Jan 29 '26 05:01

James Dickman


1 Answers

Are the locationManager:didEnterRegion being called in foreground and then your application goes to background? I'm not very clear about when you are calling those methods, but you could try creating a background task as follows:

  1. Add a property of type NSUInteger called, for example, bgTaskIdentifier, to store your background task identifier.
  2. Before your call to [self stillInRegion:region]; add the following code:

    bgTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{}];

  3. It should call your stillInRegion method, and continues even if you go to the background, so the delay should continue counting on!. Finally, you should end your background task. To do this, add the following line at the end of your sendLocalNotification method, after the if block:

    [[UIApplication sharedApplication] endBackgroundTask:bgTaskIdentifier];

Just let us know if that was helpful! and excuse me for my poor english!

Have a good day!

like image 193
lucaslt89 Avatar answered Jan 31 '26 20:01

lucaslt89



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!