我已经看过几次这个问题,但似乎没有人找到合适的答案,所以我会再次发帖。
我正在使用 Swift 3 和Xcode扫描 BLE外设。然后,如果它们具有某个名称('THX_BLE').
点击后,即可建立连接。
现在这是我似乎无法理解的有趣部分。根据几个文档,当连接到外设的成功连接时,函数didConnectPeripheral()将被调用。
现在我正在使用HM10蓝牙UART BLE模块,它上面有一个LED指示灯,告诉您是否连接。灯停止闪烁并告诉我我已连接。
这个模块可能是真实的或假的,但无论哪种方式都无关紧要,其功能是相同的。
那么为什么不调用这个方法呢?这一切都在一个类中。
感谢。
以下是整个视图代码:
import UIKit
import CoreBluetooth
// Conform to CBCentralManagerDelegate, CBPeripheralDelegate protocols
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate, UITableViewDataSource, UITableViewDelegate {
//MARK: IBOutlets
@IBOutlet weak var deviceTable: UITableView!
@IBOutlet weak var searchButton: UIButton!
@IBOutlet weak var helpButton: UIButton!
//MARK: Variables
var centralManager:CBCentralManager!
var sensorTag:CBPeripheral?
var keepScanning = false
let timerPauseInterval:TimeInterval = 10.0
let timerScanInterval:TimeInterval = 2.0
var peripherals = Array<CBPeripheral>()
let cellSpacingHeight: CGFloat = 10
let deviceName = " THX_BLE"
//MARK: Functions
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
view.backgroundColor = UIColor(red: 28/255.0, green: 34/255.0, blue: 60/255.0, alpha: 1.0)
deviceTable.alwaysBounceVertical = false
searchButton.layer.cornerRadius=10
searchButton.layer.borderColor = UIColor.white.cgColor
searchButton.layer.borderWidth = 2
searchButton.contentEdgeInsets = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)
helpButton.layer.cornerRadius=10
helpButton.layer.borderColor = UIColor.white.cgColor
helpButton.layer.borderWidth = 2
helpButton.contentEdgeInsets = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)
centralManager = CBCentralManager(delegate: self, queue: nil)
}
override func viewDidAppear(_ animated: Bool) {
UINavigationBar.appearance().tintColor = UIColor.white
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Hide the navigation bar on the this view controller
self.navigationController?.setNavigationBarHidden(true, animated: animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Show the navigation bar on other view controllers
self.navigationController?.setNavigationBarHidden(false, animated: animated)
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return (peripherals.count)
}
// Set the spacing between sections
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return cellSpacingHeight
}
// Make the background color show through
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = UIColor.clear
return headerView
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
cell.layer.cornerRadius=20 //set corner radius here
cell.layer.borderColor = UIColor.white.cgColor // set cell border color here
cell.layer.borderWidth = 2 // set border width here
let peripheral = peripherals[indexPath.row]
cell.myLabel?.text = peripheral.name
return (cell)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60.0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! ViewControllerTableViewCell
cell.myLabel.textColor = UIColor.black
deviceTable.reloadRows(at: [indexPath], with: UITableViewRowAnimation.none)
cell.myLabel?.textColor = UIColor.white
print("Forming connection with device")
// Request a connection to the peripheral
// save a reference to the sensor tag
let peripheral = peripherals[indexPath.row]
sensorTag = peripheral
sensorTag!.delegate = self
centralManager.connect(sensorTag!, options: nil)
centralManager.stopScan()
// let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
// let nextViewController = storyBoard.instantiateViewController(withIdentifier: "presetController") as! PresetViewController
// self.navigationController?.pushViewController(nextViewController, animated: true)
}
// MARK: - CBCentralManagerDelegate methods
// Invoked when the central manager’s state is updated.
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("Did update state called")
var showAlert = true
var message = ""
switch central.state {
case .poweredOff:
message = "Bluetooth on this device is currently powered off."
case .unsupported:
message = "This device does not support Bluetooth Low Energy."
case .unauthorized:
message = "This app is not authorized to use Bluetooth Low Energy."
case .resetting:
message = "The BLE Manager is resetting; a state update is pending."
case .unknown:
message = "The state of the BLE Manager is unknown."
case .poweredOn:
showAlert = false
message = "Bluetooth LE is turned on and ready for communication."
print(message)
keepScanning = true
_ = Timer(timeInterval: timerScanInterval, target: self, selector: #selector(pauseScan), userInfo: nil, repeats: false)
// Initiate Scan for Peripherals
//Option 1: Scan for all devices
centralManager.scanForPeripherals(withServices: nil, options: nil)
// Option 2: Scan for devices that have the service you're interested in...
//let sensorTagAdvertisingUUID = CBUUID(string: Device.SensorTagAdvertisingUUID)
//print("Scanning for SensorTag adverstising with UUID: \(sensorTagAdvertisingUUID)")
//centralManager.scanForPeripheralsWithServices([sensorTagAdvertisingUUID], options: nil)
}
if showAlert {
let alertController = UIAlertController(title: "Central Manager State", message: message, preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
alertController.addAction(okAction)
self.show(alertController, sender: self)
}
}
// MARK: - Bluetooth scanning
@objc func pauseScan() {
// Scanning uses up battery on phone, so pause the scan process for the designated interval.
print("*** PAUSING SCAN...")
_ = Timer(timeInterval: timerPauseInterval, target: self, selector: #selector(resumeScan), userInfo: nil, repeats: false)
centralManager.stopScan()
}
@objc func resumeScan() {
if keepScanning {
// Start scanning again...
print("*** RESUMING SCAN!")
_ = Timer(timeInterval: timerScanInterval, target: self, selector: #selector(pauseScan), userInfo: nil, repeats: false)
centralManager.scanForPeripherals(withServices: nil, options: nil)
} else {
}
}
/*
Invoked when the central manager discovers a peripheral while scanning.
The advertisement data can be accessed through the keys listed in Advertisement Data Retrieval Keys.
You must retain a local copy of the peripheral if any command is to be performed on it.
In use cases where it makes sense for your app to automatically connect to a peripheral that is
located within a certain range, you can use RSSI data to determine the proximity of a discovered
peripheral device.
central - The central manager providing the update.
peripheral - The discovered peripheral.
advertisementData - A dictionary containing any advertisement data.
RSSI - The current received signal strength indicator (RSSI) of the peripheral, in decibels.
*/
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
// print("centralManager didDiscoverPeripheral - CBAdvertisementDataLocalNameKey is \"\(CBAdvertisementDataLocalNameKey)\"")
// Retrieve the peripheral name from the advertisement data using the "kCBAdvDataLocalName" key
if let peripheralName = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
print("NEXT PERIPHERAL NAME: \(peripheralName)")
print("NEXT PERIPHERAL UUID: \(peripheral.identifier.uuidString)")
if (peripheralName == deviceName) {
print("SENSOR TAG FOUND! ADDING NOW!!!")
// to save power, stop scanning for other devices
peripherals.append(peripheral)
deviceTable.reloadData()
keepScanning = false
}
}
}
/*
Invoked when a connection is successfully created with a peripheral.
This method is invoked when a call to connectPeripheral:options: is successful.
You typically implement this method to set the peripheral’s delegate and to discover its services.
*/
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
print("**** SUCCESSFULLY CONNECTED!!!")
// Now that we've successfully connected to the SensorTag, let's discover the services.
// - NOTE: we pass nil here to request ALL services be discovered.
// If there was a subset of services we were interested in, we could pass the UUIDs here.
// Doing so saves battery life and saves time.
peripheral.discoverServices(nil)
}
/*
Invoked when you discover the peripheral’s available services.
This method is invoked when your app calls the discoverServices: method.
If the services of the peripheral are successfully discovered, you can access them
through the peripheral’s services property.
If successful, the error parameter is nil.
If unsuccessful, the error parameter returns the cause of the failure.
*/
// When the specified services are discovered, the peripheral calls the peripheral:didDiscoverServices: method of its delegate object.
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if error != nil {
print("ERROR DISCOVERING SERVICES: \(error?.localizedDescription)")
return
}
// Core Bluetooth creates an array of CBService objects —- one for each service that is discovered on the peripheral.
if let services = peripheral.services {
for service in services {
print("Discovered service \(service)")
// If we found either the temperature or the humidity service, discover the characteristics for those services.
peripheral.discoverCharacteristics(nil, for: service)
}
}
}
/*
Invoked when the central manager fails to create a connection with a peripheral.
This method is invoked when a connection initiated via the connectPeripheral:options: method fails to complete.
Because connection attempts do not time out, a failed connection usually indicates a transient issue,
in which case you may attempt to connect to the peripheral again.
*/
private func centralManager(central: CBCentralManager, didFailToConnectPeripheral peripheral: CBPeripheral, error: NSError?) {
print("**** CONNECTION TO SENSOR TAG FAILED!!!")
}
/*
Invoked when an existing connection with a peripheral is torn down.
This method is invoked when a peripheral connected via the connectPeripheral:options: method is disconnected.
If the disconnection was not initiated by cancelPeripheralConnection:, the cause is detailed in error.
After this method is called, no more methods are invoked on the peripheral device’s CBPeripheralDelegate object.
Note that when a peripheral is disconnected, all of its services, characteristics, and characteristic descriptors are invalidated.
*/
private func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
print("**** DISCONNECTED FROM SENSOR TAG!!!")
if error != nil {
print("****** DISCONNECTION DETAILS: \(error!.localizedDescription)")
}
sensorTag = nil
}
}