Search code examples
iosswiftflutterbluetoothmac-address

How to get Bluetooth device MAC address using Swift mbientlab bluetooth scanner


Working with the MbientLab metawear MetaMotionRL motion sensor. Building mobile app in flutter with both an Android and iOS frontend. Access to the device is via mbientlab API. Using Java for Android and Swift for iOS.

On the Java side I detect devices via flutter_blue. This includes the mac address for devices. When a user selects a device from a list, the app uses the mac address to connect via the mbient API.

But... I don't know how to do the same on the Swift side.

And... mbient API has its own device scanning feature. Which is nice since it only finds mbient devices; not other bluetooth devices. So, I'm using that. But, I can't seem to find the mac address in the API -- not for a device that is not yet connected. I want to display the mac address of all nearby devices before connecting so that if there are multiple the user can choose based on the mac address ... which is printed on the device.

So, I'm looking for the answer to either of these questions ... using Swift:

  1. How does one connect to a device via the mbient API with a given mac address?
  2. How does one get the mac address from the mbient device scanner?

Here's the Swift code for using the mbient scanner:

            MetaWearScanner.shared.startScan(allowDuplicates: false) { (device: MetaWear) in
                let id: String = device.peripheral.identifier.uuidString
                logger.trace("Found metawear device name:'\(device.name)' id:\(id)")
                self.foundDevicesById[id] = device
            }

There are many properties of a device -- including sub-objects. But I cannot find mac address. Well, this is a mac address property, but it is not loaded until the device is connected. Am I missing something? Is the mac address in there?

I didn't write the Java code. I don't understand it. It's complicated, but it works. It's embedded in the MainActivity.java file. Here are the parts that seem relevant:

private BtleService.LocalBinder serviceBinder;

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
    ///< Typecast the binder to the service's LocalBinder class
    serviceBinder = (BtleService.LocalBinder) service;
}

private void retrieveBoard(String macAddress) {
    BluetoothManagBluetoothManagerer btManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    BluetoothDevice remoteDevice = btManager.getAdapter().getRemoteDevice(macAddress);
    _board = serviceBinder.getMetaWearBoard(remoteDevice);
}

If I could do similar in Swift, that would be great. I have no idea how to do that.


Solution

  • This is not possible. You cannot access the MAC address of a BLE device directly in iOS. This is by design. The only identifier available is CBPeripheral.identifier. This is a fairly stable identifier, but it can change from time to time. Each phone will assign a different identifier to each BLE device. This prevents using BLE MAC addresses to track users.

    That said, for your described problem you shouldn't need an identifier. You can just put the CBPeripheral objects in a list, and when the user selects one, you can connect to it.

    If you control the firmware of the device, you can make the MAC address available through a characteristic or advertising. But in the general case, there is no way to access this information.