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.
Related
BLE works fine on 7 Plus (iOS 14.4.2) and 6 (iOS 12). But on XR (14.4.2) and 11 connection stuck after centralManager.connect(peripheral, options: nil) (infinite connection)
The peripheral is in connection mode because other smartphones cannot detect it.
At first I thought that the problem was with the radio module of the peripheral device itself (NRF52), but the problem also occurred with the debug board.
Rebooting the smartphone did not help.
It's funny that the app works fine on a MacBook with an M1 chip
Part of code:
// Peripheral model
init(withPeripheral peripheral: CBPeripheral, advertisementData advertisementDictionary: [String : Any], andRSSI currentRSSI: NSNumber, using manager: CBCentralManager) {
centralManager = manager
basePeripheral = peripheral
RSSI = currentRSSI
super.init()
advertisedName = parseAdvertisementData(advertisementDictionary)
basePeripheral.delegate = self
}
public func connect() {
centralManager.delegate = self
centralManager.connect(basePeripheral, options: nil)
print("Connecting to \(advertisedName ?? "device")...")
// logs stops here
}
public func disconnect() {
centralManager.cancelPeripheralConnection(basePeripheral)
print("Cancelling connection with \(advertisedName ?? "device")...")
// triggers on VC dismiss
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state != .poweredOn {
print("Central Manager stated changed to \(central.state)")
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
if peripheral == basePeripheral {
print("Connected to \(advertisedName ?? "device")")
delegate?.peripheralDidConnect()
discoverPrimaryServices()
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
if peripheral == basePeripheral {
print("Disconnected from \(advertisedName ?? "device")")
delegate?.peripheralDidDisconnect()
}
}
"The peripheral is in connection mode because other smartphones cannot detect it." Did you mean that other smartphones can detect it?
Given the phones you've listed as working and not working, I would expect that your board is having trouble with Bluetooth 5 (which was first supported on the iPhone 8). The NRF52 supports BT5 (it supports 5.2), but if you've written your own firmware you may have broken the support. I'd start by making sure you're running the most vanilla code you can from Nordic.
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
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)
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(...)
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 !