美文网首页iOS蓝牙开发
iBeacon开发之IoT&Swift&OC&iOS

iBeacon开发之IoT&Swift&OC&iOS

作者: 贵叔勇闯天涯 | 来源:发表于2023-09-17 17:52 被阅读0次
    前言

    蓝牙设备想必大家都很熟悉了,相关的开发资料也是很多了,这里就不必多说了
    iOS蓝牙的开发专题
    iOS蓝牙开发(一)蓝牙相关基础知识
    iOS蓝牙开发(二)ios连接外设的代码实现
    iOS蓝牙开发(三)app作为外设被连接的实现
    iOS蓝牙开发(四)BabyBluetooth蓝牙库介绍

    iBeacon 是苹果公司2013年9月发布的移动设备用OS(iOS7)上配备的新功能。其工作方式是,配备有 低功耗蓝牙(BLE)通信功能的设备使用BLE技术向周围发送自己特有的ID,接收到该ID的应用软件会根据该ID采取一些行动。比如,在店铺里设置iBeacon通信模块的话,便可让iPhone和iPad上运行一资讯告知服务器,或者由服务器向顾客发送折扣券及进店积分。此外,还可以在家电发生故障或停止工作时使用iBeacon向应用软件发送资讯。
    苹果 WWDC 14 之后,对 iBeacon 加大了技术支持和对其用于室内地图的应用有个更明确的规划。苹果公司公布了 iBeacon for Developers 和 Maps for Developers 等专题页面。

    应用场景
    • 侦测iPhone进入或者离开某个iBeacon的范围触发事件
    • 侦测iPhone跟iBeacon的距离,依据不同的距离触发事件
      1.比如,当你在国家博物馆参观的时候,当你走进《四羊方尊》前,APP侦测到装在这个藏品展牌底座的iBeacon,于是APP就开始自动播放相关的介绍,透过AirPods传进你的耳朵,这样的讲解真的也算是一种创新!
      2.再比如,在地下车库按照三点确定一个稳定区域的设计,布置好iBeacon设备,也能设计出一套室内导航的方案!
    如何获得

    如何去获得这样的设备呢?其实你打开某宝某多某东,这类的产品数不胜数。
    其实你只是在开发阶段,也可以自己去模拟一个iBeacon的设备。因为做iOS开发的我们都有一台iPhone&Mac,高版本的设备都有变身成iBeacon的蓝牙(bluetooth)能力。

    将Mac或者iPhone变成iBeacon

    -方法1: [Apple官方文档-将iPhone变成iBeacon(https://developer.apple.com/documentation/corelocation/turning_an_ios_device_into_an_ibeacon_device)

    • 方法2:可以下载一个APP将iPhone/iPad变成iBeacon设备下载APP

      IMG_9119.PNG
    • 我们可以下载别人已经开发好的应用,安装到我们的Mac上:MactsAsBeacon
      然后再去设定它的UUID、major、minor,然后再点击Start按钮,此时你的Mac就配置了一个iBeacon设备,开始发出讯号。

    image.png

    如果你想修改UUID,可以使用下列方法:
    1.打开终端(terminal)
    2.输入

    uuidgen
    

    3.回车按键


    image.png

    ps: 该项目比较老旧,运行会报错,
    解决方案:
    在Info.plist文件中,右键单击空白区域,选择 "Add Row" 添加一行。
    在新添加的行中,将键名设置为NSBluetoothAlwaysUsageDescription。
    在该键的值字段中,提供一条简明扼要的描述,说明您的应用程序为何需要蓝牙权限。例如,您可以写一句话,解释您的应用程序如何使用蓝牙,例如:"用于搜索和连接附近的蓝牙设备"。
    保存Info.plist文件并重新构建您的应用程序。
    这样做后,您的应用程序将在请求蓝牙权限时显示您提供的描述,以便用户了解为什么需要这些权限,并可以选择允许或拒绝访问。

    请确保您的应用程序遵循隐私权规定,并提供清晰的权限描述,以确保用户的隐私权得到尊重。

    iBeacon的参数相关

    每个设备都有UUID(128bit),major(16bit),minor(16bit);因此我们可以透过这三个标识区分不同的iBeacon。

    • 让设备具有相同的UUID & major,利用minor区分
    • 让设备具有相同的UUID,利用major & minor区分
    • 利用UUID,major,minor来区分
      如果不是很复杂的需求,其实前两种区分即可,比如上述的博物馆游览;如果你有分店(UUID)、产品分类(major)和不同产品(minor),就可以用第三种方案。
    开发 iBeacon 的 iOS App

    这里有官方的相关参考说明
    Determining the proximity to an iBeacon device
    1. 加入获取位置的权限描述说明
    依据Apple以下表格的说明,为了侦测iPhone进入某个iBeacon范围,量测iBeacon间的距离,我们需要在info.plist配置里加入以下两种权限的描述说明:
    Apple官方说明:Choosing the Location Services Authorization to Request

    image.png
    Privacy — Location Always and When In Use Usage Description 
    为了获取博物馆的展品iBeacon信号,请允许获取你的位置
    
    Privacy — Location When In Use Usage Description
    为了获取博物馆的展品iBeacon信号,请允许获取你的位置
    

    2. 建立 CLLocationManager,将 controller 设置为 CLLocationManager 的 delegate 且 要求获取位置的权限

    import CoreLocation
    
    class ViewController: UIViewController {
       var locationManager: CLLocationManager!
       override func viewDidLoad() {
          super.viewDidLoad()
          locationManager = CLLocationManager()
          locationManager.delegate = self
          locationManager.requestAlwaysAuthorization()
    }
    extension ViewController: CLLocationManagerDelegate {
    }
    

    3. 开始侦测iBeacon

    func monitorBeacons() {
       if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
          let proximityUUID = UUID(uuidString: "B0702880-A295-A8AB-F734-031A98A512DE")
          let beaconId = "deeplove"
          let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
          locationManager.startMonitoring(for: region)
       }
    }
    override func viewDidLoad() {
       super.viewDidLoad()
       locationManager = CLLocationManager()
       locationManager.delegate = self
       locationManager.requestAlwaysAuthorization()
       monitorBeacons()
    }
    

    说明
    (1) 利用CLBeaconRegion指定你想要侦测的iBeacon
    Apple官方文档:CLBeaconRegion

    let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
    

    产生CLBeaconRegion的方法有三种:

    public init(proximityUUID: UUID, identifier: String)
    public init(proximityUUID: UUID, major: CLBeaconMajorValue, identifier: String)
    public init(proximityUUID: UUID, major: CLBeaconMajorValue, minor: CLBeaconMinorValue, identifier: String)
    

    在刚刚的例子里,我们假设目前只有一个iBeacon设备,因此利用UUID来区分设备足以,不需要用到major和minor(ps:请记得UUID要和刚刚在Mac iBeacon APP上设定的UUID一致,如此才能侦测到化身iBeacon的Mac)

    let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
    

    (2) 开始侦测是否进入/离开iBeacon的范围

    locationManager.startMonitoring(for: region)
    

    4. 定义CLLocationManagerDelegate 的 function 侦测进入/离开iBeacon的范围

    extension ViewController: CLLocationManagerDelegate {
       func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
          print("enter region")
       }
       func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
          print("exit region")
       }
    }
    

    5. 计算距离
    有时候我们还想进一步知道iPhone和iBeacon之间的距离,Apple将距离粗略的分为四个等级,由近及远:Immediate 、Near、Far、Unknown

    image.png
    比方在看博物馆展览时,我们希望走到展品前时 App 才呈现相关的资讯,於是我们可从程式判断距离為 Immediate 时显示展品资讯,如此才不会距离画作还有一大段距离,连画都看不清楚时就奇怪地显示展品资讯。
    extension ViewController: CLLocationManagerDelegate {
       func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
          print("enter region")
          if CLLocationManager.isRangingAvailable() {
             locationManager.startRangingBeacons(in: region as! CLBeaconRegion)
          }
       }
       func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
          print("exit region")
          locationManager.stopRangingBeacons(in: region as! CLBeaconRegion)
       }
    }
    

    说明:

    利用 startRangingBeacons & stopRangingBeacons 开始 / 停止侦测 iPhone & beacon 的距离。我们在 locationManager(_:didEnterRegion:) 裡才开始侦测距离,因為侦测距离比较耗电,它将不断地量测更新距离。

    不过有一点值得注意的,实测时发现 locationManager(:didEnterRegion:) 有可能没被触发,进而让程式不会呼叫 startRangingBeacons,因此永远不会侦测到 iPhone 已经在 beacon 旁边。比方若你原本就在 beacon 范围裡,locationManager(:didEnterRegion:) 将不会被触发。因此测试时最好一开始远离 beacon,在 beacon 范围之外,然后再慢慢地靠近 beacon,进入 beacon 的范围,这样较容易触发 locationManager(_:didEnterRegion:)。(ps: 若想确保我们一定能侦测到 iPhone 就在 beacon 旁边,另一种做法是一开始就同时呼叫 startMonitoring & startRangingBeacons)

    let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
    locationManager.startMonitoring(for: region)
    locationManager.startRangingBeacons(in: region)
    

    6. 定义 CLLocationManagerDelegate 的 function 量测距离。
    从 CLBeacon 物件的 proximity 判断距离。当我们在 beacon 附近时,此 function 将不断被呼叫,告诉我们最新的距离资讯。

    func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
       if beacons.count > 0 {
          let nearestBeacon = beacons[0]
          print(nearestBeacon.proximityUUID, nearestBeacon.major, nearestBeacon.minor)
          switch nearestBeacon.proximity {
          case .immediate:
             print("immediate")
        
          case .near:
             print("near")
          case .far:
             print("far")
          case .unknown:
             print("unknown")
          @unknown default:
             print("@unknown default")
          }
       }
    }
    

    实验:

    利用 Mac 当 iBeacon,然后啟动刚刚开发的程式侦测 beacon,我们可利用此难得的机会运动一下,走走路让 iPhone 靠近和远离 Mac,观察 locationManager(_:didRangeBeacons:in:) 裡 CLBeacon 距离的变化。

    在APP进入后台侦测 beacon & 显示通知
    我们也可以在APP进入后台侦测 beacon,甚至在 App 没启动但进入 beacon 范围时,由 iOS 自动啟动 App,然后触发 locationManager:didEnterRegion:。比方以下例子,我们在 locationManager:didEnterRegion: 触发时显示通知讯息:

    func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
       let content = UNMutableNotificationContent()
       content.title = "注意"
       content.subtitle = "小明就在你身邊"
       content.badge = 1
       content.sound = UNNotificationSound.default
       let request = UNNotificationRequest(identifier: "notification", content: content, trigger: nil)
       UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
       if CLLocationManager.isRangingAvailable() {
          locationManager.startRangingBeacons(in: region as! CLBeaconRegion)
       }
    }
    

    為了显示通知,记得要先请求使用者的同意。

    import UIKit
    import UserNotifications
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
       var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { granted, error in
          if granted {
          } else {
             print("使用者不同意[图片上传中...(IMG_9120.PNG-dd714c-1695030587401-0)]
    ,哭哭!")
          }
       })
       return true
    }
    

    实验步骤:

    安装 App,然后啟动 App 同意权限后,先将它杀掉,维持 App 不啟动的状态。
    把 iPhone 收进胸前左边口袋,走到远离 beacon 的天涯海角散心。
    从天涯海角出发,朝著心爱的 beacon 方向前进。

    一旦进入 beacon 的讯号范围,此时将触发 function locationManager:didEnterRegion:,口袋裡的 iPhone 将传来通知声音,显示著通知讯息,xxx就在你身边。 IMG_9120.PNG
    ps:

    若你原本就在 beacon 范围裡,locationManager(_:didEnterRegion:) 将不会被触发。因此测试时请记得先远离 beacon。

    1. 根据 Apple 文件的说明,为了在APP进入后台侦测到进入 beacon 范围时启动 App,我们得将 Capabilities 页面 Background Modes 的 Location Updates 打开。不过根据实测的结果,不需打开 Location Updates 一样可触发 locationManager:didEnterRegion: & application(_:didFinishLaunchingWithOptions:)。
      Handling location updates in the background
      image.png
      image.png
    image.png

    相关文章

      网友评论

        本文标题:iBeacon开发之IoT&Swift&OC&iOS

        本文链接:https://www.haomeiwen.com/subject/uadwvdtx.html