I want to use the CBCentralManager in order to find the bluetooth low energy peripherals around me. The centralManager is getting initiated, it starts correctly and it is scanning. But the didDiscover function is never called. I read all the other posts to this and similar problem and am 99% sure that my problem has not the same cause. Still, I cannot find what I did wrong.
import Foundation
import CoreBluetooth
#objc(SmallerBeaconServiceImpl)
class SmallerBeaconServiceImpl : NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
private let centralManager : CBCentralManager
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn && isRunning {
startScanningForPeripherals()
}
print("updated state: \(central.state)")
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral.name ?? "no name")
}
func startScanningForPeripherals() {
if centralManager.state != CBManagerState.poweredOn {
return
}
centralManager.scanForPeripherals(withServices: nil, options: nil)
print("is scanning: \(centralManager.isScanning)")
}
private(set) var isRunning = false
func startListening() {
if isRunning {
return
}
isRunning = true
print("started.")
startScanningForPeripherals()
}
func stopListening() {
if !isRunning {
return
}
isRunning = false
centralManager.stopScan()
}
override init() {
centralManager = CBCentralManager()
super.init()
print("initiated")
}
}
optional func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) is a CBCentralManagerDelegate method.
Your class SmallerBeaconServiceImpl is compliant with CBCentralManagerDelegate, but you didn't set your centralManager delegate (CBCentralManagerDelegate) property. That's why centralManager(_central:didDiscover:advertisementData:rssi) is not called.
This can be fixed with:
centralManager = CBCentralManager(delegate: self, queue: nil)
Related
When I pass CBUUID as array to scanForPeripherals withServices nothing happened. (Xcode 12.5, Swift 5)
Step 1. Getting all devices near me and getting identifiers:
//
// ViewController.swift
//
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate {
private var centralManager : CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
centralManager.scanForPeripherals(withServices:nil, options: nil)
}
}
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
guard let name = peripheral.name else { return }
print("\nName : \(name)")
print(peripheral.identifier)// Getting identifier here.(9SD480E0-4362-4412-6350-D143DC3D14BE)
}
}
Step 2. (WRONG) Calling with identifiers and nothing is being discovered:
//
// ViewController.swift
//
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate {
private var centralManager : CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
centralManager.scanForPeripherals(withServices: [CBUUID.init(string: "9SD480E0-4362-4412-6350-D143DC3D14BE")], options: nil)
}
}
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
// NOTHING IS BEING DISCOVERED
}
}
Step 3. The correct path to follow is Step 1 (for getting id's) and Step 3 (to retrieve peripherals). Thank you #Paulw11:
//
// ViewController.swift
//
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate {
private var centralManager : CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
guard let uuid = UUID(uuidString: "9SD480E0-4362-4412-6350-D143DC3D14BE") else { return }
let result = centralManager.retrievePeripherals(withIdentifiers: [uuid])
print(result) // CBPeripheral
}
}
}
I am trying to get started with bluetooth on iOS, in order to make two neighbouring devices communicate using CoreBluetooth.
On one device an app is running playing the role of peripheral and on the other device another app is running playing the role of central.
Here is the relevant code for the two apps.
The peripheral app:
import UIKit
import CoreBluetooth
class ViewController: UIViewController,CBPeripheralManagerDelegate {
let serviceOne_UUID = CBUUID(string:"FB694B90-F49E-4597-8306-171BBA78F846"),
svcOneChrcOne_UUID = CBUUID(string:"EB6727C4-F184-497A-A656-76B0CDAC633A")
var cbPerifMngr:CBPeripheralManager!, mutaSRVC:CBMutableService!,
svcOneCharacOne:CBMutableCharacteristic!
override func viewDidLoad() {
super.viewDidLoad()
cbPerifMngr = CBPeripheralManager(delegate: self, queue: nil)
}
// CBPeripheralManagerDelegate protocol implementation.
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
mutaSRVC = CBMutableService(type: serviceOne_UUID, primary: true)
svcOneCharacOne = CBMutableCharacteristic(type: svcOneChrcOne_UUID,
properties: [.read, .notify],
value: nil, permissions: .readable)
mutaSRVC.characteristics = [svcOneCharacOne]
cbPerifMngr?.add(mutaSRVC)
}
}
func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
if error != nil {
print("Error in \(#function) :\n\(error!)")
} else {
cbPerifMngr.startAdvertising([CBAdvertisementDataServiceUUIDsKey:service.uuid])
}
}
func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
if error != nil {
print("Error in \(#function) :\n\(error!)")
}
}
}
The central app:
import UIKit
import CoreBluetooth
class ViewController: UIViewController,CBCentralManagerDelegate {
var cbCenterMngr:CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
cbCenterMngr = CBCentralManager(delegate: self, queue: nil)
}
// CBCentralManagerDelegate protocol implementation.
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print(#function)
if central.state == .poweredOn {
print("\(#function) poweredOn")
central.scanForPeripherals(withServices: [CBUUID(string:"FB694B90-F49E-4597-8306-171BBA78F846")],
options: nil)
}
}
func centralManager(_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(#function)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print(#function)
}
}
At this point, when I run both apps at the same time, I do not see anything happening showing that some kind of connection is taking place. Can anybody tell me if I need to look in a particular place or if the code above is simply wrong and nothing will happen? In which case some advice or hint would be highly appreciated.
P.S.
After trying again, I noticed this error in the logging console of the peripheral app:
peripheralManager(_:didAdd:error:)
peripheralManagerDidStartAdvertising(_:error:)
Error in peripheralManagerDidStartAdvertising(_:error:) :
Error Domain=CBErrorDomain Code=1 "One or more parameters were invalid." UserInfo={NSLocalizedDescription=One or more parameters were invalid.}
I'm coding BLE test apps for iOS with Swift 3 and I'm struggling with a problem that I can't scan devices.
I want to call the method "print("devicename: \(peripheral)")" at the last block.
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate {
private var isScanning = false
var centralManager: CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
self.centralManager = CBCentralManager(delegate: self,queue: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
centralManager.scanForPeripherals(withServices: nil,options: nil)
} else {
print("not ready")
}
}
private func centralManager(central: CBCentralManager!,didDiscoverPeripheral peripheral: CBPeripheral!,advertisementData: [String : AnyObject]!,RSSI: NSNumber!)
{
print("devicename: \(peripheral)")
}
}
func centralManagerDidUpdateState(_ central: CBCentralManager){
switch central.state {
case .poweredOn: central.scanForPeripherals(withServices: nil, options: nil)
default: print("Please turn on bluetooth")
break
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
print("----->",advertisementData)
print("==>", peripheral)
}
I am having the problem with Xcode 9.2 and iOS 11.1.2,"didDiscover" is working fine and my peripheral is saved in an array before I call connect, but "didConnect" or "didFailToConnect" not called, so the peripheral state will stay at "connecting"...
Please help
var manager: CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
//manager = CBCentralManager (delegate: self, queue: DispatchQueue.main)
//manager = CBCentralManager.init(delegate: self, queue: nil, options:[:])
//manager.delegate = self
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
guard let name = peripheral.name else { return }
print("BR peripheral.name = \(name), rssi = \(RSSI), adertisementData = \(advertisementData)")
if (peripheral.name?.hasPrefix("testBT"))! {
peripheralArray.append(peripheral)
manager.connect(peripheralArray.first!, options: [:])
print("Connecting to peripheral \(peripheral)")
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("BT connected!")
manager.stopScan()
peripheral.delegate = self
peripheral.discoverServices(nil)
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("BT disconnected!")
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print("BT failed!")
}
Try making variable global:
var myPeripheral:CBPeripheral?
Than, in your code edit it:
if (peripheral.name?.hasPrefix("testBT"))! {
myPeripheral = peripheral
//HERE WRITE DELEGATE, NOT IN didConnect
myPeripheral!.delegate = self
//peripheralArray.append(myPeripheral)
manager.connect(myPeripheral!, options: nil)
print("Connecting to peripheral \(peripheral)")
}
Now I think it should work. I would also start scanning on centralManagerDidUpdateState to make sure bluetooth is working, smth like:
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state{
case .poweredOn:
startScan() // own method where i start scanning
case .poweredOff:
print("blth powered off")
case .unsupported:
print("bltyh noit supported")
}
}
etc. there is more states, you can check it in documentation. The centralManagerDidUpdateState method is beeing called after initializing in vievDidLoad your CBCentralManager var (manager = CBCentralManager(delegate: self, queue: nil))
Hope it helps
BTW, you are making an array to store there connected peripherals. Just have in mind that whenever you return from the controller where you store that array and go back to it that array will be empty again. That's why if you need your bluetooth class working globally I would suggest you to make a BluetoothService class that would have a Singleton implemented and you could access any state anywhere in your project
if (central.state == .poweredOn) kontrolune girmiyor , bluetooth listesi gelmiyor ne yapabilirim ?
import CoreBluetooth
import UIKit
class ViewController: UIViewController {
var centralManager: CBCentralManager?
var peripherals = Array()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
}
}
extension ViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print(central.state)
if (central.state == .poweredOn){
self.centralManager?.scanForPeripherals(withServices: nil, options: nil)
}
else {
print("nil")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
peripherals.append(peripheral)
print(peripheral)
}
}
swift 4
import CoreBluetooth
var bleCentralManager: CBCentralManager!
var arrayPeripheralList = [CBPeripheral]()
viewDidLoad(){
self.bleCentralManager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state{
case .poweredOn:
central.scanForPeripherals(withServices: nil, options: nil)
default:
bleCentralManager.stopScan()
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if !(self.arrayPeripheralList.contains(peripheral)){
self.arrayPeripheralList.append(peripheral)
}
}
You have to call scanForPeripheralsWithServices from outside the delegate method firstly
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: GlobalBackgroundQueue, options: [CBCentralManagerOptionShowPowerAlertKey: true])
if self.manager!.state == CBCentralManagerState.PoweredOn {
self.manager?.scanForPeripheralsWithServices(nil, options: nil)
delay(2, closure: {
self.manager?.stopScan()
print("scanning stopped.")
})
}
}
func centralManagerDidUpdateState(central: CBCentralManager) {
if (central.state != CBCentralManagerState.PoweredOn) {
self.bluetoothStatus = false
}
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
peripherals.append(["p": peripheral, "a": advertisementData, "r": RSSI])
}