Pair and unpair
Pairing is the one area where the platforms differ most, so check before you offer the button.
Install#
flutter pub add flutter_classic_bluetoothimport 'package:flutter_classic_bluetooth/flutter_classic_bluetooth.dart';Pairing#
final ok = await bluetooth.bondDevice('AA:BB:CC:DD:EE:FF');true means the request was accepted, not that pairing finished. The exchange is asynchronous and usually involves the user confirming a code. Watch the bond state to know how it ended.
final sub = bluetooth.bondState(device.address).listen((state) {
switch (state) {
case BtcBondState.bonding:
showProgress();
case BtcBondState.bonded:
connectNow();
case BtcBondState.none:
showFailed();
}
});A user who dismisses the system dialog produces none, not an error. Treat it as a cancellation rather than a failure worth an alert.
Unpairing#
await bluetooth.unbondDevice(device.address);Android and Linux do this properly. Windows and macOS do not expose an API for it, so the call throws BtcUnsupportedException and the user has to remove the device in system settings. Say that in your UI rather than showing a button that fails.
Check first#
final caps = await bluetooth.getPlatformCapabilities();
if (caps.canBondDevices) {
// show a Pair button
}
if (caps.canUnbondDevices) {
// show a Forget button
}What each platform allows#
| Platform | Pair | Unpair | Note |
|---|---|---|---|
| Android | Yes | Yes | System dialog for the PIN |
| Windows | Yes | No | Remove in Settings |
| macOS | Yes | No | May show a system prompt; remove in System Settings |
| Linux | No | No | BlueZ needs a system pairing agent |
| iOS | No | No | Handled entirely by the system |
Do you need to pair at all?#
Often not. A secure connection requires a bond, but the platform will usually create one for you when you connect, showing the same dialog the explicit call would. Calling connect directly and handling the failure is frequently a better flow than making the user press Pair and then Connect.
Where you do need it explicitly: when you want to pair well ahead of use, when the device needs a PIN entered outside your app, or when your UI shows a paired-device manager.
Reading the current state#
Every device from a scan or from the paired list carries its bond state, so you can label a list without asking separately.
for (final device in devices) {
final label = switch (device.bondState) {
BtcBondState.bonded => 'Paired',
BtcBondState.bonding => 'Pairing...',
BtcBondState.none => 'Not paired',
};
print('${device.displayName}: $label');
}