scanForPeripheralWithServices does not return anything - ios

I am new to swift language. I have been working on establishing a bluetooth connection between my iOS app and a barcode scanner. The barcode scanner has bluetooth enabled. I tried to establish a global bluetooth connection with my iphone and it works. Based on some references from the Internet, I have written the following sample code.
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var manager : CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate : self, queue : nil)
}
func centralManagerDidUpdateState(central: CBCentralManager) {
var consoleMsg = "hello"
switch(central.state) {
case .PoweredOff:
consoleMsg = "Bluetooth is powered off"
case .PoweredOn:
consoleMsg = "Bluetooth is powered on"
manager.scanForPeripheralsWithServices(nil, options: nil)
case .Resetting:
consoleMsg = "Bluetooth is Resetting"
case .Unauthorized:
consoleMsg = "Bluetooth is Unauthorized"
case .Unknown:
consoleMsg = "Bluetooth is Unknown"
case .Unsupported:
consoleMsg = "Bluetooth is Unsupported"
}
print("\(consoleMsg)")
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
print("Discovered a peripheral \(peripheral)")
}
When I try to run the above code, log displays "Bluetooth is Powered on" and thats it. It is not discovering my barcode scanner. I also made sure that the barcode scanner is in discoverable mode. Why my code is not discovering the near-by bluetooth enabled barcode scanner? Have I done any mistake in the above code?
Thanks

You should absolutely check authorization first !

Related

How to scan non LE devices using Swift?

I have RFID reader, which is not LE device.
https://www.tsl.com/products/1153-bluetooth-wearable-uhf-rfid-reader
I'm trying to write an iOS application, scan this device and connect it using swift CoreBluetooth library but my App finds everything besides this device. How is it possible to scan this reader?
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate {
var manager: CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
manager = CBCentralManager(delegate: self, queue: nil)
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
break;
case .poweredOff:
break;
case .poweredOn:
manager.scanForPeripherals(withServices: nil)
break;
case .resetting:
break;
case .unauthorized:
break;
case .unsupported:
break;
default:
break;
}
}
}
That device states that is MFi certified and uses the SPP profile, not the BLE GATT profile. This means that you will need to use the External Accessory Framework, not Core Bluetooth, to communicate with it.
You will need to the manufacturer provided iOS SDK for the device. If they do and you want to release your app on the App Store then they will also need to approve your app and supply some paperwork to Apple.
The device says that it also supports the HID profile, so perhaps you could just treat it as a keyboard; This doesn't require any code but isn't the best user experience.
You need to use CoreNFC to read RFID tags. No need to use CoreBluetooth at all.
https://developer.apple.com/documentation/corenfc

How to bond/pair to a bluetooth LE device programmatically in swift Xcode?

