如何使用 iPad 5 in Swift 4 来宣传 iBeacon
How to advertise an iBeacon using an iPad 5 in Swift 4
所以我找到了一个关于使用 iBeacons 的好教程,我创建了一个接收器和一个广播器,但是当我 运行 代码时,我看不到有任何信标正在广播。有没有人有好的解决方案可以解决我的问题?
import UIKit
import CoreLocation
import CoreBluetooth
import Foundation
/// ibeacon class
class iBeaconConfiguration
{
// You can use uuidgen in terminal to generate new one.
static let uuid = UUID(uuidString: "7FA08BC7-A55F-45FC-85C0-0BF26F899530")!
private init() {}
}
如果您想知道,上面的 class 仅用于 UUID
class BroadcastViewController: UIViewController {
fileprivate var broadcasting: Bool = false
fileprivate var beacon: CLBeaconRegion?
fileprivate var peripheralManager: CBPeripheralManager?
@IBOutlet var statusLabel: UILabel!
@IBOutlet var triggerButton: UIButton!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.setNeedsStatusBarAppearanceUpdate()
}
override func viewDidLoad() {
super.viewDidLoad()
statusLabel = UILabel()
triggerButton = UIButton(frame: CGRect(x: 130, y: 10, width: 100, height: 50))
triggerButton.backgroundColor = UIColor.blue
triggerButton.addTarget(self, action: #selector(broadcastBeacon(sender:)), for: .touchUpInside)
self.view.addSubview(triggerButton)
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 50, height: 50))
button.backgroundColor = UIColor.red
button.addTarget(self, action: #selector(dismiss1), for: .touchUpInside)
self.view.addSubview(button)
self.view.backgroundColor = UIColor.white
let UUID: UUID = iBeaconConfiguration.uuid
let major: CLBeaconMajorValue = CLBeaconMajorValue(arc4random() % 100 + 1)
let minor: CLBeaconMinorValue = CLBeaconMinorValue(arc4random() % 2 + 1)
self.beacon = CLBeaconRegion(proximityUUID: UUID, major: major, minor: minor, identifier: "tw.darktt.beaconDemo")
self.peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
}
deinit
{
self.beacon = nil
self.peripheralManager = nil
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func dismiss1() {
//self.dismiss(animated: true, completion: nil)
present(ReceiverViewController(), animated: true, completion: nil)
}
}
// MARK: - Status Bar -
extension BroadcastViewController {
override var preferredStatusBarStyle: UIStatusBarStyle
{
if self.broadcasting {
return .lightContent
}
return .default
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation
{
return .fade
}
override var prefersStatusBarHidden: Bool
{
return false
}
}
//MARK: - Actions -
extension BroadcastViewController {
@IBAction fileprivate func broadcastBeacon(sender: UIButton) -> Void
{
let state: CBManagerState = self.peripheralManager!.state
if (state == .poweredOff && !self.broadcasting) {
let OKAction: UIAlertAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
let alert: UIAlertController = UIAlertController(title: "Bluetooth OFF", message: "Please power on your Bluetooth!", preferredStyle: .alert)
alert.addAction(OKAction)
self.present(alert, animated: true, completion: nil)
return
}
let titleFromStatus: (Void) -> String = {
let title: String = (self.broadcasting) ? "Start" : "Stop"
return title + " Broadcast"
}
let buttonTitleColor: UIColor = (self.broadcasting) ? UIColor.blue : UIColor.white
sender.setTitle("nil", for: .normal)
sender.setTitleColor(buttonTitleColor, for: .normal)
let labelTextFromStatus: (Void) -> String = {
let text: String = (self.broadcasting) ? "Not Broadcast" : "Broadcasting..."
return text
}
self.statusLabel.text = "broadcast started"
let animations: () -> Void = {
let backgroundColor: UIColor = (self.broadcasting) ? UIColor.white : UIColor.blue
self.view.backgroundColor = backgroundColor
self.broadcasting = !self.broadcasting
self.setNeedsStatusBarAppearanceUpdate()
}
let completion: (Bool) -> Void = {
finish in
self.advertising(start: self.broadcasting)
}
UIView.animate(withDuration: 0.25, animations: animations, completion: completion)
}
// MARK: - Broadcast Beacon
func advertising(start: Bool) -> Void
{
if self.peripheralManager == nil {
return
}
if (!start) {
self.peripheralManager!.stopAdvertising()
return
}
let state: CBManagerState = self.peripheralManager!.state
if (state == .poweredOn) {
let UUID:UUID = (self.beacon?.proximityUUID)!
let serviceUUIDs: Array<CBUUID> = [CBUUID(nsuuid: UUID)]
// Why NSMutableDictionary can not convert to Dictionary<String, Any>
var peripheralData: Dictionary<String, Any> = self.beacon!.peripheralData(withMeasuredPower: 1) as NSDictionary as! Dictionary<String, Any>
peripheralData[CBAdvertisementDataLocalNameKey] = "iBeacon Demo"
peripheralData[CBAdvertisementDataServiceUUIDsKey] = serviceUUIDs
self.peripheralManager!.startAdvertising(peripheralData)
}
}
}
// MARK: - CBPeripheralManager Delegate -
extension BroadcastViewController: CBPeripheralManagerDelegate {
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager)
{
let state: CBManagerState = peripheralManager!.state
if state == .poweredOff {
self.statusLabel.text = "Bluetooth Off"
if self.broadcasting {
self.broadcastBeacon(sender: self.triggerButton)
}
}
if state == .unsupported {
self.statusLabel.text = "Unsupported Beacon"
}
if state == .poweredOn {
self.statusLabel.text = "Not Broadcast"
}
}
}
除此之外,我还阅读了苹果网站上的文档,但我并没有深入了解。我也去了可能喜欢的 10 个不同的 Github 项目并尝试了它们,但它们都是以 swift.
的早期版本的方式编写的
假设您有一个正在运行的 iBeacon 扫描应用程序(否则,很难知道您的设备是否正确广播)...
我建议从简单开始...让 "start broadcasting" 部分正常工作,然后添加其他内容。
创建一个新项目(或向当前项目添加一个新的 VC)。添加 "Start" 和 "Stop" 按钮,您将连接到下面的 @IBAction
函数。
将此设为您的新 VC 的 class:
//
// BroadcasterViewController.swift
//
// Created by Don Mag on 3/16/18.
//
import UIKit
import CoreLocation
import CoreBluetooth
class BroadcasterViewController: UIViewController, CBPeripheralManagerDelegate {
var myBeacon: CLBeaconRegion!
var beaconData: NSDictionary!
var peripheralMgr: CBPeripheralManager!
let myRegionID = "myRegionID"
@IBAction func startBeacon(_ sender: Any) {
// don't do anything if myBeacon already exists
guard myBeacon == nil else { return }
let beaconUUID = "7FA08BC7-A55F-45FC-85C0-0BF26F899530"
let beaconMajor: CLBeaconMajorValue = 123
let beaconMinor: CLBeaconMinorValue = 456
let uuid = UUID(uuidString: beaconUUID)!
myBeacon = CLBeaconRegion(proximityUUID: uuid, major: beaconMajor, minor: beaconMinor, identifier: "MyIdentifier")
beaconData = myBeacon.peripheralData(withMeasuredPower: nil)
peripheralMgr = CBPeripheralManager(delegate: self, queue: nil, options: nil)
}
@IBAction func stopBeacon(_ sender: Any) {
// don't do anything if there's no peripheral manager
guard peripheralMgr != nil else { return }
peripheralMgr.stopAdvertising()
peripheralMgr = nil
beaconData = nil
myBeacon = nil
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
peripheralMgr.startAdvertising(beaconData as! [String: AnyObject]!)
} else if peripheral.state == .poweredOff {
peripheralMgr.stopAdvertising()
}
}
}
运行 您 "broadcaster" 设备上的应用程序,然后点击“开始”按钮。然后 运行 你的 "scanner" 应用程序在另一台设备上,看看你是否找到你的新 "Device as iBeacon"
注意:我相信您已经知道,您的扫描器必须正在扫描与您在广播设备上使用的相同的beaconUUID
。在此示例代码中,我使用了您在问题中发布的相同 UUID 字符串。
这对我来说效果很好 - 希望它对您也能起到同样的作用。如果 这部分 正常工作,那么您可以实现应用程序的其余部分——UI、状态标签、任何其他选项——并添加一些错误处理(蓝牙未启用或未授予权限等)。
您不能向 iBeacon 广告添加任何额外内容并使其被识别。这两行是个问题,必须删除:
peripheralData[CBAdvertisementDataLocalNameKey] = "iBeacon Demo"
peripheralData[CBAdvertisementDataServiceUUIDsKey] = serviceUUIDs
第一行试图在广告中添加广播名称。您不能这样做,因为数据包中没有额外的空间用于此类信息。
第二行试图在广告中添加 GATT 服务 UUID。这根本不符合逻辑。 iBeacon 广告是蓝牙 LE 制造商广告,它不广告 GATT 服务。添加这将使广告无效或导致广告 API 失败。
显示的代码可能存在其他问题。我建议简化代码以在应用程序启动时启动传输,这样您就可以消除任何可能的 UI 错误。我会使用像 Locate 这样的 Android 检测器,这样即使您的 ProximityUIID 错误,您也可以看到广告。 Android,不像iOS可以看到任何信标广告。
所以我找到了一个关于使用 iBeacons 的好教程,我创建了一个接收器和一个广播器,但是当我 运行 代码时,我看不到有任何信标正在广播。有没有人有好的解决方案可以解决我的问题?
import UIKit
import CoreLocation
import CoreBluetooth
import Foundation
/// ibeacon class
class iBeaconConfiguration
{
// You can use uuidgen in terminal to generate new one.
static let uuid = UUID(uuidString: "7FA08BC7-A55F-45FC-85C0-0BF26F899530")!
private init() {}
}
如果您想知道,上面的 class 仅用于 UUID
class BroadcastViewController: UIViewController {
fileprivate var broadcasting: Bool = false
fileprivate var beacon: CLBeaconRegion?
fileprivate var peripheralManager: CBPeripheralManager?
@IBOutlet var statusLabel: UILabel!
@IBOutlet var triggerButton: UIButton!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.setNeedsStatusBarAppearanceUpdate()
}
override func viewDidLoad() {
super.viewDidLoad()
statusLabel = UILabel()
triggerButton = UIButton(frame: CGRect(x: 130, y: 10, width: 100, height: 50))
triggerButton.backgroundColor = UIColor.blue
triggerButton.addTarget(self, action: #selector(broadcastBeacon(sender:)), for: .touchUpInside)
self.view.addSubview(triggerButton)
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 50, height: 50))
button.backgroundColor = UIColor.red
button.addTarget(self, action: #selector(dismiss1), for: .touchUpInside)
self.view.addSubview(button)
self.view.backgroundColor = UIColor.white
let UUID: UUID = iBeaconConfiguration.uuid
let major: CLBeaconMajorValue = CLBeaconMajorValue(arc4random() % 100 + 1)
let minor: CLBeaconMinorValue = CLBeaconMinorValue(arc4random() % 2 + 1)
self.beacon = CLBeaconRegion(proximityUUID: UUID, major: major, minor: minor, identifier: "tw.darktt.beaconDemo")
self.peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
}
deinit
{
self.beacon = nil
self.peripheralManager = nil
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func dismiss1() {
//self.dismiss(animated: true, completion: nil)
present(ReceiverViewController(), animated: true, completion: nil)
}
}
// MARK: - Status Bar -
extension BroadcastViewController {
override var preferredStatusBarStyle: UIStatusBarStyle
{
if self.broadcasting {
return .lightContent
}
return .default
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation
{
return .fade
}
override var prefersStatusBarHidden: Bool
{
return false
}
}
//MARK: - Actions -
extension BroadcastViewController {
@IBAction fileprivate func broadcastBeacon(sender: UIButton) -> Void
{
let state: CBManagerState = self.peripheralManager!.state
if (state == .poweredOff && !self.broadcasting) {
let OKAction: UIAlertAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
let alert: UIAlertController = UIAlertController(title: "Bluetooth OFF", message: "Please power on your Bluetooth!", preferredStyle: .alert)
alert.addAction(OKAction)
self.present(alert, animated: true, completion: nil)
return
}
let titleFromStatus: (Void) -> String = {
let title: String = (self.broadcasting) ? "Start" : "Stop"
return title + " Broadcast"
}
let buttonTitleColor: UIColor = (self.broadcasting) ? UIColor.blue : UIColor.white
sender.setTitle("nil", for: .normal)
sender.setTitleColor(buttonTitleColor, for: .normal)
let labelTextFromStatus: (Void) -> String = {
let text: String = (self.broadcasting) ? "Not Broadcast" : "Broadcasting..."
return text
}
self.statusLabel.text = "broadcast started"
let animations: () -> Void = {
let backgroundColor: UIColor = (self.broadcasting) ? UIColor.white : UIColor.blue
self.view.backgroundColor = backgroundColor
self.broadcasting = !self.broadcasting
self.setNeedsStatusBarAppearanceUpdate()
}
let completion: (Bool) -> Void = {
finish in
self.advertising(start: self.broadcasting)
}
UIView.animate(withDuration: 0.25, animations: animations, completion: completion)
}
// MARK: - Broadcast Beacon
func advertising(start: Bool) -> Void
{
if self.peripheralManager == nil {
return
}
if (!start) {
self.peripheralManager!.stopAdvertising()
return
}
let state: CBManagerState = self.peripheralManager!.state
if (state == .poweredOn) {
let UUID:UUID = (self.beacon?.proximityUUID)!
let serviceUUIDs: Array<CBUUID> = [CBUUID(nsuuid: UUID)]
// Why NSMutableDictionary can not convert to Dictionary<String, Any>
var peripheralData: Dictionary<String, Any> = self.beacon!.peripheralData(withMeasuredPower: 1) as NSDictionary as! Dictionary<String, Any>
peripheralData[CBAdvertisementDataLocalNameKey] = "iBeacon Demo"
peripheralData[CBAdvertisementDataServiceUUIDsKey] = serviceUUIDs
self.peripheralManager!.startAdvertising(peripheralData)
}
}
}
// MARK: - CBPeripheralManager Delegate -
extension BroadcastViewController: CBPeripheralManagerDelegate {
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager)
{
let state: CBManagerState = peripheralManager!.state
if state == .poweredOff {
self.statusLabel.text = "Bluetooth Off"
if self.broadcasting {
self.broadcastBeacon(sender: self.triggerButton)
}
}
if state == .unsupported {
self.statusLabel.text = "Unsupported Beacon"
}
if state == .poweredOn {
self.statusLabel.text = "Not Broadcast"
}
}
}
除此之外,我还阅读了苹果网站上的文档,但我并没有深入了解。我也去了可能喜欢的 10 个不同的 Github 项目并尝试了它们,但它们都是以 swift.
的早期版本的方式编写的假设您有一个正在运行的 iBeacon 扫描应用程序(否则,很难知道您的设备是否正确广播)...
我建议从简单开始...让 "start broadcasting" 部分正常工作,然后添加其他内容。
创建一个新项目(或向当前项目添加一个新的 VC)。添加 "Start" 和 "Stop" 按钮,您将连接到下面的 @IBAction
函数。
将此设为您的新 VC 的 class:
//
// BroadcasterViewController.swift
//
// Created by Don Mag on 3/16/18.
//
import UIKit
import CoreLocation
import CoreBluetooth
class BroadcasterViewController: UIViewController, CBPeripheralManagerDelegate {
var myBeacon: CLBeaconRegion!
var beaconData: NSDictionary!
var peripheralMgr: CBPeripheralManager!
let myRegionID = "myRegionID"
@IBAction func startBeacon(_ sender: Any) {
// don't do anything if myBeacon already exists
guard myBeacon == nil else { return }
let beaconUUID = "7FA08BC7-A55F-45FC-85C0-0BF26F899530"
let beaconMajor: CLBeaconMajorValue = 123
let beaconMinor: CLBeaconMinorValue = 456
let uuid = UUID(uuidString: beaconUUID)!
myBeacon = CLBeaconRegion(proximityUUID: uuid, major: beaconMajor, minor: beaconMinor, identifier: "MyIdentifier")
beaconData = myBeacon.peripheralData(withMeasuredPower: nil)
peripheralMgr = CBPeripheralManager(delegate: self, queue: nil, options: nil)
}
@IBAction func stopBeacon(_ sender: Any) {
// don't do anything if there's no peripheral manager
guard peripheralMgr != nil else { return }
peripheralMgr.stopAdvertising()
peripheralMgr = nil
beaconData = nil
myBeacon = nil
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
peripheralMgr.startAdvertising(beaconData as! [String: AnyObject]!)
} else if peripheral.state == .poweredOff {
peripheralMgr.stopAdvertising()
}
}
}
运行 您 "broadcaster" 设备上的应用程序,然后点击“开始”按钮。然后 运行 你的 "scanner" 应用程序在另一台设备上,看看你是否找到你的新 "Device as iBeacon"
注意:我相信您已经知道,您的扫描器必须正在扫描与您在广播设备上使用的相同的beaconUUID
。在此示例代码中,我使用了您在问题中发布的相同 UUID 字符串。
这对我来说效果很好 - 希望它对您也能起到同样的作用。如果 这部分 正常工作,那么您可以实现应用程序的其余部分——UI、状态标签、任何其他选项——并添加一些错误处理(蓝牙未启用或未授予权限等)。
您不能向 iBeacon 广告添加任何额外内容并使其被识别。这两行是个问题,必须删除:
peripheralData[CBAdvertisementDataLocalNameKey] = "iBeacon Demo"
peripheralData[CBAdvertisementDataServiceUUIDsKey] = serviceUUIDs
第一行试图在广告中添加广播名称。您不能这样做,因为数据包中没有额外的空间用于此类信息。
第二行试图在广告中添加 GATT 服务 UUID。这根本不符合逻辑。 iBeacon 广告是蓝牙 LE 制造商广告,它不广告 GATT 服务。添加这将使广告无效或导致广告 API 失败。
显示的代码可能存在其他问题。我建议简化代码以在应用程序启动时启动传输,这样您就可以消除任何可能的 UI 错误。我会使用像 Locate 这样的 Android 检测器,这样即使您的 ProximityUIID 错误,您也可以看到广告。 Android,不像iOS可以看到任何信标广告。