Search code examples
iosibeacon

How to suspend beacon's notification while in range?


I'm quite a newbie in iOS development and I start working with iBeacon since a couple of weeks. I'm currently developing an app that delivers a coupon to the user while he/she enters a beacon's range (e.g. a store section). This coupon has to be delivered only once in a while, but the user may most likely stay inside the beacon's range even after the delivery is done so I need the app to suspend "listening" to that particular beacon for a fixed amount of time, let's say 30 mins.

This is my implementation of the locationManager:didRangeBeacons:inRegion::

- (void)locationManager:(CLLocationManager *)manager
        didRangeBeacons:(NSArray *)beacons
               inRegion:(CLBeaconRegion *)region {
    if (foundBeacons.count == 0) {
        for (CLBeacon *filterBeacon in beacons) {
            // If a beacon is located near the device and its major and minor values are equal to some constants
            if (((filterBeacon.proximity == CLProximityImmediate) || (filterBeacon.proximity == CLProximityNear)) && ([filterBeacon.major isEqualToNumber:[NSNumber numberWithInt:MAJOR]]) && ([filterBeacon.minor isEqualToNumber:[NSNumber numberWithInt:MINOR]]))
                // Registers the beacon to the list of recognized beacons
                [foundBeacons addObject:filterBeacon];
        }
    }
    // Did some beacon get found?
    if (foundBeacons.count > 0) {
        // Takes first beacon of the list
        beacon = [foundBeacons firstObject];

        if (([beacon.major isEqualToNumber:[NSNumber numberWithInt:MAJOR]]) && ([beacon.minor isEqualToNumber:[NSNumber numberWithInt:MINOR]])) {
            // Plays beep sound
            AudioServicesPlaySystemSound(soundFileObject);

            if (self.delegate) {
                // Performs actions related to the beacon (i.e. delivers a coupon)
                [self.delegate didFoundBeacon:self];
            }
            self.locationManager = nil;
        }
        [foundBeacons removeObjectAtIndex:0];
        beacon = nil;
    }
}

How can I add some timer or something related to make the app ignore the beacon for a while?


Solution

  • A common technique is to keep a data structure that tells you when you last took action on a beacon, and then avoid taking action again if enough time has not passed since you last did so.

    The following example shows how you can add a 10 minute (600 second) filter on repeating beacon events.

    // Declare these in your class
    #define MINIMUM_ACTION_INTERVAL_SECONDS 600
    NSMutableDictionary *_lastBeaconActionTimes;
    
    ...
    
    // Initialize in your class constructor or initialize method
    _lastBeaconActionTimes = [[NSMutableDictionary alloc] init];
    
    ...
    
    // Add the following before you take action on the beacon
    
    NSDate *now = [[NSDate alloc] init];
    NSString *key = [NSString stringWithFormat:@"%@ %@ %@", [beacon.proximityUUID UUIDString], beacon.major, beacon.minor];
    NSDate *lastBeaconActionTime = [_lastBeaconActionTimes objectForKey:key];
    if (lastBeaconActionTime == Nil || [now timeIntervalSinceDate:lastBeaconActionTime] > MINIMUM_ACTION_INTERVAL_SECONDS) {
      [_lastBeaconActionTimes setObject:now forKey:key];
    
      // Add your code to take action here
    
    }