关闭

iBeacons

939人阅读 评论(0) 收藏 举报
分类:

iBeacons可以提供室内地图等微区位服务,为特定区域内任意相关设备提供优惠信息、硬解码定位等服务。

    iBeacons 是IOS7系统最新推出的一个类似于RFID的微定位技术。利用蓝牙4.0(低功耗蓝牙)进行数据传输(iphone 4s 以上设备)。手持设备能够在一定的范围内(可以达到50m之内)收到IBecons基站发送的信号。任何实现了IBeacon协议的蓝牙设备都可以充当ibeacon基站使用。不同其它利用GPS,蜂窝数据等的定位方式。蓝牙4.0本身的成本低,设备的耗电量也低所以相比其它定位方式有自己的优势。并且这种定位直接是端对端的直接定位,省去了GPS的卫星和蜂窝数据的基站通信,是对现有定位技术的一个有效的补充,有其利用的独特的场景和价值。与NFC不同,iBeacons可以进行远程传送信息。

    比如,用户在餐馆叫服务员买单的时候,餐馆可以通过iBeacons向用户发送一条买单信息,用户只需坐在原位拿出手机按几下就可以完成埋单,无需像近场通讯(NFC)那样还要把手机靠近某个地方才能正常付费。

    之前的位置定位服务都是通过WIFI或者GPS定位,但定下来的位置都不那么准确。而现在可以通过iBeacons实现范围内的微定位了。

    目前,国外一家叫做Estimote的公司目前正在这一领域展开研发,该公司的蓝牙智能技术可以在低功耗蓝牙技术支持的范围内向任何设备发送内容和微区位数据。该技术不仅仅可以用于购物方面的应用,还可以提供室内地图数据。

    Paypal近期也推出了类似的服务,让顾客无需刷卡或者拿出手机就完成购物。用户只需把Beacon适配器通过USB接入终端,使用Paypal应用的顾客入店时会自动签到并通知商家,而商家则可以提供个性化的优惠,让顾客知道订单什么时候会就绪,支付过程也更加简便。

        实现iBeacons精准的微定位功能除了需要运行iOS 7且支持BLE的设备外,还需要在室内、店内或者其他公共环境中部署iBeacon基站。当用户走进信号覆盖区域内时,用户就会收到相关的提醒和询问。以梅西百货为例,当用户走到商场某个店面附近时,安装了相应app的用户就会收到由iBeacons基站发出的产品信息或者打折信息。此外,美国职棒大联盟(MLB)也已经测试使用了iBeacon 技术,苹果更是在254间Apple Store 里应用了iBeacon 技术。
        对于开发者来说,可以创建一个更加具有交互性的博物馆应用,当用户在博物馆内随意行走时,通过信息提醒用户某些特别的展览。技术还可以用作室内导航,比如在地铁站或者机场这些GPS信号不大好的地方更好地引导用户。

设置:Broadcasting App
beacon广播的是什么?它是一个UUID,类似:C293726B-63BF-420A-9D79-92C71F67536A。beacon会不断地广播该UUID,并且接收方app会用同样的UUID检测信号。

添加需要的框架
在通过Bluetooth进行实际广播前,我们需要为项目添加适当的框架。
 
打开项目设置,滚动至底部。在“Linked Frameworks and Libraries”下点击“+”按钮添加CoreBluetooth.framework和CoreLocation.framework.
创建一个UUID
在Mac上打开Launchpad(或者仅打开应用程序文件夹),并打开Terminal app。在Launchpad中,它可能是一个被叫做“Other”的文件夹,图标如下图:
 
打开后,你会看见一个可以键入“uuidgen”的窗口,它会输出一个可供使用的UUID!复制生成的UUID,我们将会用它进行广播。
 
Beacon广播
在ViewController.h中,我们要输入先前添加的框架。
  1. #import <CoreLocation/CoreLocation.h> 
  2. #import <CoreBluetooth/CoreBluetooth.h> 
 
下一步,添加用以广播的3个以上属性,这样你在ViewController.h file中会有4个属性。
  1. @property (weak, nonatomic) IBOutlet UILabel *statusLabel; 
  2. @property (strong, nonatomic) CLBeaconRegion *myBeaconRegion; 
  3. @property (strong, nonatomic) NSDictionary *myBeaconData; 
  4. @property (strong, nonatomic) CBPeripheralManager *peripheralManager; 
 
这里还有一件事要完成--让ViewController类遵循“CBPeripheralManagerDelegate”协议,我们可以在class declaration中添加如下代码
  1. @interface ViewController : UIViewController<CBPeripheralManagerDelegate> 
.h file完成后,打开.m file,
 
在viewDidLoad方法中添加如下代码(替代我们之前生成的UUID)
  1. - (void)viewDidLoad 
  2.     [super viewDidLoad]; 
  3.     // Do any additional setup after loading the view, typically from a nib. 
  4.      
  5.     // Create a NSUUID object 
  6.     NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"A77A1B68-49A7-4DBF-914C-760D07FBB87B"]; 
  7.      
  8.     // Initialize the Beacon Region 
  9.     self.myBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid 
  10.                                                                   major:1 
  11.                                                                   minor:1 
  12.                                                              identifier:@"com.appcoda.testregion"]; 
在上边的代码中,我们创建了一个新的NSUUID对象。
 
然后,我们设置了一个CLBeaconRegion,并通过那个UUID进行初始化,major number,minor number 以及identifier。如果你所处的位置内有一大堆数据,major number和minor number就是用来识别你的beacons。在上边梅西百货的例子中,每个department会有一个特定的major number--识别一组beacons,在店内,每个beacon会有一个特定的minor number。
 
通过major number和minor number ,你将能精确识别哪个beacon被获取了。最后,标识符是该区域唯一的ID。
 
在之前我们设置的buttonClicked method中,我们添加如下代码:
  1. - (IBAction)buttonClicked:(id)sender { 
  2.      
  3.     // Get the beacon data to advertise 
  4.     self.myBeaconData = [self.myBeaconRegion peripheralDataWithMeasuredPower:nil]; 
  5.      
  6.     // Start the peripheral manager 
  7.     self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self 
  8.                                                                      queue:nil 
  9.                                                                    options:nil]; 
在上述代码中,我们调用了“peripheralDataWithMeasuredPower:” ,它可以给我们提供即将进行广播的beacon data。
 
第二行代码启动了外围设备管理,并监控Bluetooth的状态更新。
 
现在我们需要处理状态更新方法来检测Bluetooth何时打开和关闭。所以添加以下委托方法,因为我们的ViewController类遵照“CBPeripheralManagerDelegate” protocol。
  1. -(void)peripheralManagerDidUpdateState:(CBPeripheralManager*)peripheral 
  2.     if (peripheral.state == CBPeripheralManagerStatePoweredOn) 
  3.     { 
  4.         // Bluetooth is on 
  5.          
  6.         // Update our status label 
  7.         self.statusLabel.text = @"Broadcasting..."
  8.          
  9.         // Start broadcasting 
  10.         [self.peripheralManager startAdvertising:self.myBeaconData]; 
  11.     } 
  12.     else if (peripheral.state == CBPeripheralManagerStatePoweredOff) 
  13.     { 
  14.         // Update our status label 
  15.         self.statusLabel.text = @"Stopped"
当Bluetooth外围设备状态改变时会触发该方法。所以在该方法中,我们要检查当前设备处于什么状态。如果Bluetooth处于打开状态,我们将会更新我们的标签,调用“startAdvertising”方法,并把传递beacon data进行广播。相反,如果Bluetooth处于关闭状态,我们将会停止广播。
 
现在把app部署至设备,打开Bluetooth并点击按钮,系统就会广播你的UUID!现在我们要创建一个接收方的app来检测和处理广播。
 
注意:模拟器不能使用Bluetooth,所以不能通过模拟器进行广播。为了把app部署至支持BLE的真实设备上(iPhone 4S and up, iPad mini and iPad 3 and up),你需要加入苹果开发者计划。
 
检测Beacon
设置另一个Single View Application,并命名为“BeaconReceiver” 
添加CoreLocation框架
CoreLocation框架已经更新以支持beacon检测,我们需要把它添加在我们项目中。打开项目属性并点击“Linked Libraries and Frameworks”下的“+”图标。添加CoreLocation框架
现在,像之前那样,通过IBOutlet属性连接来添加UILabel。打开辅助编辑器,确保ViewController.h位于右边窗格。按下“control”键并点击UILabel,拖出一条线并放在 “@interface” 和 “@end”行之间。放开后,出现一个弹出对话框,你可以给属性命名为“statusLabel”。 
 
  1. @interface ViewController : UIViewController 
  2.   
  3. @property (weak, nonatomic) IBOutlet UILabel *statusLabel; 
  4.   
  5. @end 
 
最后打开ViewController.h,在文件顶部添加该框架,并调整类声明使之遵从CLLocationManagerDelegate协议,该协议包含一个delegate method,可以让我们知道最新监测到的beacons。
  1. #import <UIKit/UIKit.h> 
  2. #import <CoreLocation/CoreLocation.h> 
  3.   
  4. @interface ViewController : UIViewController<CLLocationManagerDelegate> 
  5.   
  6. @property (weak, nonatomic) IBOutlet UILabel *statusLabel; 
  7.   
  8. @end 
 
监测Beacons
我们需要添加两个属性,一个是保持对beacon region(我们即将进行检测)的跟踪;另一个是保存locationmanager,它会更新发现的beacons,在ViewController.h添加以下代码:
  1. @interface ViewController : UIViewController<CLLocationManagerDelegate> 
  2.   
  3. @property (strong, nonatomic) CLBeaconRegion *myBeaconRegion; 
  4. @property (strong, nonatomic) CLLocationManager *locationManager; 
  5. @property (weak, nonatomic) IBOutlet UILabel *statusLabel; 
  6.   
  7. @end 
 
现在打开ViewController.m,在“viewDidLoad” 方法中,我们将要初始化locationManager,把我们设置为它的委托。我们也将开始监控想要的beacon,so have that UUID handy!
  1. - (void)viewDidLoad 
  2.     [super viewDidLoad]; 
  3.     // Do any additional setup after loading the view, typically from a nib. 
  4.      
  5.     // Initialize location manager and set ourselves as the delegate 
  6.     self.locationManager = [[CLLocationManager alloc] init]; 
  7.     self.locationManager.delegate = self; 
  8.      
  9.     // Create a NSUUID with the same UUID as the broadcasting beacon 
  10.     NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"A77A1B68-49A7-4DBF-914C-760D07FBB87B"]; 
  11.      
  12.     // Setup a new region with that UUID and same identifier as the broadcasting beacon 
  13.     self.myBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid 
  14.                                                              identifier:@"com.appcoda.testregion"]; 
  15.      
  16.     // Tell location manager to start monitoring for the beacon region 
  17.     [self.locationManager startMonitoringForRegion:self.myBeaconRegion]; 
 
在第7和第8行代码中,我们把locationManager初始化为CLLocationManager的新实例,然后把我们设置为它的委托,这样当更新时就会通知我们。
 
在11行中,我们通过同样的UUID设置了NSUUID对象,作为一个被app(先前创建的那个)广播的对象。
 
最后我们把region传递给location manager 以便于监视。
 
下一步,我们需要执行一些委托方法,当region被检测时将会调用该方法。
 
 首先,在ViewController.m中添加如下代码:
  1. - (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion*)region  
  2.     [self.locationManager startRangingBeaconsInRegion:self.beaconRegion]; 
  3.   
  4. -(void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion*)region  
  5.     [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion]; 
  6.     self.beaconFoundLabel.text = @"No"
上边代码执行了两个方法,当设备进入区域或者离开区域时会被调用。当区域被检测,我们通知locationManager开始寻找区域内的beacons。
 
现在执行这个方法
  1. -(void)locationManager:(CLLocationManager*)manager 
  2.        didRangeBeacons:(NSArray*)beacons 
  3.               inRegion:(CLBeaconRegion*)region 
  4.     // Beacon found! 
  5.     self.statusLabel.text = @"Beacon found!"
  6.      
  7.     CLBeacon *foundBeacon = [beacons firstObject]; 
  8.      
  9.     // You can retrieve the beacon data from its properties 
  10.     //NSString *uuid = foundBeacon.proximityUUID.UUIDString; 
  11.     //NSString *major = [NSString stringWithFormat:@"%@", foundBeacon.major]; 
  12.     //NSString *minor = [NSString stringWithFormat:@"%@", foundBeacon.minor]; 
当一个或者更多beacons被检测时,该方法将会被失效。在上述代码中,你可以看到我们如何获得UUID,来自beacon的major和minor数据。另外,虽然我们上边并未执行,但你可以遍历beacons array,并通过检测近距离的beacon属性来决定哪一个是最近的。
 
运行demo
如果你有两台iOS真机,并且你已经加入了苹果iOS开发者计划,那你就可以对该技术进行测试。发布beacon app和点击“Broadcast”按钮,然后等待“Broadcasting…”信息出现。发布receiver app,并让它远离broadcasting beacon,然后走近它模仿实际进入beacon区域。 
总结
如果你没有多台设备,你可以通过购买BLE beacons并把他们放在房子周围来创建很酷的app。 Estimote makes such beacons and you get three for $99.
 
所以我希望你能明白iBeacons应用的强大之处,我也希望这个demo能点燃你对真实世界的想象。你可以下载在此下载demo app的Xcode项目。
 
本文由Code With Chris的Chris Ching提供,Chris通过其网站和YouTube教授iOS开发课程。
*********************************************************************************************************************************************************

所有支持蓝牙4.0iDevice都能够作为beacon基站发射信号,这就需要 CoreBluetooth.framework 的支持。 我们需要创建一个CBPeripheralManager实例,然后发射beacon广播信号:


一个beacon基站主要有三个属性,即上面说到过的:proximityUUID major minor,对应到CoreLocation中的CLBeacon类:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @interface CLBeacon : NSObject <NSCopying, NSSecureCoding>  
  2. //...  
  3. @property (readonly, nonatomic) NSUUID *proximityUUID;  
  4. @property (readonly, nonatomic) NSNumber *major;  
  5. @property (readonly, nonatomic) NSNumber *minor;  
  6. //...  
  7. @end  

//beacon基站创建一个唯一标示

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  
  1. time_t t;

        srand((unsignedtime(&t));

        CLBeaconRegion *region = [[CLBeaconRegion allocinitWithProximityUUID:self.beaconRegion.proximityUUID

                                                                         major:rand()

                                                                         minor:rand()

                                                                    identifier:self.beaconRegion.identifier]; 

proximityUUID :对于每个公司这个是唯一的。对于该公司的所有的ibeacons都有相同的UUID。

major:相关的一系列ibeacons的标示。

minor:某个特殊的ibeacon的标示。

identifier:该beacons区域的唯一标示。

举个例子:一个展览公司A,和一个展览公司B会有不同的proximityUUID,展览公司A在地址C和地址D有不同的展览馆,那么他们就有不同的major值。对于地址C的展览馆里面的不同楼层有会有不同的minor值。所以我们可以根据proximityUUID,major,minor三个值唯一确定一个ibeacon。


//获取该Beacon区域的信号信息

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. NSDictionary *peripheralData = [region peripheralDataWithMeasuredPower:nil];  

//创建并广播Beacon信号

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. CBPeripheralManager *peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];  
  2. [peripheralManager startAdvertising:peripheralData];  

当然你还需要在CBPeripheralManagerDelegate代理方法:peripheralManagerDidUpdateState:根据不同的状态做一些处理。


Beacon Monitoring

苹果将iBeacons相关的接口放到了 CoreLocation.framework 。在iOS7之前,我们可以通过CLRegion定义一个地理区域,来跟踪设备在该区域内的运动情况,iOS7之后,CLRegion被完全变成了一个抽象类,子类CLCircularRegionCLBeaconRegion分别承担实现一个地理区域和Beacon信号区域的功能。


iOS7之后的CLRegion主要有两个属性:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @interface CLRegion : NSObject <NSCopying, NSSecureCoding>  
  2. @property (nonatomic, assign) BOOL notifyOnEntry;  
  3. @property (nonatomic, assign) BOOL notifyOnExit;  
  4. @end  

notifyOnEntrynotifyOnExit分别标记是否在进入和退出该区域时调用对用代理方法。CLBeaconRegion另外增加了一个属性notifyEntryStateOnDisplay标记是否在用户手机屏幕点亮时调用代理方法。


创建一个 CLBeaconRegion ,我们需要先创建一个目标监控区域唯一的UUID(该UUID需要跟之前基站的UUID一致)

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. CLBeaconRegion *targetBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:

    self.beaconRegion.proximityUUID

     identifier:self.beaconRegion.identifier];  

创建完Regoin后,我们需要对该Region进行监控以获取是否进入该区域及一些距离等信息,我们需要创建一个CLLocationManager实例然后调用startMonitoringForRegion:方法来监控上面的BeaconRegion

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. self.locationManager = [[CLLocationManager alloc] init];  
  2. self.locationManager.delegate = self;  
  3. [self.locationManager startMonitoringForRegion:targetBeaconRegion];  

剩下的就是通过CLLocationManagerDelegate中的各个方法来获取监控区域内的所有CLBeacon基站,进入或退出某个Beacon区域,计算举例某个CLBeacon的距离等。


*******************************************************************************************************************************

现在有很多种关于iBeacon是什么,以及我们可以如何使用它们的解释。然而从技术角度上来说,它们是如何工作的?底层的技术使用的使用Bluetooth LE,因此。。。


What is Bluetooth LE?(什么是Bluetooth LE,简写BLE)


Bluetooth Low Energy(BLE)是2010年发布的蓝牙4.0技术规范的一部分。它起源于2006年Nokia的Wibree技术,但最终被整合进了蓝牙。这是一组与传统蓝牙不同的协议,并且使用的设备上也不会向后兼容。因此,现在市面上你可以看到三种类型的设备:

1.Bluetooth设备:只支持传统蓝牙的设备。

2.Bluetooth Smart Ready设备:同时支持传统蓝牙和LE模式的设备。

3.Bluetooth Smart设备:只支持LE模式的设备。


最新的手机(iPhone 4s+, SG3+)、笔记本、平板电脑等,基本上都已经支持蓝牙4.0,也就是Bluetooth Smart Ready设备。Beacon,从另一方面来说,这种设备只支持low energy protocols(LE低功耗协议),属于上面说所的“Bluetooth Smart”设备,这也是它们靠一颗纽扣电池就能运行很长时间的原因。老式设备,比如外设、汽车系统、旧手机等通常只支持传统蓝牙协议。


BLE最重要的特点当然在于它的低能耗。举个例子,一些beacon设备靠一颗微型电池就能够持续发送一个信号两年左右(这种电池一般是不可拆卸的,你可能需要在beacon停止工作之后替换一个新的beacon)。传统蓝牙和LE蓝牙使用的都是相同的波段(2.4GHz-2.4835GHz)。BLE协议的传输速率比较低,因此除了用于发现设备和做一些简单通信之外,不太适合用于传输大量的数据流。在协议条款上,LE和传统蓝牙的信号都能够覆盖到100米的范围。


How does BLE communication work?(BLE设备如何通信)


BLE的通信包括两个主要部分:advertising(广告)和connecting(连接)。


广告(Advertising)是一种单向的发送机制。想要被搜索到的设备可以以20毫秒到10秒钟的时间间隔发送一段数据包。使用的时间间隔越短,电池消耗的越快,但设备被发现的速度也就会快。数据包长度最多47个字节,由以下部分组成:


    1 byte preamble(1字节做报头)

    4 byte access address(4字节做地址)

    39 bytes advertising channel PDU(39个字节用于PDU数据包)

    3 bytes CRC(3个字节用于CRC数据校验)



对于广告通信信道,地址部分永远都是0x8E89BED6。对于其它数据信道,地址部分由不同的连接决定。


返回的PDU数据也拥有自己的数据报头(2个字节:声明有效载荷数据的长度和类型——设备是否支持连接等等)和当前有效载荷数据(最多37个字节)。


最终,有效载荷数据中的头6个字节是设备的MAC地址,所以实际信息数据最高可占31个字节。


BLE设备可以运行在单一的不可连接的广告模式中(在这种模式下所有的信息都包含在广告数据包中),然而设备也是允许运行在可被连接的模式下(通常情况下都是这种模式)。


当设备被发现之后,一个连接就会被建立起来。之后就可以读取BLE设备提供的Service,以及每个Service的characteristic(属性,类似于GATT Profile实例)。每一个characteristic都会提供一些值,这些值可以被读取或者修改。例如,一个小型温控器可以开放一个service用于获取当前的温度或者湿度读数(相当于是service的characteristic),同时也可以开放其它的service和characteristic用于设置期望的温度。这里因为beacon不使用连接模式,我将会跳过这些细节。如果你想要了解更多关于连接BLE设备的内容,可以参考Apple's Core Bluetooth guide,尽管你可能不是一个IOS开发者。更多相关技术性的文章,可以参考Introduction to BLEMaking the most out of BLE Advertising mode


How do beacons use BLE?(beacon设备如何使用BLE)


Beacon设备只使用了广告通信信道。正如beacon(信标、灯塔)的字面意思,这种设备以一定的时间间隔发送数据包,并且发送的数据被可以被像手机这样的设备获取。也就是说,iBeacon只是BLE广告模式的一种简单的使用,并在此基础上提供了对IOS的一些附加支持。


如果你试着拦截一段iBeacon广告数据包,例如下面从Estimote beacon截获的数据包:


[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 02 01 06 1A FF 4C 00 02 15 B9 40 7F 30 F5 F8 46 6E AF F9 25 55 6B 57 FE 6D 00 49 00 0A C5  

(截获以上数据,如果你使用的Mac设备,你可以参考additional XCode download为XCode添加蓝牙扫描和数据包打印工具。如果是Window设备,请参考这里


以上的数据已经将广告数据包的报头、修正地址、广告PDU数据包的报头和其中的MAC地址部分都移除掉了,也就是说这部分数据只包含了实际信息数据——一共30个字节,符合实际信息数据最多31个字节的限制。


那么一个iBeacon设备的BLE广告数据是如何组成的?以下是Apple修正的数据格式,整理如下(也可以参考这里):


[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 02 01 06 1A FF 4C 00 02 15: iBeacon prefix (fixed)  
  2. B9 40 7F 30 F5 F8 46 6E AF F9 25 55 6B 57 FE 6D: proximity UUID (here: Estimote’s fixed UUID)  
  3. 00 49: major  
  4. 00 0A: minor  
  5. C5: 2’s complement of measured TX power  



根据这些原理,如果你想要实验beacon的功能,你不必需要一个真正的beacon设备。如果你有最新的手机(例如iPhone4S+,SG3+)或者配备蓝牙4的笔记本(例如Retina MacBook),你可以将这些设备转换成iBeacon发送设备和接收设备。以iPhone为例,你可以在AppStore上下载“Locate iB”应用。对于MacOS,可以参考这里。当然你可以可以使用树莓派


Breaking down the iBeacon format(解析iBeacon的数据格式)


除了修正的iBeacon前缀数据(02 01 ... 15),其它各部分数据各代表什么?


Proximity UUID(上面例子中的B9 ... 6D部分):这是将你所有的beacon与其他人的beacon设备区别开的id!例如,目前在商店里某个区域分布着多个beacon形成一条“链带”,用于为顾客提供特定的服务,那么归属于同一条“链带”的beacon将分配到相同的proximity UUID。为这条“链带”设计的专用应用程序将会在后台使用这个UUID扫描到这条“链带”中的beacon设备。


major编号(2个字节,上面例子中为0x0049,也就是73):用于将相关的beacon标识为一组。例如,一个商店中的所有beacon将会分配到相同的major编号。通过这种方式,应用程序就能够知道顾客位于哪一家商店。


minor标号(也是2个字节,上面例子中为0x000A,也就是10):用于标识特定的beacon设备。例如一个商店中的每一个beacon设备都拥有唯一的minor编号,这样你才能够知道顾客位于商店中的哪个位置。


Measuring distance(测量距离)


最后一个值,TX power,用于确定你和beacon之间距离有多近。根据这个值不但可以获得粗略的信息(比如靠近/远离/不在范围内等),也可以获取精确到米的距离(当然你也可以转换为以步为单位的距离)。那么如何实现?


TX power(上面例子中为0xC5=197,根据2的补码测得256-197=-59dBm)是距离设备1米测得的信号强度值(RSSI- Received Signal Strength Indication,接收到的信号强弱指标)。假如接收到的信号强度减弱了,那么我们可能在远离。只要知道1米距离的RSSI,以及当前的RSSI(我们可以从接收到的信号中一块获取到这些信息),那么计算出当前的距离是可能的。IOS已经实现了个这个功能,对于其它平台需要自己手动编码计算,可以参考这里


译注:Java代码粗略计算距离代码:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected static double calculateAccuracy(int txPower, double rssi) {  
  2.   if (rssi == 0) {  
  3.     return -1.0// if we cannot determine accuracy, return -1.  
  4.   }  
  5.   
  6.   double ratio = rssi*1.0/txPower;  
  7.   if (ratio < 1.0) {  
  8.     return Math.pow(ratio,10);  
  9.   }  
  10.   else {  
  11.     double accuracy =  (0.89976)*Math.pow(ratio,7.7095) + 0.111;      
  12.     return accuracy;  
  13.   }  
  14. }     

然而,在实际应用中,由于人体或者其它通信阻碍物都有可能削弱信号,因此这个距离只是一个估算值。


IOS integration(IOS整合)


IOS已经整合了iBeacon。当你进入beacon的范围内,你的应用程序就可以接收到通知,即使你的应用程序处于在后台也能接收到。一个应用程序可以注册一个区域的进入或者退出事件,因此即使应用程序没有运行也可以被唤醒。为了响应这些事件,应用程序可以发送例如本地推送通知,提示用户打开应用程序查看商店的促销广告(这些促销广告可以从网络上面获取),或者是其它相关的内容。


更准确的说,当手机处于不活动状态时,也就是IOS进入了低电量监控模式的时候,只有iBeacon区域进入/退出事件能够被接收到。当手机和应用程序处于活动状态,你可以进入ranging模式,这个能够让你检测的信号强度和估算距离更加准确。


注意你的手机检测beacon需要花费一定的时间。首先,beacon设备是间隔一定的时间才发送一次广告。其次,如果你的手机处于非活动模式,它只在有些时候才会检测蓝牙信号。一个beacon设备要被检测到,上面两段工作时间就需要有交集。实践证明,它可能需要15分钟才能检测到一个beacon设备。


按步骤开发一个iOS iBeacon应用程序可以参考这里。Beacon的制造商通常也会提供SDK帮助开发Beacon应用程序。参考Estimote的iOS SDK 和Android SDK


How can I get some beacons?(如何获取Beacon设备)


Beacon设备资源现在比较稀少,你通常需要等上几个星期才能拿到货,但可以肯定的是将来这种情况会改善。


因此,最快的选择就是创建一个Beacon模拟器:将iPhone/Android/MacBook/其它笔记本/树莓派转换成了Beacon模拟器。


第二种选择就是试着去订购一些Beacon设备了:


    pre-order Estimote beacons; 3 for $99

    Kontakt beacons come in a couple of packages; 4 for $99, 10 for $279

    RaspberryPi kits from RadiusNetworks: 1 for $99

    RedBearLab offers BLE shields for Arduino for $30

    Bleu sells USB-iBeacon dongles. 1 for $40, 5 for $150


Alternatives(替代品)


iBeacon不是唯一一种基于BLE近距离技术开发的设备。高通同样正在开发自己的Beacon——Gimbal,并集合了iOS和Android SDK。它们提供的功能比较类似,但是BLE广告的数据格式可能不一样。我的开发工具还在运送途中,因此我还没有测试过,但是这种Beacon肯定很有趣,尤其是它的价格最低只有5美元。


What's next?(下一步是什么?)


现在还没有做的事情就是开发一些基于Beacon的应用程序。为了实现这个目的,记住SoftwareMill:我们经常寻找一些有趣的项目来开发。


原文地址:http://www.warski.org/blog/2014/01/how-ibeacons-work/


安卓版本的beacon讲解*********************************************************************************************************************************************************************

注意,本人运行官方的示例,无法正常使用。主要原因是需要重新设置BeaconParser。

下面是我写的一个例子,供大家参考:


package com.example.sample_beacon;

import java.util.Collection;

import org.altbeacon.beacon.Beacon;
import org.altbeacon.beacon.BeaconConsumer;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.MonitorNotifier;
import org.altbeacon.beacon.RangeNotifier;
import org.altbeacon.beacon.Region;

import android.app.Activity;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;

public class MainActivity extends Activity implements BeaconConsumer
{
	protected static final String TAG = "MonitoringActivity";
	/** 重新调整格式*/
	public static final String IBEACON_FORMAT = "m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24";
	/** 设置兴趣UUID*/
	public static final String FILTER_UUID = "E2C56DB5-DFFB-48D2-B060-D0F5A71096E0";
	
	private BeaconManager beaconManager;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		beaconManager = BeaconManager.getInstanceForApplication(this);
		beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(IBEACON_FORMAT));
		beaconManager.bind(this);
	}

	@Override
	protected void onDestroy()
	{
		super.onDestroy();
		beaconManager.unbind(this);
	}

	@Override
	public void onBeaconServiceConnect()
	{
		beaconManager.setMonitorNotifier(new MonitorNotifier()
		{
			@Override
			public void didEnterRegion(Region region)
			{
				Log.e(TAG, "I just saw an beacon for the first time!");
			}

			@Override
			public void didExitRegion(Region region)
			{
				Log.e(TAG, "I no longer see an beacon");
			}

			@Override
			public void didDetermineStateForRegion(int state, Region region)
			{
				Log.e(TAG, "I have just switched from seeing/not seeing beacons: " + state);
			}
		});

		try
		{
			//开始监视
			beaconManager.startMonitoringBeaconsInRegion(new Region(FILTER_UUID, null, null, null));
		}
		catch (RemoteException e)
		{
			e.printStackTrace();
		}
	}

}

上述示例中,通过调用 beaconManager.getBeaconParsers()获取到BeaconParser列表,然后往里面添加一个我们自己定义的BeaconParser。

而BeaconParser是通过setBeaconLayout(String)方法,设置对应的Beacon格式。


以下是设置的iBeacon格式

IBEACON_FORMAT = "m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24";

  •    m - matching byte sequence for this beacon type to parse (exactly one required)
       s - ServiceUuuid for this beacon type to parse (optional, only for Gatt-based becons)
       i - identifier (at least one required, multiple allowed)
       p - power calibration field (exactly one required)
       d - data field (optional, multiple allowed)


下面来简单说一下iBeacon广播的数据。


一般来说,我们在调用BluetoothAdapter.startLeScan()搜索iBeacon的时候,

会在回调函数onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)中获取到iBeacon发出广播数据,

就是参数scanRecord所携带的数据。如下所示:

02 01 06 1A FF 4C 00 02 15 E2 C5 6D B5 DF FB 48 D2 B0 60 D0 F5 A7 10 96 E0 00 03 00 03 CD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

把其它无关数据去掉,变成

02 01 06 1A FF 4C 00 02 15 E2 C5 6D B5 DF FB 48 D2 B0 60 D0 F5 A7 10 96 E0 00 03 00 03 CD

以上数据只包含了实际信息数据(其它数据如MAC、数据包报头……不在这里),共30字节

经过整理后,变成

02 01 06 1A FF 4C 00 02 15  (iBeacon的前缀,固定不变的)
E2 C5 6D B5 DF FB 48 D2 B0 60 D0 F5 A7 10 96 E0 (UUID的值)
00 03 (major值)
00 03 (minor值)
CD (tx值,表示距离1米是应该接收到的信号强度,可用于计算距离)

按照相关资料所述,识别是否iBeacon靠上面的红字(0215),参考资料如下

https://github.com/RadiusNetworks/android-ibeacon-service/blob/master/src/main/java/com/radiusnetworks/ibeacon/IBeacon.java



再回到之前我们要设置的BeaconParser的问题上……

在默认情况下,通过beaconManager.getBeaconParsers()方法获取到BeaconParser列表,默认只有一个。

而且,该默认的BeaconParser被设置为"m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25",

注意看m值,这里是”beac“来的,并不是iBeacon的标识,

也就是说,android-beacon-library这个库默认情况下,并不是用于扫描iBeacon,

想要用于扫描iBeacon商标,需要做以上修改 ……


iBeacon 的 API 并不十分复杂,但他的行为比较难弄清楚,特别是当应用运行在后台时,检测到 beacon 的时间延迟会让开发者难以推测。在做了一些实验和合理的推测后,我们得出了一些结论:
检测到 beacon 的时间跟设备进行蓝牙扫描的时间间隔有关,每当设备进行扫描的时候,就能发现 iBeacon region 的变化。
在 ranging 打开的情况下,设备会每秒钟做一次扫描,也就是说状态更新最多延迟一秒。
程序在后台运行,并且 monitoring 打开的时候,设备可能每隔数分钟做一次扫描。iOS 7 的响应速度较慢,iOS 7.1 有比较大的改善。
如果存在设置 notifyEntryStateOnDisplay=YES 的 beacon,iOS 会在屏幕点亮的时候(锁屏状态下按下 home 键,或者因为收到推送点亮等)进行一次扫描。
设备重启并不影响 iBeacon 后台检测的执行。
iOS 7 中,在多任务界面中杀掉程序会终止 iBeacon 检测的执行,iOS 7.1 上改变了这一行为,被杀掉的 app 还可以继续进行 iBeacon 检测。


安卓beacon封装库

https://github.com/AltBeacon/android-beacon-library.git

demo下载地址:http://download.csdn.net/detail/eieihihi/8679825


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:78260次
    • 积分:1803
    • 等级:
    • 排名:千里之外
    • 原创:86篇
    • 转载:189篇
    • 译文:2篇
    • 评论:7条
    文章分类
    最新评论