I am currently trying to develop and application that allows users to bond to a Peripheral via a click of a button and the password will be automatically entered.
Is it possible to Bond and Remove Bond programmatically using swift?
Pairing is initiated any time that you attempt to write to or read from a characteristic on the BLE device. However, if the device is not set to require authentication and/or bonding, you will not see the iOS popup which requests the PIN code.
I struggled with this with my HM-10 because I could write data to the characteristic using the Core Bluetooth (via Swift) function writeValue() without ever seeing the pairing popup.
I couldn't figure it out until I read the HM-10 (implements the IC cc2451) datasheet very closely and found that I needed to set the AT+TYPE to value 3. It defaults to 0 which means that the HM-10 does not require pairing/bonding so you never see the iOS popup.
You can read more about the details where I asked the question and ultimately found the solution and wrote it up: How do I pair and/or bond to BLE on iOS using Swift code and an HM-10 so data sent is encrypted?
Follow the step to connect Ble device into iOS Program.
1) Import
import CoreBluetooth
2) Declared the variables into the class or ViewController.
let kServiceUART = CBUUID(string: "0x1800")
var peripheralHeartRateMonitor: CBPeripheral?
var cbManger: CBCentralManager!
3) Initialize the cbManger into ViewDidLoad function of viewController or initalize function of class.
cbManger = CBCentralManager(delegate: self, queue: .main)
4) Override delegate method of the CBCentralManager .
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unsupported:
print("BLe Unsupported")
break
case .unauthorized:
print("BLe unauthorized")
break
case .poweredOff:
let alertMessgesInst = AlertMessages.sharedInstance
CommonUtils.showAlert(alertMessgesInst.actofit_Title, message: alertMessgesInst.trun_On_blueTooth)
break
case .poweredOn:
if isNewFirmWareOFImpulse {
let uuidString = StorageServices.readFromDefaults(key: Constants.userDefaultKeys.impulseUUID)
let uuid = UUID(uuidString:uuidString as! String )
let device = cbManger.retrievePeripherals(withIdentifiers: [uuid!])
peripheralHeartRateMonitor = device.first
peripheralHeartRateMonitor!.delegate = self
cbManger?.connect(peripheralHeartRateMonitor!)
}else {
let option:[String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: false)]
cbManger.scanForPeripherals(withServices: nil, options: option)
}
break
case .unknown:
print("BLe unknown")
break
default:
break
} // End Swith
} // End 'centralManagerDidUpdateState' function.
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if isNewFirmWareOFImpulse {
peripheralHeartRateMonitor = peripheral
print("UUid of band is :- \(peripheralHeartRateMonitor?.identifier.uuidString)")
if impulseName == peripheral.name {
peripheralHeartRateMonitor!.delegate = self
cbManger.stopScan()
// STEP 6: connect to the discovered peripheral of interest
cbManger?.connect(peripheralHeartRateMonitor!)
} // End impulse condition
}else {
let keysArray = advertisementData.keys
if let tempImpulseName = peripheral.name {
print(impulseName + " and " + tempImpulseName )
if impulseName == tempImpulseName {
for key in keysArray {
if key == "kCBAdvDataManufacturerData"{
let manufactureData = advertisementData[key]
if let stringValue = manufactureData.debugDescription as? String {
var heartValue: String = String()
heartValue = stringValue
heartValue.removeLast()
heartValue.removeLast()
let last = heartValue.removeLast()
let secondLast = heartValue.removeLast()
let hR = String([secondLast, last])
if let value = UInt8(hR, radix: 16){
if Int(value) > 60 {
hrArray.append(Int(value))
}
} // End the value block
} // end of if 'stringValue' condition
} // end 'Key' if condition
} // End for each loop
} // End impulse condition
} // End pheripheral if condition
} // end version condition
} // End function 'didDiscover peripheral'.
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
// STEP 8: look for services of interest on peripheral
peripheralHeartRateMonitor?.discoverServices(nil)
} // END func centralManager(... didConnect peripheral
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if error != nil {

Swift launch thread in background

I'm trying to send a process in a background thread using the following code:
let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
print("running in the background queue")
btDiscovery
})
but the class is only processing while begin in foreground...any idea ?
EDIT1:
btDiscovery is a class which performs a BLE device scan every X seconds:
let btDiscoverySharedInstance = Beacon();
class Beacon: NSObject, CBCentralManagerDelegate {
private var centralManager: CBCentralManager?
private var peripheralBLE: CBPeripheral?
....
func centralManagerDidUpdateState(central: CBCentralManager) {
switch (central.state) {
case CBCentralManagerState.PoweredOff:
print("BLE powered off")
self.clearDevices()
case CBCentralManagerState.Unauthorized:
// Indicate to user that the iOS device does not support BLE.
print("BLE not supported")
break
case CBCentralManagerState.Unknown:
// Wait for another event
print("BLE unknown event")
break
case CBCentralManagerState.PoweredOn:
print("BLE powered on")
self.startScanning()
break
case CBCentralManagerState.Resetting:
print("BLE reset")
self.clearDevices()
case CBCentralManagerState.Unsupported:
print("BLE unsupported event")
break
}
}
func startScanning() {
print("Start scanning...")
if let central = centralManager {
central.scanForPeripheralsWithServices(nil, options: nil)
}
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
print("Discovered peripheral \(RSSI) dBM name: \(peripheral.name)")
print("UUID: \(peripheral.identifier.UUIDString)")
...
sleep(delayPolling)
self.startScanning()
}
when the app is launched and remains in foreground, the scan is performed correctly every "delayPolling" seconds.
but as soon as I put my app is background, the scan is paused. it restarts only when it comes back again in foreground.
I would need to leave this scan running in background every time (even if we set a lower priority to this thread).
EDIT2:
by reading the documentation https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html
I can see that
When an app that implements the central role includes the UIBackgroundModes key with the bluetooth-central value in its Info.plist file, the Core Bluetooth framework allows your app to run in the background to perform certain Bluetooth-related tasks. While your app is in the background you can still discover and connect to peripherals, and explore and interact with peripheral data. In addition, the system wakes up your app when any of the CBCentralManagerDelegate or CBPeripheralDelegate delegate methods are invoked
I selected the corresponding options in my Info.plist file:
but my app is not running my thread in background.
I realize this is an old question, but scanning in the background requires that you supply a Service UUID.
central.scanForPeripheralsWithServices(nil, options: nil)
needs to be
central.scanForPeripheralsWithServices(serviceUUID, options: nil)

Basic BLE communication app for iOS with swift

I am quite new to iOS programming and also to bluetooth protocol.
I have found a sample code written in swift and trying to modify it to work with my own bluetooth module. The module I have is DBM01 from dorji.
The service I need to use is FFF0 and the characteristics is FFF1 for sending a ASCII value.
When I use the LightBlue app on my macbook and connect to the board I have designed, which has the DBM01 module on it, I can send the char value of "1" and I get the expected response (Turning on a LED) and when I send value of "0" it turns the LED off.
Now with the code I have, I can connect to the DBM01 module. I can print its name. However, I cannot disconnect from it with the following function. I am also not sure if this is for disconnecting from the device or it is called automatically when the device is disconnected. Regardless, it does not work either way.
func centralManager(central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: NSError?)
My main problem is I really didn't understand how I specify the service and the characteristics that I am interested in and connect to specific device that has them.
I am also unable to send a message. When I try I got the predefined error, since the following condition did't hold
if writeCharacteristic != nil
Below is my full code.
Appreciate if you can point out where I am doing wrong and how I can achieve connecting to specific device with specific service and characteristics information and sending data.
//
// ViewController.swift
// bleSwift
//
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var centralManager: CBCentralManager!
var peripheral: CBPeripheral!
var writeCharacteristic: CBCharacteristic!
var service: CBService!
var characteristic: CBCharacteristic!
var bluetoothAvailable = false
let message = "1"
#IBOutlet weak var deviceName: UILabel!
#IBOutlet weak var ServiceName: UILabel!
#IBOutlet weak var CharacteristicsName: UILabel!
func centralManagerDidUpdateState(central: CBCentralManager)
{
print("Checking state")
switch (central.state)
{
case .PoweredOff:
print("CoreBluetooth BLE hardware is powered off")
case .PoweredOn:
print("CoreBluetooth BLE hardware is powered on and ready")
bluetoothAvailable = true;
case .Resetting:
print("CoreBluetooth BLE hardware is resetting")
case .Unauthorized:
print("CoreBluetooth BLE state is unauthorized")
case .Unknown:
print("CoreBluetooth BLE state is unknown");
case .Unsupported:
print("CoreBluetooth BLE hardware is unsupported on this platform");
}
if bluetoothAvailable == true
{
discoverDevices()
}
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber)
{
// Stop scanning
self.centralManager.stopScan()
print("Stopped Scanning")
// Set as the peripheral to use and establish connection
//self.peripheral = peripheral
//self.peripheral.delegate = self
//self.centralManager.connectPeripheral(peripheral, options: nil)
peripheral.discoverServices([CBUUID(string: "FFF0")])
print("CONNECTED!!")
print(peripheral.name)
deviceName.text = peripheral.name
}
func discoverDevices() {
print("Discovering devices")
centralManager.scanForPeripheralsWithServices(nil, options: nil)
}
#IBAction func disconnectDevice(sender: AnyObject) {
func centralManager(central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: NSError?)
{
print("CONNECTION WAS DISCONNECTED")
deviceName.text = "Disconnected"
}
}
#IBAction func Scan(sender: AnyObject)
{
print("Scan")
centralManager = CBCentralManager(delegate: self, queue: nil)
}
#IBAction func Send(sender: AnyObject)
{
let data = message.dataUsingEncoding(NSUTF8StringEncoding)
if writeCharacteristic != nil
{
print("Sent")
peripheral!.writeValue(data!, forCharacteristic: writeCharacteristic, type: CBCharacteristicWriteType.WithoutResponse)
}
else
{
print("Couldn't Send")
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
In order to send data to your ble peripheral, you should:
Start scanning.
In your ble central manager delegate you'll recieve didDiscoverPeripheral callback with discovered peripheral. Set yourself as its delegate and connect to it: centralManager.connectPeripheral(...)
Receive didConnectPeripheral in delegate. Now call discoverServices for this peripheral.
Recieve didDiscoverServices in your delegate. Finaly, call discoverCharacteristics for your service.
You'll recieve characteristic in didDiscoverCharacteristic delegate method. After that, you'll be able to send data to exact characteristic of your peripheral.
To disconnect peripheral, call method centralManager.cancelPeripheralConnection(...)

Swift: Why can't my iOS scanned other bluetooth devices

Now I'm currently doing an application project that needs my iPhone to scan other nearby bluetooth devices and list them out. I'm wondering is my code has any problem?
Code:
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate {
var manager: CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
manager = CBCentralManager (delegate: self, queue: nil)
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
print("Peripheral: \(peripheral)")
}
func centralManagerDidUpdateState(central: CBCentralManager) {
print("Checking")
switch(central.state)
{
case.Unsupported:
print("BLE is not supported")
case.Unauthorized:
print("BLE is unauthorized")
case.Unknown:
print("BLE is Unknown")
case.Resetting:
print("BLE is Resetting")
case.PoweredOff:
print("BLE service is powered off")
case.PoweredOn:
print("BLE service is powered on")
print("Start Scanning")
manager.scanForPeripheralsWithServices(nil, options: nil)
default:
print("default state")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I'm using iPhone 5 (iOS 9) and I'm sure that my Bluetooth is turned on.
When I run the application in my iPhone, the console only log the following output:
Checking
BLE service is powered on
Start Scanning
But there is no Bluetooth device's name shown in the output. Even I turn on my iPad (iPad Mini 4 iOS 8) and the list still wouldn't update.
Sometimes it does scan my MacBook Pro Bluetooth and the output will have this:
Peripheral: <CBPeripheral: 0x14d70e00, identifier = 54738076-6C97-FD04-18CF-5E1AF6705865, name = vivien’s MacBook Pro, state = disconnected>
So, why is this happening? Can someone please explain to me?
case 1:
You must use GKSession to scan and connect with another iOS device,not CoreBluetooth.
case 2:
Your bluetooth device is a Bluetooth 3.0 accessory.Your iPhone can discover and show it in Setting->Bluetooth.
But this message isn't delivered to your app,so your app won't discover it.
Try again with a Bluetooth 4.0 accessory.

Resources