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)
}
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 connect automatically to my AirPods with a simple app using BLE. I get the name of the device and the status to "connecting", but for some reason I can't connect to it. Function 'didConnect peripheral' is never triggered.
I tried all different approaches from tutorials and from other posts, tried to store the peripheral data in an array to keep the reference but nothing seem to work.
Is there any step which I can get some extra info between 'didDiscover' and 'didConnect'?
Working in XCode 9.2, using Swift 4 and iOS 11.2 on iPhone.
Here's my code:
let deviceName = "AirPods de Roger"
var isConnected = false
var manager: CBCentralManager!
var peripheralBLE: CBPeripheral?
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch manager.state {
case.poweredOff:
print("BLE service is powered off")
case.poweredOn:
print("BLE service is powered on and scanning")
manager.scanForPeripherals(withServices: nil, options: nil)
default:
print("BLE service in another state")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if peripheral.name == deviceName && isConnected == false {
self.manager.stopScan()
self.peripheralBLE = peripheral
self.peripheralBLE?.delegate = self
manager.connect(peripheral, options: nil)
isConnected = true
print("\(peripheral.name) pre-connected")
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
lblConnected.isHidden = false
print("AirPods Connected")
peripheral.discoverServices(nil)
}
This one is my current implementation:
import UIKit
import CoreBluetooth
var manager: CBCentralManager!
var peripheralBLE: CBPeripheral!
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
let deviceName = "AirPods de Iván"
var isConnected = false
#IBOutlet weak var Label: UILabel!
#IBAction func Click(_ sender: UIButton) {
self.connect()
}
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func connect() {
manager.connect(peripheralBLE, options: nil)
print("connect")
self.updateLabelStatus()
}
func disconnect() {
manager.cancelPeripheralConnection(peripheralBLE!)
print("disconnect")
self.updateLabelStatus()
}
func updateLabelStatus() {
switch peripheralBLE.state {
case.connected:
Label.text = "connected"
case.disconnected:
Label.text = "disconnected"
case.connecting:
Label.text = "connecting"
case.disconnecting:
Label.text = "disconnecting"
default:
Label.text = "label"
}
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch manager.state {
case.poweredOff:
print("BLE service is powered off")
case.poweredOn:
print("BLE service is powered on and scanning")
manager.scanForPeripherals(withServices: nil, options: nil)
default:
print("BLE service in another state")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if peripheral.name == deviceName && isConnected == false {
print("found AirPods \(peripheral)")
peripheralBLE = peripheral
peripheralBLE!.delegate = self
manager.stopScan()
self.updateLabelStatus()
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("AirPods Connected")
peripheral.discoverServices(nil)
self.updateLabelStatus()
}
func centralManager(_ central: CBCentralManager,
didFailToConnect peripheral: CBPeripheral,
error: Error?) {
print("AirPods Connect error")
print(error)
self.updateLabelStatus()
}
}
I am finding the device but when I try to connect, nothing happens
BLE service is powered on and scanning
found AirPods <CBPeripheral: 0x1c4103f00, identifier = 0E6FCF72-B86E-FB10-DD62-4A575BAD0ECC, name = AirPods de Iván, state = disconnected>
connect
I can connect other devices with this code
I can connect the airpods with my mac without problems with a similar code
I can't connect airpods with my iphone :S
Something strange happens here I am almost sure that the code is right
Since the AirPods advertise with kCBAdvDataIsConnectable = 0, they're not supposed to be connected via BLE.
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])
}
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)
I am trying to write a simple app that constantly broadcasts a 'beacon' even when the app is not active. I know that using CoreLocation will switch this off when the app is not in use so I was trying to build a solution using Core Bluetooth.
The trouble is that I can't get the app to start advertising.
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralManagerDelegate {
var centralManager:CBCentralManager = CBCentralManager()
var peripheralManager:CBPeripheralManager = CBPeripheralManager()
let uuid:CBUUID = CBUUID(string: "DCEF54A2-31EB-467F-AF8E-350FB641C97B")
override func viewDidLoad() {
super.viewDidLoad()
self.peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
self.centralManager.delegate = self
let advertisingData = [CBAdvertisementDataLocalNameKey:"my-peripheral", CBAdvertisementDataServiceUUIDsKey: uuid]
peripheralManager.startAdvertising(advertisingData)
centralManager.scanForPeripheralsWithServices([uuid], options: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func peripheralManagerDidStartAdvertising(peripheral: CBPeripheralManager, error: NSError?) {
print("started advertising")
print(peripheral)
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
print("peripheral discovered")
print("peripheral: \(peripheral)")
print("RSSI: \(RSSI)")
}
func centralManagerDidUpdateState(central: CBCentralManager) {
print("central state updated")
print(central.description)
if central.state == .PoweredOff {
print("bluetooth is off")
}
if central.state == .PoweredOn {
print("bluetooth is on")
let advertisingData = [CBAdvertisementDataLocalNameKey:"my-peripheral", CBAdvertisementDataServiceUUIDsKey: uuid]
let service = CBMutableService(type: uuid, primary: true)
self.peripheralManager.addService(service)
peripheralManager.startAdvertising(advertisingData)
centralManager.scanForPeripheralsWithServices(nil, options: nil)
}
if central.state == .Unsupported {
print("bluetooth is unsupported on this device")
}
}
func peripheralManagerDidUpdateState(peripheral: CBPeripheralManager) {
print("peripheral state updated")
print("\(peripheral.description)")
}
}
I have installed this on two devices, the issue seems to be in the transmission of the advert since peripheralManagerDidStartAdvertising() is never called.
The issue is related to immediate call .startAdvertising() right after .addService() call.
You must call .startAdvertising() ONLY after func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) delegate method is called.
If you use this init method the centralManagerDidUpdateState is going to work. You can set the CBCentralManagerScanOptionAllowDuplicatesKey option if you would like to see the beacons continually.
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralManagerDelegate {
var centralManager:CBCentralManager!
var peripheralManager:CBPeripheralManager = CBPeripheralManager()
let uuid:CBUUID = CBUUID(string: "DCEF54A2-31EB-467F-AF8E-350FB641C97B")
override func viewDidLoad() {
super.viewDidLoad()
self.peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
self.centralManager = CBCentralManager(delegate: self, queue: nil)
let advertisingData = [CBAdvertisementDataLocalNameKey:"my-peripheral", CBAdvertisementDataServiceUUIDsKey: uuid]
peripheralManager.startAdvertising(advertisingData)
centralManager.scanForPeripheralsWithServices([uuid], options: [ CBCentralManagerScanOptionAllowDuplicatesKey : true])
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func peripheralManagerDidStartAdvertising(peripheral: CBPeripheralManager, error: NSError?) {
print("started advertising")
print(peripheral)
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
print("peripheral discovered")
print("peripheral: \(peripheral)")
print("advertisement: \(advertisementData)")
if let data = advertisementData["kCBAdvDataServiceData"] {
print("found advert data: \(data)")
}
print("RSSI: \(RSSI)")
}
func startAdvert(){
let advertisingData = [CBAdvertisementDataLocalNameKey:"my-peripheral", CBAdvertisementDataServiceUUIDsKey: uuid]
peripheralManager.startAdvertising(advertisingData)
}
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
print("peripheral disconnected")
print("peripheral: \(peripheral)")
}
func centralManagerDidUpdateState(central: CBCentralManager) {
print("central state updated")
print(central.description)
if central.state == .PoweredOff {
print("bluetooth is off")
}
if central.state == .PoweredOn {
print("bluetooth is on")
centralManager.scanForPeripheralsWithServices(nil, options: [ CBCentralManagerScanOptionAllowDuplicatesKey : true])
startAdvert()
}
if central.state == .Unsupported {
print("bluetooth is unsupported on this device")
}
}
func peripheralManagerDidUpdateState(peripheral: CBPeripheralManager) {
print("peripheral state updated")
print("\(peripheral.description)")
}
}
The CBAdvertisementDataServiceUUIDsKey value passed to startAdvertising should be an array of CBUUID objects but you are passing a single CBUUID
let advertisingData = [CBAdvertisementDataLocalNameKey:"my-peripheral", CBAdvertisementDataServiceUUIDsKey: [uuid]]