This post will show you just the minimum effort needed to get a list of BLE (Bluetooth 4.0) devices that are advertising on your iOS device. Make sure you have an iOS device with BLE and another device that is capable of advertising its BLE services ( I am using an RFDuino, with it\’s device name set to Display).
Let\’s get started.
- Create a new single view Swift project.
- Add a UITableView to the ViewController in the pre-made Storyboard.
- Add a UITableviewCell to the tableview with identifier \”cell\”.
- Attach the datasource and delegate from the UITableView to the ViewController in the Storyboard.
- Add an IBOutlet for the UITableView in your ViewController class.
- Make sure the class for the ViewController is set to the class ViewController.
Add the CoreBluetooth framework to your project.
Now make your ViewController Swift file look like this:
import CoreBluetooth
import UIKit
class ViewController: UIViewController {
var centralManager: CBCentralManager?
var peripherals = Array<CBPeripheral>()
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//Initialise CoreBluetooth Central Manager
centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
}
}
extension ViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if (central.state == .poweredOn){
self.centralManager?.scanForPeripherals(withServices: nil, options: nil)
}
else {
// do something like alert the user that ble is not on
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
peripherals.append(peripheral)
tableView.reloadData()
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: \"cell\")! as UITableViewCell
let peripheral = peripherals[indexPath.row]
cell.textLabel?.text = peripheral.name
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return peripherals.count
}
}
centralManagerDidUpdateState will be called whenever the CoreBluetooth BLE service state changes. For this example I am only checking if the state == .poweredOn but there are other states you can check for such as off, unknown and resetting. When the state is on we initiate a device scan using scanForPeripheralsWithServices.
If the service finds a device the delegate method didDiscoverPeripheral is called. In this method we just get the newly discovered peripheral and add it to our array of peripherals. We then call reloadData on the tableView so that the new object in the array is used in our tableView. I have only used the name property from the peripheral but there is loads more stuff to play with.
When you turn on your BLE device you should see something like the following:
Could you post the complete project with UI codes? I am new to IOS and would like to learn from your example. Thanks.
Here you go. Star it if it helps you please. https://github.com/HarryGoodwin/BLE_Scanner_iOS
Succinct and easy to understand. Thanks for mate ^^
I want to scan and update table every 5 seconds, how to do that?
I want to update the list of discoverable BLE devices every 5 seconds, how do i do that?
How to display RSSI?
There is a delegate method for CBPeripheralDelegate that you can use on your discovered peripheral, alternatively you will see an RSSI parameter in the didDiscoverPeripheral delegate method.
I get the error, Binary operator ‘==’ cannot be applied to operands of type ‘CBManagerState’ and ‘CBCentralManagerState’, at the line, if (central.state == CBCentralManagerState.PoweredOn). Any idea?
Change “CBCentralManagerState.PoweredOn” to “CBManagerState.PoweredOn”. Apparently the former was deprecated in iOS 10.
try if (centralManager!.state == .poweredOn) instead
change the line to this:
if (central.state == CBManagerState.poweredOn)
CBCentralManagerState is deprecated is newer swift version. Hope this helps.
//CoreBluetooth methods
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch (central.state) {
case .poweredOff:
break
case .unauthorized:
// Indicate to user that the iOS device does not support BLE.
break
case .unknown:
// Wait for another event
break
case .poweredOn:
self.centralManager?.scanForPeripherals(withServices: nil, options: nil)
case .resetting:
break
case .unsupported:
break
}
}
I get problems with dequeueReusableCell returning nil and thus the optional unwrapping failing. It may be worth mentioning that you need to add a cell with identifier “cell” to the Table View in the storyboard
Fixed. Thanks
It looks like this will scan and show the same devices many times. Consider using a set instead of an array.
Hello and thank you very much for your project,
I tested it with my iPhone to find my Raspberry Pi Zero W having BLE, but it did not find it, I wanted to ask you why can’t do it ? , maybe you have an explanation to help me?
As per the code, the phone should not be paired with the device??? Go to Bluetooth options in phone settings and click on “Forget this device” for the device you are trying to connect and try running again.
Nice article. Thanks much.
Pingback: Jump In – xaboh17, andec17, madan17 | | Civilingeniør i Lærings- og Oplevelsesteknologi
Pingback: Bluetooth | Bluetooth low energy | Swift - Rigorous | Fascinating | Spectacular
Can You tell how to get mac address of BLE devices?
its not possible from just CBPeripheral – https://stackoverflow.com/questions/33145798/how-to-get-mac-address-from-cbperipheral-and-cbcenter
However if you are the peripheral programmer you could send the MAC address as a characteristic https://www.silabs.com/community/wireless/bluetooth/knowledge-base.entry.html/2015/08/06/_how-to_get_a_ble-VTRI
Thank You
How to get list of wifi networks on IOS – swift ?
it is possible to filter from specifically UUID ?
Just wanted to take a moment and thank you for posting this and the code sample at GitHub. The code is github has a very nice interface too. Now hopefully, I’ll be able to extend that code to do what I am trying to do — just trying to get a basic BLE to Arduino working so that I can send bytes from iOS device to Arduino. I’m able to do this easily with my Android apps but have found it a bit more difficult to do on iOS / Swift (but that’s just because I’m not as experienced in iOS dev). Thanks again.
Pingback: Bluetooth | Bluetooth low energy | Swift - The Expert Software Development And Training Company - +91-7838552946 +91-9711874933