蓝牙系列七、iBeacon

iBeacon简介

  • iBeacon起源:苹果在WWDC2013上正式推出了iBeacon,并且在iOS7设备商配置了该功能
  • iBeacon应用:苹果期望将其作为一种技术标准,这个标准允许移动App(包括iOS和Android设备)监听来自于iBeacon设备上的信号并作出响应.
  • iBeacon设备:配备有BLE通信功能,并使用BLE向周围发送自己特有的ID,移动设备上的App在接收到该ID后可以作出相应的反应.比如,我们在店铺里设置iBeacon发射器,便可以让应用接收到信息并将这一信息通知给服务器,服务器向我们的App返回与该店铺相关的产品或折扣信息.
  • 本质上讲,iBeacon技术允许App了解他们在某个局部范围内的位置,并向用户分发基于位置的超文本上下文内容.

简单开发流程

  • 1.初始化iBeacon的区域,以及区域管理者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#import <CoreLocation/CoreLocation.h>

@interface AppDelegate () <CLLocationManagerDelegate>

@property (nonatomic, strong) CLBeaconRegion *beaconRegion; /**< beacon区域 */

@property (nonatomic, strong) CLLocationManager *locMgr; /**< 位置管理者 */

@end

@implementation AppDelegate
#pragma mark - lazy
// 懒加载iBeacon区域
- (CLBeaconRegion *)beaconRegion
{
if (!_beaconRegion) {
NSUUID *proximityUUID = [[NSUUID alloc] initWithUUIDString:@"416C0120-5960-4280-A67C-A2A9BB166D0F"];
_beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:proximityUUID
identifier:@"brID"];
/**
* 一个App为了在特定商场提⾼高⽤用户体验,可⽤用使⽤用相同的proximity UUID来监听商场的所有商铺。当⽤用户进⼊入⼀一个商店时,App检测商铺的iBeacon设备并使⽤用major和 minor值来获取额外的信息,如⽤用户进⼊入哪家商店或⽤用户在商店的哪个区域(注意:虽然每个iBeacon都必须有⼀一个proximity UUID,但 major和minor的值是可选的)。
*/
}
return _beaconRegion;
}

// 懒加载创建地域管理者
- (CLLocationManager *)locMgr
{
if (!_locMgr) {
_locMgr = [[CLLocationManager alloc] init];
_locMgr.delegate = self;
}
return _locMgr;
}
  • 2.进入退出时候的操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#pragma mark - CLLocationManagerDelegate

// 开始监听
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);
}

// 进入监控的region区域
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
if ([region isEqual:self.beaconRegion]) {
// Start calculating ranges for beacons in the specified region.
// 开始计算beaconRegion区域内部的iBeacon设备数量,确定我们的设备与区域中的一个或多个iBeacon设备的相对距离,并在距离改变时被通知,触发代理 didRangeBeacons
[self.locMgr startRangingBeaconsInRegion:self.beaconRegion];

NSDictionary *info = [self.beaconRegion peripheralDataWithMeasuredPower:@0];
// 通知外设开启广播
[[NSNotificationCenter defaultCenter] postNotificationName:@"didEnterRegionNotification" object:nil userInfo:info];
}

}
// 退出监控的region区域
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
// 外设关闭广播
// 通知外设开启广播
[[NSNotificationCenter defaultCenter] postNotificationName:@"didExitRegionNotification" object:nil];
}

// 当指定Beacon区域的iBeacon设备进⼊入范围、离开范围或相对距离改变时,CLLocationManager对象调⽤用代理对象的 locationManager:didRangeBeacons:inRegion:
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons inRegion:(CLBeaconRegion *)region
{
// beacons表⽰示当前设备范围内的iBeacon。
// iBeacon的数组根据离设备的相对距离来排序,最近的在最前⾯面。
// 我们可以使⽤用这些对象中的信息来确定⽤用户离每个iBeacon设备的距离。 CLBeacon对象(数组元素)的proximity属性给出了(手机)到⼀一个beacon的相对距离
// 注意:iBeacon的排列依赖于检测到的BLE⽆无线信号的强度,以及这些信号受墙壁、门或其它物理实体的影响。当我们使⽤用iBeacon时需要考虑 这些影响因素。
if (beacons.count) {
for (NSInteger i = 0; i < beacons.count; i++) {
CLBeacon *beacon = beacons[i];
/**
* typedef NS_ENUM(NSInteger, CLProximity) {
CLProximityUnknown,
CLProximityImmediate,
CLProximityNear,
CLProximityFar
} NS_ENUM_AVAILABLE_IOS(7_0) __WATCHOS_PROHIBITED;
*/
if (beacon.proximity == CLProximityNear) {
NSLog(@"major = %@|| minor = %@", beacon.major, beacon.minor);

// 注意:当多个iBeacon设备广告了相同的proximityUUID, major和minor属性组合时,在locationManager:didRangeBeacons:inRegion:方法 中它们可能会有不同的距离与精度。建议每⼀一个beacon设备都是唯⼀一标识的。
}else
{

}
}
}

}

// 报错
- (void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region withError:(NSError *)error
{
NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);
}
  • 3.外设模式给它广播
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#import <CoreBluetooth/CoreBluetooth.h>

@interface ViewController () <CBPeripheralManagerDelegate>

@property (nonatomic, strong) CBPeripheralManager *pMgr; /**< 外设管理模式 */

@end

@implementation ViewController

// 懒加载创建
- (CBPeripheralManager *)pMgr
{
if (!_pMgr) {
//
_pMgr = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
}
return _pMgr;
}


- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 先初始化外设管理者
[self pMgr];

[[NSNotificationCenter defaultCenter] addObserverForName:@"didEnterRegionNotification"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * _Nonnull note) {
// 开始广播位置信息proximity UUID(及major或minor值)
if (self.pMgr.state == CBPeripheralManagerStatePoweredOn) {
//
[self.pMgr startAdvertising:note.userInfo];
}
}];

[[NSNotificationCenter defaultCenter] addObserverForName:@"didExitRegionNotification"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * _Nonnull note) {
if (self.pMgr.isAdvertising) {
[self.pMgr stopAdvertising];
}
}];
}

- (void)dealloc
{
// 实际上控制器中不写也不会出问题,此处只是为了 代码规范
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - CBPeripheralManagerDelegate

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
//
}
}