how to connect with bluetooth low energy in ios swift? - ios

I want to connect with ble peripheral.
But my code doesn't call didConect function
this is my code :
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
let device = (advertisementData as NSDictionary)
.object(forKey: CBAdvertisementDataLocalNameKey)
as? NSString
if device?.contains(BEAN_NAME) == true {
print("Did discover peripheral", peripheral)
self.bluetoothManager.stopScan()
self._peripheral = peripheral
self._peripheral.delegate = self
central.connect(peripheral, options: nil)
}
}
func centralManager( central: CBCentralManager, didConnect peripheral: CBPeripheral) { //cant call this
print("connected to \(BEAN_NAME)")
peripheral.discoverServices(nil)
}
Logs :
BLE service is powered on
Did discover peripheral <CBPeripheral: 0x1740eef00, identifier = 4872623B-F872-443A-8A96-F4E1F84D6841, name = GoDoor in :), state = disconnected>

I created a demo project, which scans for Bluetooth LE devices and displays them in a list:
Check it out on github: quickies/BluetoothScanner.ios
Screenshot

I've solved this.
just need to change :
func centralManager(central: CBCentralManager, didConnect peripheral: CBPeripheral)
into this :
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
reference : Swift 3: Can't connect to peripheral via BLE

#IBAction func btnConnect(_ sender: UIButton){
self.appDelegate.bleManager.stopScan()
self.appDelegate.selectPeripheral = self.arrayPeripheral[sender.tag]
self.appDelegate.bleManager.connect(self.selectPeripheral, options: nil)
}

Related

Bluetooth didConnect or didFailToConnect not called Xcode 9.2 with iOS 11.1.2

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

CBCentralManager not getting connected

I'm trying to connect near by bluetooth devices. I'm able to discover but i'm unable to connect them.
this delegate is working but after discovering i'm trying connect with one of the pheripheral
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if let device = (advertisementData as NSDictionary).object(forKey: CBAdvertisementDataLocalNameKey) as? String {
print(device)
if device.contains("BODY") {
self.connectPeripheral = peripheral
self.connectPeripheral.delegate = self
self.manager.connect(connectPeripheral, options: nil)
self.manager.stopScan()
}
}
}
These two delegates methods are not invoking. one of these should be called.
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.delegate = self
peripheral.discoverServices(nil)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
//NSLog("Error %#", error.debugDescription)
print(error.debugDescription)
}
You need to maintain a strong reference to the CBPeripheral instance, because once you tell the Central to stop scanning, it will deallocate all its discovered peripherals.

Why I don't get instance of paired device via CoreBluetooth?

I have a device (named later "scanner") and other devices (named later "stone"). Scanner can scan stones and display their information on build in display. Scanner can send stones information via Bluetooth and I want to read this data and use it in my app. I started code connection implementation but I discovered a problem. Here is my code:
import UIKit
import CoreBluetooth
class BluetoothViewController: UIViewController {
var manager:CBCentralManager!
var peripheral:CBPeripheral!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
}
}
extension BluetoothViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
central.scanForPeripherals(withServices: nil, options: nil)
}
else {
print("Bluetooth not available.")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("peripheral \(peripheral)")
print("rssi \(RSSI)")
print("advertisementData: \(advertisementData)")
print("--------")
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print(peripheral)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print(peripheral)
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print(peripheral)
}
}
extension BluetoothViewController: CBPeripheralDelegate {
}
The problem is scanner doesn't appear in
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
and
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
never call.
Note that my iPhone is connected with a scanner and scanner tell me the connection is working.
What I want to achieve?
I want to create viewcontroller which check if scanner is connected.
if connected then
get scan information
else
find device and connect
get scan information
Please help me. :)
Edit
In LightBlue Explorer app my scanner device doesn't appear.
But with this app works perfectly.
Maybe using CoreBluetooth is a wrong way to do this. What is better. If creators of above app can communicate thee is a possibility to do it.
Thanks #Paulw11's comment I realized my "scanner" uses iPod Accessory Protocol. To make sure I import ExternalAccessory framework and check for devices.
EAAccessoryManager.shared().showBluetoothAccessoryPicker(withNameFilter: nil, completion: nil)
After call this function I saw list of accessory devices and my scanner was there.

Swift 3: Can't connect to peripheral via BLE

I'm new to working with BLE, currently trying to make a simple application which would connect to my custom BLE device. I am able to discover the BLE device, but for some reason i can't connect to it.
I tried to check it with 'Light Blue', it shows my device as connectable and seems to work fine. But in my app after i discover the device, CB manager tries to connect to it and seems to 'freeze'? Function 'didConnect peripheral' is never triggered, and state of peripheral is forever 'connecting'.
How can i identify the problem? Is there any options i can include in connection method, or somehow track the connection process?
I would appreciate any advice where to search for problems.
Working in XCode 8.2.1, using Swift 3. iOS 10.2.1 installed on the testing phone
Here's my code:
import UIKit
import CoreBluetooth
class InfoPageViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var manager:CBCentralManager!
var peripheral:CBPeripheral!
let BEAN_NAME = "MyDevice"
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
let device = (advertisementData as NSDictionary)
.object(forKey: CBAdvertisementDataLocalNameKey)
as? NSString
if device?.contains(BEAN_NAME) == true {
self.manager.stopScan()
self.peripheral = peripheral
self.peripheral.delegate = self
manager.connect(peripheral, options: nil)
print("discovered \(BEAN_NAME)")
}
}
func centralManager(
central: CBCentralManager,
didConnect peripheral: CBPeripheral) {
print("connected to \(BEAN_NAME)")
peripheral.discoverServices(nil)
}
func centralManager(central: CBCentralManager, didConnect peripheral: CBPeripheral) {}
--------------------^
Versus:
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
--------------------^
The signature of the method is not the correct one, you are missing the _.
Method signatures are important.
We can assume, since theses delegate methods are optional, that internally, the Apple code asks itself:
Does my delegate have the method func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) implemented (respondsToSelector:)? In your case, not, because it's not the same, and then yours is not called.
You copy/paste the one from the doc or remove it and let XCode do its autocompletion thing.

CoreBluetooth is disconnecting from unused peripherals due to an API Misuse

I am trying to connect to a MacBook Pro from an iPad with CoreBluetooth.
Here is my delegation for CBCentralManagerDelegate:
extension MasterViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
print("Scanning for peripherals")
central.scanForPeripherals(withServices: nil, options: nil)
Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.stopScan), userInfo: nil, repeats: true)
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Did discover peripheral", peripheral)
central.connect(peripheral, options: nil)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Did connect to ", peripheral)
peripheral.delegate = self
self.remotePeripheral.append(peripheral)
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {}
}
But when I scan I get this error in the log:
<Error>: [CoreBluetooth] API MISUSE: Cancelling connection for unused peripheral
Why does this happen?
Not sure why this worked, but I found that it works if I assign the peripherals delegate to self, and add the peripheral to an array before I connect to it.
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Did discover peripheral", peripheral)
peripheral.delegate = self
self.remotePeripheral.append(peripheral)
central.connect(peripheral, options: nil)
}
I was seeing this error and for those who also are facing the same issue, my suggestion is that I wasn't storing the CBPeripheral device in my helper class. That seems unnecessary to do but for some reason it needs to be bounded internally I believe.
Well, Here's what I did:-
class BLEHelper: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate{
#Published var pairedDevice:CBPeripheral?=nil
...
and then in your didDiscover function:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
pairedDevice=peripheral
peripheral.delegate=self
myCentral.connect(peripheral, options:nil)
myCentral.stopScan()
}
This line here does the trick:- pairedDevice=peripheral

Resources