简体   繁体   中英

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
    }



}

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.

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.

You should be able to send a request to a web service, but you won't be able to reliably receive the response. Your app only stays awake for about 5 seconds after a beacon notification.

It MIGHT be possible to request background time to complete your network transaction - I'm not an expert on processing from the background.

You need the user to unlock the phone in order to do anything with the UI anyway. Why not have your server send a push notification in response to your message? That accomplishes all your goals.

If you really need the response of your web service call to display the notification, then @duncan-c is right that it may not answer in the 5 seconds or so before your app goes back to sleep.

Another alternative is to send a push notification to your iOS device from your web service. The advantage of this approach is it will be delivered to your phone even if your app has gone back to sleep. The disadvantage of this approach is that delivery of push notifications is not immediate -- they sometimes take a few minutes to arrive. You have to decide if that is workable for your use case.

i try Something to range beacon in BackGrounds it works for me and i hope it will work for you

first Step:add this code in application didFinishLaunchingWithOptions

 _locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[_locationManager setDistanceFilter:kCLDistanceFilterNone];
[_locationManager requestAlwaysAuthorization];


    _locationRegion=[[CLBeaconRegion alloc]
                     initWithProximityUUID:BLUE_SCENE
                     identifier:@"EstimoteSampleRegion"];

[_locationRegion setNotifyOnEntry:YES];
[_locationRegion setNotifyOnExit:YES];
[_locationRegion setNotifyEntryStateOnDisplay:YES];


[_locationManager startMonitoringForRegion:_locationRegion];

second Step : also add this code again in this function

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

and in this Function

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{

what i found that your app will wake up in a background for just a secs and enter this function didDetermine state so in this sec you call ranging for beacon Function and implement it's delegate in AppDelegate

if you need a help just tell me

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM