低功耗蓝牙技术现在几乎是智能手机的标配。随着这一技术的发展,苹果在2013年WWDC大会上,苹果推出iBeacon技术。该技术允许开发 人员开发能够使用iBeacon硬件传感器的iOS应用程序,来为相应的应用程序提供更加精准的位置信息。2014年WWDC大会上,苹果表示,对 iBeacon技术进行了改善,借助该技术,应用程序现在能够跟踪到用户所在的楼层的精确位置信息。

iBeacon的工作方式是Transmitter-Receiver,即基站-接收机模式的。基站?这个时候不要想到移动、联通的那些大铁 塔。这个基站可以是一个运行着Bluetooth 4.0 LE的设备,也可以是经过配置的iPhone、iPad。iPhone4S和之后的iPhone、iPad3或之后的iPad,包括iPad mini都可以配置成iBeacon基站。

这里列举个iBeacon的使用场景:在房屋中介中使用。米国一家技术公司把 iBeacon 安装在要出售的房屋前,当用户开车至此,不用下车就可以用中介的 APP 获得此房屋所有相关信息和照片,不用打印及搜索。据说,效果还是很不错的,大约有一半左右的用户打开手机查看了相关信息。甚至于还有一个老外用 iBeacon做了一个实景的经营游戏,点击这里观看。

一个基站主要有三部分标识:

1. UUID,形如:206A2476-D4DB-42F0-BF73-030236F2C756。用来标识某一个公司。比如,某个房地产公司的全部的基站都用同一个UUID。

2. major,用来标识某一类的beacon。比如这个房地产公司的北京的房子都设定为1,上海的都设定为2。

3. minor,用来标识某一个特定的beacon。比如某栋楼的某个基站。

用这个房地产商开发的app就可以获取到UUID,和后面的major值和minor值。当app进入beacon的区域,探测到 UUID:”206A2476-D4DB-42F0-BF73-030236F2C756“,major为1,minor为20。那么就表明这个用户在这 个房地产商的北京楼盘的编号20的楼盘。这栋楼的说明文字、图片或者视频等就可以展现在用户面前。

下面就进入我们的教程。不过前提是你要是苹果的开发者,因为这个app需要在真机运行。然后要有2台设备,一个当基站,一个当接收机。最后,还得有一台能运行Xcode的电脑。

首先创建一个SingleView的项目,起个名字叫MyBeacon。然后把我们需要用到的Framework加进来,把CoreBluethooth.framework和CoreLocation.framework加到项目中。

创建一个Storybard,并在视图中添加如下的UIController:

关于storyboard的细节就不多说了。下面新建两个文件:TrackViewController 和 ConfigViewController 。这时候会自动生成一个 ViewControler 类。分别把他们按照上图所示对应到 stroyboard 的几个ViewController 中,并添加图中所示的 UILabel 。然后把需要现实APP运行结果的 UILabel 作为 IBOutlet 。

TrackViewController 的 IBOutlet 是这样的:(以下的两个文件都用的是Swift语言,如果你需要的话可以自行修改为OC语言)

ConfigViewController 的 IBOutlet 是这样的:

先搞定基站部分

在 ConfigViewController 中添加如下的属性:

第一个 CLBeaconRegin 属性,用来设置基站需要的 proximityUUID ,major 和 minor 的给你信息。

第二个 NSDictionary 的属性,用来获取外设的数据。

第三个 CBPeripheralManager 的属性,用来开启基站的数据传输。

这些属性后面的感叹号是Swift里的一种语法。变量或者属性的定义,在类型的后面可以是问号后者是感叹号。他们都表示这个变量或者属性可以是 有值的也可以是空值nil(注意这里的nil和OC里的nil是两回事)。但是使用问号的变量或者属性需要在使用前判断是否有值,如果有的话通过感叹号取 值。使用感叹号定义的变量或者属性则可以直接取值并使用。这里使用感叹号定义属性,这样在使用的时候可以直接取值。详细的使用会在代码中体现。

要让iOS设备开始传输信号还需要做些其他的事情。在viewDidLoad中调用几个方法才能让基站工作起来。首先调用的是initBeacon方法,之后是要把数据现实出来的setLabels方法。

在这里通过uuid字符串设定NSUUID实例。uuid字符串可以通过uuidgen命令在终端里生成。也可以通过代码生成,但是这里没有这个必要。然后其他的值major和minor分别设定为1,identifier设定为我们示例的名字。

下面我们就要考虑传输的问题了。在用户点击了传输按钮之后开始使用设备的蓝牙外设发出信号。方法如下

在这个方法里,首先通过我们设定的beaconRegion属性获得相关的外设数据。这个数据是NSDictionary类型的。需要说明的是,这个类型可以在Swift中使用,但是和Swift本身的Dictionary是不兼容的。

之后,初始化了CBPeripheralManager属性。这里简单处理,设定queue和options为nil。为了设定代理为 self 需要实现 CBPeripheralManagerDelegate protocol 。

实现了这个protocol之后,还需要实现这个protocol的一个方法。这个方法在OC里来讲是required的,所以必须实现。

外设的状态中有两个需要我们处理的。一个是PoweredOn一个PoweredOff。On了就让peripheralManager开始对 外发出信号。Off了就停止发出信号。所以呢,如果直接在transmitaction中调用代码startAdvertising是设备对外发出信号的 话,会报错。Console会打印出”CBPeripheralManager is not Powered on“。所以我们在以上的代码中在Pwoered On的时候再开始调用代码发出信号。发出信号的时候呢,我们给了advertising方法传入了从beaconRegion取出来的 NSDictionary数据。这也是接收机辨识基站用到的数据。

之后我们把数据显示在界面上。

这个方法很简单,只要在viewDidLoad里调用setLabels方法就可以。全部设定在基站里的数据都会显示在界面上了。其中包括 uuid、major和minor,最后是我们设定的identifier。用Swift比用OC写代码是会少一些量,如果你对Swift足够熟的话。比 如,取得一个值的字符窜值的时候就不用[Nsstring stringWithFormat:"..."]这么麻烦的写法了。

我们的app已经可以作为基站使用了。但是没有接收机的话这个app可是一点都不好玩。在下面就开始处理接收机的部分。

接收iBeacon信息

接收iBeacon信号的底层功能已经在Core Location Framework里实现了。在iOS7里,可以自动识别你是否进入了一个区域以及其他的距离之类的信息。

下面在TrackViewController中处理,首先把CoreLocation库的头文件加进来。然后增加下面的两个属性:

CLBeaconRegion属性是用来定义我们要寻找的beacon的。这个app只会接收到有同样的UUID的的发射机发射的信号。

CLLocationManager属性是用来建立位置服务并搜索beacon的。

在viewDidLoad方法中添加如下代码:

首先,要初始化CLLocationManager,然后把代理设置为self。当然设定代理之前我么需要实现CLLocationManagerDelegate protocol,具体的就不写出来了。然后调用initRegion方法,这个会在后面给出详情。

首先创建UUID实例。用来初始化这个实例的的uuid字符串必须和基站的uuid字符串是一样的,要不互相找不见。

然后初始化beaconRegion,proximityUUID就是前面创建的UUID实例,identitifer就是在基站中用到的 identifier字符串。然后开始监测前面初始化出来的beaconRegion。调用代码 self.trackLocationManager.startMonitoringForRegion(self.beaconRegion)开始检 测。

接下来,我们需要监测这个app进入和离开区域的事件,代码如下:

第一个方法是进入的,当你接收到基站信号的时候这个方法就开始执行(当然你要离基站足够近)。然后调用locationManager的startRagingBeaconsInRegion方法,病传入我们之前定义好的beaconRegion属性。

第二个方法很简单,就是在离开这个区域的时候就停止执行,调用locationManager的stopRagingBeaconsInRegion。

下面是didRangeBeacons方法:

首先判断方法传入的beacons数组的元素有多少。如果有0个的时候什么都不做。如果有一个或以上的话,这里简单处理只取最后一个beacon来处理。

之后的代码都只是从beacon中取出数据来现实在界面上,比如UUID,major,minor,accuracy和RSSI。这些值会随着 接收机和基站的距离不同以及基站的设置不同而一直改变。尤其accuracy和RSSI都是beacon用来现实距离的。其中proximity会显示四 个值:UnkNown、Immediate、Near和Far。Immediate是半米以内,Near远一些,Far更远。RSSI是信号强度。

运行程序

现在这个app可以运行了。但是需要分别运行在两台可以兼容低功耗蓝牙的设备上。一台当基站一台当接收机。

当你从足够远(10~20米)的地方想基站的方向走的时候,一个你”didEnterRange”那个didRangeBeacons方法就会被调用,这是就可以从方法中传入的beacon数组中取出值来现实在界面上。

但是有一点需要注意的是,我们处理的基站只有一个,所以每次都取出beacon数组的最后一个。如果有多个beacon基站的话就需要循环beacon数组的每一个元素,判断这个元素的proximity是Immdiate还是Near还是Far等。

每次测试的时候都进入或者离开一个区域太麻烦。可以在viewDidLoad方法中添加一行代码:

然后添加如下方法:

动调用了didStartMonitoringForRegion,在这个方法中调用了trackLocationManager的startRangingBeaconsInRegion方法。这样虽然不完美,但是足够测试了。

下面是代码列表:

ConfigViewController:

 
 
  1. importUIKit
  2. importCoreLocation
  3. importCoreBluetooth
  4. classConfigViewController:UIViewController,CBPeripheralManagerDelegate{
  5. //properties
  6. @IBOutletvaruuidLabel:UILabel
  7. @IBOutletvarmajorLabel:UILabel
  8. @IBOutletvarminorLabel:UILabel
  9. @IBOutletvaridentityLabel:UILabel
  10. @IBOutletvartransmitButton:UIButton
  11. varbeaconRegion:CLBeaconRegion!
  12. varbeaconPeripheralData:NSDictionary!
  13. varperipheralManager:CBPeripheralManager!
  14. overridefuncviewDidLoad(){
  15. super.viewDidLoad()
  16. self.initBeacon()
  17. self.setLabels()
  18. }
  19. funcinitBeacon(){
  20. self.beaconRegion=CLBeaconRegion(proximityUUID:NSUUID(UUIDString:"206A2476-D4DB-42F0-BF73-030236F2C756")
  21. ,major:1,minor:"com.mybeacon.region")
  22. }
  23. funcsetLabels(){
  24. self.uuidLabel.text=self.beaconRegion.proximityUUID.UUIDString
  25. self.majorLabel.text=self.beaconRegion.major.stringValue
  26. self.minorLabel.text=self.beaconRegion.minor.stringValue
  27. self.identityLabel.text=self.beaconRegion.identifier
  28. }
  29. overridefuncdidReceiveMemoryWarning(){
  30. super.didReceiveMemoryWarning()
  31. //dispoSEOfanyresourcesthatcanberecreated.
  32. }
  33. @IBActionfunctransmitaction(sender:UIButton){
  34. self.beaconPeripheralData=self.beaconRegion.peripheralDataWithMeasuredPower(nil)
  35. self.peripheralManager=CBPeripheralManager(delegate:self,queue:nil,options:nil)
  36. }
  37. //delegatemethods
  38. funcperipheralManagerDidUpdateState(peripheral:CBPeripheralManager!){
  39. ifperipheral.state==CBPeripheralManagerState.PoweredOn{
  40. println("Poweredon")
  41. self.peripheralManager.startAdvertising(self.beaconPeripheralData)
  42. }
  43. elseifperipheral.state==CBPeripheralManagerState.PoweredOff{
  44. println("Poweredoff")
  45. self.peripheralManager.stopAdvertising()
  46. }
  47. }
  48. }

TrackViewController:

importCoreLocation
  
  
  • classTrackViewController:UIViewController,CLLocationManagerDelegate{
  • @IBOutletvarbeaconLabel:UILabel
  • @IBOutletvaruuidLabel:UILabel
  • @IBOutletvarmajorLabel:UILabel
  • @IBOutletvarminorLabel:UILabel
  • @IBOutletvaraccuracyLabel:UILabel
  • @IBOutletvardistanceLabel:UILabel
  • @IBOutletvarRSSiLabel:UILabel
  • varbeaconRegion:CLBeaconRegion!
  • vartrackLocationManager:CLLocationManager!
  • overridefuncviewDidLoad(){
  • super.viewDidLoad()
  • self.trackLocationManager=CLLocationManager();
  • self.trackLocationManager.delegate=self;
  • self.initRegion()
  • self.locationManager(self.trackLocationManager,didStartMonitoringForRegion:self.beaconRegion)
  • }
  • funcinitRegion(){
  • varuuid=NSUUID(UUIDString:"206A2476-D4DB-42F0-BF73-030236F2C756")
  • self.beaconRegion=CLBeaconRegion(proximityUUID:uuid,identifier:"com.mybeacon.region")
  • self.trackLocationManager.startMonitoringForRegion(self.beaconRegion)
  • }
  • funclocationManager(manager:CLLocationManager!,didStartMonitoringForRegionregion:CLRegion!){
  • self.trackLocationManager.startRangingBeaconsInRegion(self.beaconRegion)
  • }
  • overridefuncdidReceiveMemoryWarning(){
  • super.didReceiveMemoryWarning()
  • //dispoSEOfanyresourcesthatcanberecreated.
  • }
  • funclocationManager(manager:CLLocationManager!,didEnterRegionregion:CLRegion!){
  • self.trackLocationManager.startRangingBeaconsInRegion(self.beaconRegion)
  • }
  • funclocationManager(manager:CLLocationManager!,didExitRegionregion:CLRegion!){
  • self.trackLocationManager.stopRangingBeaconsInRegion(self.beaconRegion)
  • self.beaconLabel.text="No"
  • }
  • funclocationManager(manager:CLLocationManager!,didRangeBeaconsbeacons:[AnyObject]!,inRegionregion:CLBeaconRegion!){
  • println("beaconscount"+String(beacons.count))
  • ifbeacons.count<=0{
  • return
  • }
  • varbeacon:AnyObject=beacons[beacons.count-1]
  • self.beaconLabel.text="Yes"
  • self.uuidLabel.text=beacon.proximityUUID?beacon.proximityUUID!.UUIDString:""
  • self.majorLabel.text=beacon.major?beacon.major!.stringValue:""
  • self.minorLabel.text=beacon.minor?beacon.minor!.stringValue:""
  • self.accuracyLabel.text=beacon.accuracy?String(beacon.accuracy):""
  • ifbeacon.proximity{
  • switch(beacon.proximity!){
  • case.UnkNown:
  • self.distanceLabel.text="UnkNownproximity"
  • caseCLProximity.Immediate:
  • self.distanceLabel.text="Immediate"
  • caseCLProximity.Near:
  • self.distanceLabel.text="Near"
  • caseCLProximity.Far:
  • self.distanceLabel.text="Far"
  • default:
  • }
  • }
  • self.RSSiLabel.text=beacon.RSSi?beacon.RSSi!.description:""
  • }
  • }
  • iBeaconswift的更多相关文章

    1. ios – 订阅来自CBC特性的通知不起作用

      现在控制台输出到这里看起来像这样:嘿!它说updateNotification是假的.它来自哪里?为什么,这是我对setNotify的回调…我告诉它要通知!让我们在println的行中设置一个断点并检查错误对象:好的,所以这让我没有想法.我无法找到有关该错误代码的相关线索.自从我尝试为之前发现的特征设置通知以来,我无法理解描述本身,因此它必须存在,对吧?此外,在Android上似乎可以订阅通知,所以我想我可以排除设备的问题……有关这方面的任何线索都非常感谢!

    2. ios – 为什么NSManagedObjectID会发生变化?

      我不确定这个问题的格式对这个网站是否有用.基本上,有没有人知道什么使得Apple确保在每次将数据保存到持久存储时NSManagedobjectID发生变化的设计决策?我最大的问题是为什么提供临时的managedobjectID.它有什么意义吗?解决方法我有点困惑为什么你一直说NSManagedobjectID特别是UUID.URI表示可能具有与UUID格式类似的外观,但我没有在文档中看到它表示“NSManagedobjectID是UUID”.为什么Apple以这种方式设计它超出了StackOverflow

    3. ios – 修复ARC中潜在的内存泄漏

      以下单例类帮助器方法可能会导致保留周期.在静态分析器中获取警告:“在线路上分配的对象的潜在泄漏……”我确实尝试过使用ivaruuid__weak但是当我分析时仍会出现警告.谢谢像这样在课堂上被召唤:解决方法这会删除警告吗?

    4. ios – 在区域监控时检测iBeacon需要多长时间?

      采取这种情况:用户在口袋里有一个通过iBeacon的iPhone.她的手机是区域监控.应用程序被唤醒时,现实世界需要多少时间才能进入该地区?

    5. ios – iBeacon:didEnterRegion和didDetermineState(CLRegionStateInside)之间有什么区别?

      当用户进入某个地区时,我想发布通知.但是,由于同样的两个CLLocationManagerDelegate方法,我很困惑.如何正确使用这两种方法?有些人说如果应用程序在该区域启动,则需要“didDetermineState”方法来启动区域观察.谢谢,解决方法苹果的documentationforCLLocationManager状态:Thelocationmanagercallsthismetho

    6. ios – 如何从核心蓝牙设备读取信息

      >如何阅读蓝牙设备的其他信息?

    7. ios – 在开发过程中应该如何使用identifierForVendor?

      解决方法在模拟器中构建和运行时,这个值将会改变.在真实的设备上,只有当用户从设备中删除所有应用并重新安装应用时,才会更改.如果您希望模拟器应用程序在开发期间使用一致的标识符,您可以定义该UUID,并将其用于模拟器构建:请注意,您需要用真实的UUID字符串替换SOME-STATIC-UUID-STRING.

    8. ios – 通过UUID编写CBC特征

      我试图用CoreBluetooth写一个特定的,已知的特征.我觉得这应该是可能的,因为我使用了一个德州仪器BLE实用程序,您可以在连接的外设上选择一个“写值”操作,只需输入特征UUID和您要编写的值,并且执行没有问题.据我了解,为了做到这一点,我必须打电话配置为具有正确的UUID的CBC特征对象.我已经尝试使用正确的UUID进行CBMutableCharacteristic,甚至正确的权限,我知道

    9. ios – 扫描特定CBUUID时,Core Bluetooth无法找到外围设备

      似乎这个问题被“回答”了here,但没有任何代码来表明他们做了不同的事情,我不得不问一个新问题.我有自己的代码具有相同的行为,在OSX上使用CoreBluetooth的CBCentralManager扫描特定的CBUUID并没有发现一个iOS设备充当CBPeripheralManager的外围设备(除非它及其服务先前已被发现).为了查看我的代码是否有问题,我下载了Apple’ssamplecode

    10. 如何在不使用登录系统的情况下识别唯一用户(iOS)

      我可以从设备获得的任何类型,而无需用户填写任何字段.解决方法您可以尝试使用存储在用户的iCloud中的键值存储中的一些唯一随机字符串.因此,当用户第一次启动您的应用时,您会发现他的iCloud没有存储任何值,因此您生成并存储它.当用户下次启动应用程序时,您将看到此值,并将采取相应措施.更重要的是,即使用户将重新安装您的应用程序或将重置设备,您仍然可以在他的iCloud中按值识别用户.

    随机推荐

    1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

      下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

    2. swift UISlider,UIStepper

      我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

    3. preferredFontForTextStyle字体设置之更改

      即:

    4. Swift没有异常处理,遇到功能性错误怎么办?

      本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

    5. 字典实战和UIKit初探

      ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

    6. swift语言IOS8开发战记21 Core Data2

      上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

    7. swift语言IOS8开发战记22 Core Data3

      上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

    8. swift实战小程序1天气预报

      在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

    9. 【iOS学习01】swift ? and !  的学习

      如果不初始化就会报错。

    10. swift语言IOS8开发战记23 Core Data4

      接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

    返回
    顶部