【问题标题】:Reacting to multiple iBeacons对多个 iBeacon 做出反应
【发布时间】:2015-07-30 15:34:06
【问题描述】:

我已经在 iBeacons 上玩了几个星期了,如果可以从同一个视图控制器监视两个信标,我很想知道。

例如,到目前为止,我已经制作了一个具有三个单独视图的应用程序,每个视图都会对单独的信标做出反应,根据范围改变内容并触发音乐和视频等动态内容。所有这些视图都是相同的布局,所以如果我可以更改它,我会很痛苦,所以我有一个视图控制器可以根据我附近的信标更改内容,而不必更改视图。

这会更有意义,因为您只能监视一个,这意味着当 segue 触发并且正在监视新信标时,如果您移回第一个信标,它不会在您进入第一个信标时返回该视图接近。

我确信有一种方法可以做到这一点,因为美国的苹果商店正在使用信标来触发促销等,并且他们没有问题地依赖最近的信标。

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

@interface ExhibitsViewController : UIViewController <CLLocationManagerDelegate,UIScrollViewDelegate>
{
CLBeacon *beacon;
}

@property (strong, nonatomic) CLBeaconRegion *beaconRegion;
@property (strong, nonatomic) CLLocationManager *locationManager

@end

这是我的头文件中定义信标、beaconRegion 和 locationManager 的代码。

#import "MultipleBeaconsViewController.h"

@interface MultipleBeaconsViewController ()  
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UILabel *rangeLabel;
@property (weak, nonatomic) IBOutlet UILabel *uuidLabel;
@end

@implementation MultipleBeaconsViewController

NSUUID *iBeacon1uuid;
NSUUID *iBeacon2uuid;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
    // Custom initialization
}
return self;
}

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self initRegion];

[self locationManager:self.locationManager didStartMonitoringForRegion:self.iBeacon1Region];
[self locationManager:self.locationManager didStartMonitoringForRegion:self.iBeacon2Region];

}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

- (void)initRegion {

iBeacon1uuid = [[NSUUID alloc] initWithUUIDString:@"11111111-2222-3333-4444-555555555555"];
_iBeacon1Region = [[CLBeaconRegion alloc] initWithProximityUUID:iBeacon1uuid identifier:@"com.private.Gallery"];
_iBeacon1Region.notifyOnEntry = YES;
_iBeacon1Region.notifyOnExit = YES;

// launch app when display is turned on and inside region
_iBeacon1Region.notifyEntryStateOnDisplay = YES;

if ([CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]])
{
    [_locationManager startMonitoringForRegion:_iBeacon1Region];
    [_locationManager startRangingBeaconsInRegion:_iBeacon1Region];
}

iBeacon2uuid = [[NSUUID alloc] initWithUUIDString:@"55555555-4444-3333-2222-111111111111"];
_iBeacon2Region = [[CLBeaconRegion alloc] initWithProximityUUID:iBeacon2uuid identifier:@"com.private.Gallery"];
_iBeacon2Region.notifyOnEntry = YES;
_iBeacon2Region.notifyOnExit = YES;

// launch app when display is turned on and inside region
_iBeacon2Region.notifyEntryStateOnDisplay = YES;

if ([CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]])
{
    [_locationManager startMonitoringForRegion:_iBeacon2Region];
    [_locationManager startRangingBeaconsInRegion:_iBeacon2Region];
}
}

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

if ([region isKindOfClass:[CLBeaconRegion class]])
{

    CLBeaconRegion *beaconRegion = (CLBeaconRegion *)region;

    if ([beaconRegion.proximityUUID isEqual: iBeacon1uuid])
    {
        _titleLabel.text = @"Beacon 1 proximity entered";

    }
    else if ([beaconRegion.proximityUUID isEqual: iBeacon2uuid])
    {
        _titleLabel.text = @"Beacon 2 proximity entered";
    }

}

}

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

if ([region isKindOfClass:[CLBeaconRegion class]]) {

    CLBeaconRegion *beaconRegion = (CLBeaconRegion *)region;


    if ([beaconRegion.proximityUUID isEqual: iBeacon1uuid])
    {

        _titleLabel.text = @"Beacon 1 proximity exited";
    }
    else if ([beaconRegion.proximityUUID isEqual: iBeacon2uuid])
    {

        _titleLabel.text = @"Beacon 2 proximity exited";
    }

}
}

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

if ([region isKindOfClass:[CLBeaconRegion class]]) {

    for (CLBeacon *beacon in beacons)
    {

        NSString *beaconID = [beacons objectAtIndex:0];
        NSLog(@"%@",beaconID);

        if ([region.proximityUUID isEqual:iBeacon1uuid])
        {

            if (beacon.accuracy >=0.000001 && beacon.accuracy <=0.500000)
            {
            _titleLabel.text = @"Beacon 1";
            _rangeLabel.text = [NSString stringWithFormat:@"%f",beacon.accuracy];
            _uuidLabel.text = [NSString stringWithFormat:@"%@", beacon.proximityUUID];
            }
        }
        else if ([region.proximityUUID isEqual:iBeacon2uuid])
        {
            if (beacon.accuracy >=0.000001 && beacon.accuracy <=0.500000) {
                _titleLabel.text = @"Beacon 2";
                _rangeLabel.text = [NSString stringWithFormat:@"%f",beacon.accuracy];
                _uuidLabel.text = [NSString stringWithFormat:@"%@", beacon.proximityUUID];
            }
            else
            {

            }
        }

    }
}
}

这是我在测量信标的实现文件中的代码。

