Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ranging iOS beacons in background

I know that the main purposes of the

-(void)locationManager:(CLLocationManager*)manager
       didRangeBeacons:(NSArray*)beacons
              inRegion:(CLBeaconRegion*)region

is to work while the app in foreground.

While in background,

- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region

is used to detect beacons but with not as much information as wanted (minor and major ids from CLBeacons to provide contextual information).

I know that delegate methods from the CLLocationManager allow to run briefly code in background.

Is it possible to do something like that : - start briefly to range beacons in background when entering a region - call a webservice in background according to minor/major ids - dispatch UILocalNotification configured with the return result of the webservice

- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region
{

    if (![region isKindOfClass:[CLBeaconRegion class]]) return;


    [locationManager startRangingBeaconsInRegion:(CLBeaconRegion*)region];

}

and then :

-(void)locationManager:(CLLocationManager*)manager
       didRangeBeacons:(NSArray*)beacons
              inRegion:(CLBeaconRegion*)region
{

    if (beacons.count == 0) return;

    CLBeacon *foundBeacon = [sortedBeacons firstObject];

    // DO STUFF IN BACKGROUND
    if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive){
        //Call for a webservice according to minor /major

        //Dispatch contextual notification
        // ^success(...)
        UILocalNotification * theNotification = [[UILocalNotification alloc] init];
        theNotification.alertBody = [NSString stringWithFormat:@""];

        theNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1];

        [[UIApplication sharedApplication] scheduleLocalNotification:theNotification];


    }
    else{   //DO STUFF IN FOREGROUND
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"proximity"
                                                                       ascending:YES];
        NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"accuracy"
                                                                        ascending:YES];

        NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor,sortDescriptor2];
        NSArray *sortedBeacons = [beacons sortedArrayUsingDescriptors:sortDescriptors];
        //determine which beacon will be used to trigger foreground event
    }



}
like image 487
Romain Dorange Avatar asked Jan 17 '14 14:01

Romain Dorange


People also ask

What is the range of iBeacon?

The maximum range of an iBeacon transmission will depend on the location and placement, obstructions in the environment and where the device is being stored (e.g. in a leather handbag or with a thick case). Standard beacons have an approximate range of 70 meters. Long range beacons can reach up to 450 meters.

Can Iphone act as beacon?

To broadcast your beacon's identity from an iOS device, use the Core Bluetooth framework to configure the iOS device as a Bluetooth peripheral. When configured as a peripheral, your iOS device broadcasts its beacon information out to other devices using the Bluetooth hardware.

Can beacons access data on your phone?

Beacons themselves don't collect any data. They do not send marketing messages to your phone. They broadcast location marks that your phone and apps using your phone can take advantage of to understand more precisely where you are.

Can beacons work without app?

Summary: For installations with regular beacons (an iBeacon is a type of beacon) then you cannot do much without an app, as you cannot interact with users (even after the additions from Eddystone).


2 Answers

I have experienced exactly same scenario. I have used below pattern:

// start background task
- (void)beginBackgroundTask {
    if (self.backgroundTask != UIBackgroundTaskInvalid) {
        [self endBackgroundTask];
    }

    self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [self endBackgroundTask];
    }];
}

// end background task
- (void)endBackgroundTask {
    if (self.backgroundTask != UIBackgroundTaskInvalid) {
        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
    }
    self.backgroundTask = UIBackgroundTaskInvalid;
}

These are conventional methods I have used to mark/unmark background tasks like calling web service.

Here are some using patterns of these:

[self beginBackgroundTask];

[[MySessionManager sharedInstance] POST:MoteList parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
    // process the response

    [self endBackgroundTask];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
    // error handling
}];

By the way, this background task time period is limited to 3mins around.

There are also another option to do background task for unlimited time period: That's to use multitasking API supported by NSURLSession since iOS 7. But it can be just used for download/upload tasks. If you need to do POST request, the server response should be downloadable json/xml data. The app should download that into a file and parse programmatically.

I hope this will help you.

like image 101
Zheng Huiying Avatar answered Sep 21 '22 14:09

Zheng Huiying


Answering your original question: is it possible to range while in background mode? The answer is yes, but you should stop it as soon as possible. iOS will stop you anyway, but keeping the ranging on will drain battery and it won't make sense.

I have the same problem too.

  1. Identify major/minor once in a region.
  2. Call a web service for updated info.
  3. While monitoring UUID, you can't detect major/minor change for overlapping beacons with the same UUID.

My solution goes like this:

  1. Monitor UUID
  2. Once in the region, stop monitoring and start ranging to identify nearest beacon.
  3. Once the nearest beacon is identified (sometimes after up to 3 calls to ranging delegate method), stop ranging.
  4. At his moment, also, determine if we're running in background mode (as you can see, I ranged and stopped ranging without asking the running mode).
  5. If we are in foreground mode: I show a top banner with beacon info. And schedule another ranging in 3 seconds to detect a new beacon.
  6. If we are in background mode: I send a local notification.
  7. In both modes I defer the web service call until the user acts on the notification. In the meantime I display a generic message for the beacon selected from a local dictionary: "Touch to see today's special promotions".

I know it sounds convoluted, and it is. It required in field testing to tune it. It satisfies the minimum requirement without depending on a fast internet connection.

I'll try the background tasks proposed by @ZhenHuiying, it sounds viable if the beacons are outdoors. In my case, the cell signal indoor is not reliable enough to show updated data while in background mode.

like image 28
Juan Valera Avatar answered Sep 19 '22 14:09

Juan Valera