Here are steps to create a simple BLE (Bluetooth Low Energy) scanner app for iPhone (for my own learning purpose). The goal is to enable below features.
- Scan for all advertising devices around.
- Print the device name, RSSI (signal strength), and advertising data [1] for each discovered device in the debug console output [2].
* It doesn’t filter any specific UUID, doesn’t connect to any peripheral device, and doesn’t show anything on app screen.
Prerequisites (parentheses indicate my environment)
- Xcode (10.0) ruining on Mac (10.14)
- iPhone (iPhone 8 with iOS 12.0.1)
* An actual iOS device is required since Bluetooth is not supported in Xcode simulator.
Steps
1. Launch Xcode and create a Single View App.
2. Open ViewController.swift file and import CoreBluetooth framework.
import CoreBluetooth
3. In order to scan, iPhone need to be BLE central. So, add CBCentralManagerDelegate protocol to ViewController class.
class ViewController: UIViewController, CBCentralManagerDelegate {
4. Then, Xcode will prompt an error. Click on “Fix” button and it will create centralManagerDidUpdateState method which will be called when the central manager’s state is changed. At startup, this method is called after instantiating CBCentralManager.
5. Declare a variable for CBCentralManager in ViewController class.
private var centralManager : CBCentralManager!
6. Instantiate CBCentralManager in viewDidLoad method.
centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
7. In centralManagerDidUpdateState method, start scanning when the state is poweredOn.
if central.state == .poweredOn { print("Bluetooth is On") centralManager.scanForPeripherals(withServices: nil, options: nil) } else { print("Bluetooth is not active") }
8. Define centralManager didDiscover method in ViewController class. It will be called when any advertising device is discovered. Inside the method, it prints the device name, RSSI, and advertising data.
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { print("\nName : \(peripheral.name ?? "(No name)")") print("RSSI : \(RSSI)") for ad in advertisementData { print("AD Data: \(ad)") } }
Test
1. Connect iPhone to Mac.
2. Make sure Bluetooth setting is ON on the connected iPhone.
3. Build and run the program, and check the console output on Xcode. Below is an example of the output.
Bluetooth is On Name : Flex RSSI : -55 AD Data: (key: "kCBAdvDataIsConnectable", value: 1) AD Data: (key: "kCBAdvDataLocalName", value: Flex) AD Data: (key: "kCBAdvDataServiceUUIDs", value: <__NSArrayM 0x282a0c600>( ADAB3BF6-6E7D-4601-BDA2-BFFAA68956BA ) ) AD Data: (key: "kCBAdvDataTxPowerLevel", value: -6) AD Data: (key: "kCBAdvDataServiceData", value: { "Device Information" = <0704>; }) Name : Apple TV RSSI : -89 AD Data: (key: "kCBAdvDataIsConnectable", value: 1) Name : (No name) RSSI : -71 AD Data: (key: "kCBAdvDataManufacturerData", value: <06000109 210ab8f3 61ae6190 4445534b 544f502d 4e424c54 533655>) AD Data: (key: "kCBAdvDataIsConnectable", value: 0) Name : (No name) RSSI : -96 AD Data: (key: "kCBAdvDataIsConnectable", value: 1)
In the example above, it detected my Fitbit Flex (Line 3-14) and some other devices. All possible advertising data type on CoreBluetooth are listed here.
References
[1] Advertising Data Type – Bluetooth SIG
[2] Console output in Xcode – Apple Developer
This was super useful and worked a treat for me. Thank you very much – very clear instructions
Hi Andrew, Thank you for your comment. Glad to hear that!
Hi, i am getting (no names) in the name field. I followed your steps thoroughly. Where did I go wrong?
Please advice.
I could not get my personal bluetooth devices. It isnt log inside the ide.
Hi i have followed your tutorial im getting no name and I am confused why I am getting this