Swift 3: Can't connect to peripheral via BLE - ios

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.

Related

iPadOS 13.4 Ble pairing popup triggered without read/write to protected characteristic

Pre iPadOS 13.4 we needed to read/write to protected characteristic of a peripheral device in order to trigger pairing popup. Starting iPadOS 13.4 - the passcode popup seems to be triggered simply via a successful connection with the peripheral (CBCentralManager().connect(peripheral, options: nil)).
I need to further communicate with the peripheral in order to get the passcode before the pairing popup is displayed. Once the pairing popup is displayed - the peripheral stops responding to any further requests.
Is this a design change or a bug on 13.4? I cannot find anything on the web/apple's release notes for iPadOS 13.4.
If this is a design change - what is an elegant way of handling this?
The following code triggers pairing on didConnect peripheral:
//Sample Code
var centralManager: CBCentralManager?
var peripheral: CBPeripheral?
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
print("CentralManager state: Powered On")
centralManager?.scanForPeripherals(withServices: [advertisingUUID], options: nil)
print("Scanning for peripherals...")
default:
print("CentralManager state: Powered Off")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
self.peripheral = peripheral
self.peripheral?.delegate = self
centralManager?.connect(peripheral, options: nil)
centralManager?.stopScan()
}
func centralManager(_ central: CBCentralManager,
didConnect peripheral: CBPeripheral) {
print("Peripheral Connected")
}
func centralManager(_ central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: Error?){
print("Peripheral Disconnected")
}

BLE Swift code is scanning but not finding BLE devices

In Swift, and Xcode 9, I am trying to scan for and connect to all BLE devices. This code should print out "no name" for all BLE devices found. Scanning is working, but my BLE devices are not being found. Beside me, there is an Android phone with BLE, which I am unable to find.
Simulation device: iPhone 6s, bluetooth turned -ON
import UIKit
import CoreBluetooth
//let svcLight = CBUUID.itit(string: "24958294582945")
class BLEViewController: UIViewController , CBCentralManagerDelegate, CBPeripheralDelegate{
func centralManagerDidUpdateState(_ central: CBCentralManager) {
//scan for peripherals if "on" state change
if central.state == CBManagerState.poweredOn{
//not concerned with any services for now, and we are not passing in any options
central.scanForPeripherals(withServices: nil, options: nil)
print("scanning...")
//check for other states, add if else statements
}
}
//handle the callback for when something is found
//diddiscover was the autocomplete word for a peripheral
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if peripheral.name?.contains("POR 1007BT") == true {
//even if the peripheral doesn't have a name, we will get some info for it
print (peripheral.name ?? "no name")
centralManager.stopScan()
print(advertisementData)
//connect to the peripheral now
central.connect(peripheral, options: nil)
//store a local copy of the peripheral in the property
myPeripheral = peripheral
}
}
//so our central can begin scanning again
//if peripheral disconnects for whatever reason, it will immidiately start scanning
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
central.scanForPeripherals(withServices: nil, options: nil)
}
//callback for connecting to a central, didconnect was the autocomplete word
//discovr services
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("connected \(peripheral.name)")
peripheral.discoverServices(nil)
peripheral.delegate = self
}
//callback for diddiscover services: auto complete: diddiscover
//for each of the services in my peripheral, print out the UUID
//may not need this funciton, need to check
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
//optionally binding it
if let services = peripheral.services {
for svc in services {
print(svc.uuid.uuidString)
}
}
}
//! is used to unwrap it so anywhere in the code, it doesn't need to be unwrapped as an optional
var centralManager : CBCentralManager!
//keep a reference/store our peripheral
var myPeripheral : CBPeripheral?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//create instance of CBManager
//pass in self as the delegate to handle any callbacks
centralManager = CBCentralManager.init(delegate: self, queue: nil)
}

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.

how to connect with bluetooth low energy in ios swift?

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)
}

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.

Resources