【问题讨论】:

    标签: ios objective-c bluetooth-lowenergy ibeacon


    【解决方案1】:

    是的,你可以。要做到这一点,您不必保留 self.beaconRegion 属性,您只需创建任意数量的对象并启动监视器并开始对其进行测距,例如我就是这样做的:

    //Reion 1

    CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:major minor:minor identifier:identifier];
    region.notifyOnEntry = YES;
    region.notifyOnExit = YES;
    // launch app when display is turned on and inside region
    region.notifyEntryStateOnDisplay = YES;
    
    if ([CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]])
    {
        [_locationManager startMonitoringForRegion:region];
        [_locationManager startRangingBeaconsInRegion:region];
    }
    

    //区域2

       CLBeaconRegion *region2 = [[CLBeaconRegion alloc] initWithProximityUUID:uuid2 major:major2 minor:minor2 identifier:identifier2];
        region2.notifyOnEntry = YES;
        region2.notifyOnExit = YES;
        // launch app when display is turned on and inside region
        region2.notifyEntryStateOnDisplay = YES;
    
        if ([CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]])
        {
            [_locationManager startMonitoringForRegion:region2];
            [_locationManager startRangingBeaconsInRegion:region2];
        }
    

    //等等

    之后,在每个 self.locationManager 委托方法中确保您拥有哪个信标,例如:

    - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    
        if ([region isKindOfClass:[CLBeaconRegion class]]) {
            CLBeaconRegion *beaconRegion = (CLBeaconRegion *)region;
    
            // Find out which beacon you have,
            // I check just UUID but maybe your beacons have the same uuid but major, minor are difference so you need to check minor/major as well
            if ([beaconRegion.proximityUUID isEqual:UUIDFIRST]) {
    
                //Do some stuff
            }
        }
    }
    

    如果您想查看最近使用的信标:

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

    枚举信标数组:

    if ([region isKindOfClass:[CLBeaconRegion class]]) {
    
            for (CLBeacon *beacon in beacons) { // 1
                // do the checking which beacon you have
                if ([beaconRegion.proximityUUID isEqual:UUIDFIRST]) { // 2
    
                }
    
                     // check beacon.accuracy property this should gives you distance in meters meters
                     //beacon.accuracy // 3
                }
            }
        }
    

    // 扩展

    如果您在两个(或更多)信标范围内,则信标将在信标数组中传递给您。通过调用 [beacons lastObject] 你只会得到一个信标。您需要做的是枚举(遍历数组中的所有对象)在我上面的代码中查看 no 1(我对其进行了一些编辑)并查看您拥有的信标(2),然后比较距离(3)和值较小的那个是最近的。

    【讨论】:

    • 您好,我尝试使用它来解决问题,我现在可以看到第二个信标,但即使在第一个信标旁边,该应用程序也只能对第二个信标进行范围。我的代码中唯一的不同是我仍在使用“iBeacon = [beacons lastObject];。你能向我解释你在写“枚举信标数组”时的意思吗
    • 您好,很抱歉再次打扰您仍然有问题,应用程序只找到第二个信标,我已经使用 NSLog 检查了数组中的项目,发现它只找到一个信标,如果我当时注释掉了它会找到第一个信标的第二个区域,但这是我可以让它找到第一个信标的唯一方法。我已经编辑了我的原始帖子以包含新代码,以防我做错了什么
    • 替换你的日志 (NSLog(@"%@",beaconID);) 在 didRangeBeacons: 方法到 NSLog(@"UUID: %@", beacon.proximityUUID.UUIDString);你应该会看到两个信标
    • 我已经做到了,我仍然只能看到一个信标,一旦我注释掉“startMonitoring”和“startRanging”,就可以看到第一个信标。
    • 将标识符更改为范围 1 和范围 2 不同。
    【解决方案2】:

    一个 UUID 可以在许多 iBeacon 上重复使用。每个信标都有一个主要和一个次要数字来区分每个信标。

    所以公司会购买单个 UUID,但是(占用商店),

    所有专业=1都在一楼:

    • minor 1 = 女装
    • 未成年人 2 = 男装

    专业2=二楼:

    • 未成年人 1 = 童装
    • 次要 2 = 鞋类

    ... 等等。当应用程序在商店中走动时,信标可以告诉它它们在哪里,并根据数据提供广告/视频。

    您在 didRangeBeacons 回调中检查这些值。我还相信一个应用程序可以同时监控多达 20 个区域,因此该回调中的 region 属性将包含不同的 UUID

    【讨论】:

    • 我在上面的代码中删除了我的代码,如您所见,信标的 UUID 完全不同,不幸的是我的老板是配置信标并拒绝更改 UUID 的人,所以它们非常不同,所以我需要用完全不同的 UUID 监控两个
    • @DavidHare 好的,顺便说一句,你的老板应该改变它们。如果你要使用一种技术,你应该符合标准。除此之外,您的 for 循环是错误的。 for (CLBeacon *beacon in beacons) 在这里你有一个 for each 循环,其中beacon 将依次是指向每个对象的指针,但在第一行你总是拉出数组中的第一个信标。您正在做的是在同一个对象上多次运行相同的代码,要么使用带有索引的 for 循环,要么更新您的代码以使用 beacon 而不是将其拉出数组
    • @DavidHare - 只要您只需要同时对一个非常小的数字进行建模,就可以使用不同的区域 UUID,但它不能扩展,因为 iOS 对可以同时监控的数字设置了下限.因此,您的组织需要在大规模部署之前更改其分配做法。
    • @ChrisStratton - 我知道这一点,信标只用于应用程序一个下午,这就是为什么我的老板不希望更改 UUID,因为他们将返回他们之后的职位。
    【解决方案3】:

    中提供的标识符
    [[CLBeaconRegion alloc] initWithProximityUUID:iBeacon1uuid identifier:@"com.private.Gallery"]; 
    

    您监控的每个信标都必须不同。

    在你的情况下,它们都是@"com.private.Gallery"

    【讨论】:

      猜你喜欢
      • 2017-12-16
      • 2015-12-29
      • 1970-01-01
      • 2021-02-18
      • 2017-11-08
      • 2017-12-25
      • 2022-12-24
      • 2015-07-19
      • 1970-01-01
      相关资源
      最近更新 更多