了解iOS中的iBeacons:didDetermineState和didEnterRegion事件

时间:2015-10-08 08:41:00

标签: ios objective-c iphone cllocationmanager ibeacon

第一部分:

我已经编写了以下代码来监控iBeacons。我想检测 didEnterRegion didExitRegion 事件。但它永远不会发生。您能否看一下代码并提出可能缺少的内容?

我使用Apple AirLocate sample code将一台设备配置为iBeacon,并执行以下步骤来测试我的代码:

步骤:

  1. 在设备B上编译并执行AirLocate示例代码
  2. 在设备A上编译并执行此代码
  3. 设备B中的
  4. 使用AirLocate app将设备配置为iBeacon,选择以下UUID:“74278BDA-B644-4520-8F0C-720EAF059935”
  5. 结果:

    • 州内消息

    预期结果:

    • 州内消息
    • 确实进入了区域

    为什么?

    这些是我的plist条目:

    enter image description here

    代码:

    #import "BeaconMonitoring.h"
    
    @implementation BeaconMonitoring
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            self.locationManager = [[CLLocationManager alloc] init];
    
            if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
                [self.locationManager requestAlwaysAuthorization];
            }
    
            self.locationManager.delegate = self;
            self.locationManager.pausesLocationUpdatesAutomatically = NO;
    
            self.monitoredRegions = [[NSMutableArray alloc] initWithCapacity:10];
        }
        return self;
    }
    
    - (void) startRangingForBeacons{
        NSLog(@"in startRangingForBeacons");
        [self.locationManager startUpdatingLocation];
        [self startMonitoringForRegion:[[NSUUID alloc] initWithUUIDString:@"74278BDA-B644-4520-8F0C-720EAF059935"] :@"b"];
    }
    
    - (void) startMonitoringForRegion:(NSUUID*)beaconUUID :(NSString*)regionIdentifier{
       /**
        Alternatively:
        CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:@"xxxx"
        major:10
        minor:20
        identifier:@"name"]
        **/
    
        // Override point for customization after application launch.
        CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:beaconUUID identifier:regionIdentifier];
    
        beaconRegion.notifyEntryStateOnDisplay = NO;
        beaconRegion.notifyOnEntry = YES;
        beaconRegion.notifyOnExit  = YES;
    
        [self.locationManager startMonitoringForRegion:beaconRegion];
        [self.locationManager startRangingBeaconsInRegion:beaconRegion];
        [self.monitoredRegions addObject:beaconRegion];
    }
    
    - (void) stopRangingForbeacons{
        NSLog(@"in stopRangingForbeacons");
        [self.locationManager stopUpdatingLocation];
    
        for (int i=0; i < [self.monitoredRegions count]; i++) {
            NSObject * object = [self.monitoredRegions objectAtIndex:i];
    
            if ([object isKindOfClass:[CLBeaconRegion class]]) {
                CLBeaconRegion * region = (CLBeaconRegion*)object;
                [self.locationManager stopMonitoringForRegion:region];
                [self.locationManager stopRangingBeaconsInRegion:region];
            }
            else{
                NSLog(@"Serious error, should never happen!");
            }
        }
    }
    
    
    #pragma CLLocationManagerDelegate
    
    -(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
        [manager startRangingBeaconsInRegion:(CLBeaconRegion*)region];
        [self.locationManager startUpdatingLocation];
        NSLog(@"You entered the region.");
    }
    
    -(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
        [manager stopRangingBeaconsInRegion:(CLBeaconRegion*)region];
        [self.locationManager stopUpdatingLocation];
    
    
        NSDictionary * notificationData = @{ @"value" : @"exitedRegion"};
        [[NSNotificationCenter defaultCenter] postNotificationName:@"dataUpdate" object:nil userInfo:notificationData];
    
        NSLog(@"You exited the region.");
        // [self sendLocalNotificationWithMessage:@"You exited the region."];
    }
    
    - (void) locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
    {
        NSLog(@"did determine state");
    
        switch (state) {
            case CLRegionStateInside:
                NSLog(@"state inside");
                break;
            case CLRegionStateOutside:
                NSLog(@"state outside");
                break;
            case CLRegionStateUnknown:
                NSLog(@"state unknown");
                break;
            default:
                NSLog(@"Default case: Region unknown");
                break;
        }
    }
    
    -(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
    
        NSLog(@"Did range %lu beacon in region %@", (unsigned long)[beacons count], region.identifier);
    
        NSString * visibleInformation = [NSString stringWithFormat:@"(%lu)", (unsigned long)[beacons count]];
    
        for (int i=0; i<[beacons count]; i++) {
            CLBeacon *beacon = [beacons objectAtIndex:i];
    
            if ([beacons count] == 1) {
                NSNumber * distance =  [NSNumber numberWithFloat:beacon.accuracy];
                visibleInformation = [NSString stringWithFormat:@"%i-%i is %f", beacon.major.intValue, beacon.minor.intValue, distance.doubleValue];
            }
            else{
                visibleInformation = [visibleInformation stringByAppendingString:[NSString stringWithFormat:@" %i-%i ", beacon.major.intValue, beacon.minor.intValue]];
            }
        }
    }
    
    @end
    

    第二部分:

    我查看了 AirLocate 源代码,了解是否有必要在内部消息状态中触发以使监视正常工作。但是我发现** didDetermineState **方法是在AppDelegate中实现的。

    为什么?

    - (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
    {
        /*
         A user can transition in or out of a region while the application is not running. When this happens CoreLocation will launch the application momentarily, call this delegate method and we will let the user know via a local notification.
         */
        UILocalNotification *notification = [[UILocalNotification alloc] init];
    
        if(state == CLRegionStateInside)
        {
            notification.alertBody = NSLocalizedString(@"You're inside the region", @"");
        }
        else if(state == CLRegionStateOutside)
        {
            notification.alertBody = NSLocalizedString(@"You're outside the region", @"");
        }
        else
        {
            return;
        }
    
        /*
         If the application is in the foreground, it will get a callback to application:didReceiveLocalNotification:.
         If it's not, iOS will display the notification to the user.
         */
        [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
    }
    

1 个答案:

答案 0 :(得分:1)

假设:R =由B制作并由A听取的区域

案例1

如果A在B之前启动:

  1. app A应告诉您确定区域R =外部
  2. 的状态
  3. app A应该运行didEnter Region R
  4. 案例2

    如果A在B之后开始实际启动:

    1. 它应该只运行determineState Region R = inside
    2. 结束了。这里没有2,因为它永远不会进入范围。它是从里面开始的