3、经典蓝牙(BR/EDR)基础:蓝牙适配器(BluetoothAdapter)操作、开启/关闭蓝牙、搜索设备、绑定配对流程
好,咱们正式开始动手操作蓝牙了。
这一章,我带你搞定经典蓝牙最核心的几个操作:蓝牙适配器、开关蓝牙、搜索设备、绑定配对。说白了,就是让手机能发现别人,也能被别人发现。
3.1 蓝牙适配器(BluetoothAdapter)—— 一切操作的入口
在 Android 里,所有蓝牙操作都绕不开一个对象:BluetoothAdapter。你可以把它理解成「蓝牙硬件的大门」。没有它,你什么都干不了。
获取它的方式很简单:
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
如果返回 null,说明设备不支持蓝牙。嗯,这种情况现在很少见了,但我记得早期在一些平板上遇到过。
3.2 开启/关闭蓝牙
拿到适配器后,第一件事就是检查蓝牙状态。
if (!bluetoothAdapter.isEnabled()) {
// 蓝牙未开启
}
开启蓝牙有两种方式:
- 隐式启动(推荐):通过 Intent 让用户确认
- 直接启动:调用
enable()方法(需要系统权限)
我一般用第一种,用户体验更好:
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
为什么不用 enable()?
因为 enable() 是静默开启,用户完全不知道。我曾经在一个项目里这么干过,结果被用户投诉「手机偷偷开蓝牙,是不是在偷我数据?」—— 从那以后,我再也不敢用直接开启了。
bluetoothAdapter.enable() 需要 BLUETOOTH_ADMIN 权限,且 Android 10 以上限制更严格。非系统应用不建议使用。
关闭蓝牙更简单:
bluetoothAdapter.disable();
但同样需要 BLUETOOTH_ADMIN 权限。我个人建议:关闭操作也交给用户自己决定,别替用户做主。
3.3 搜索设备 —— 让蓝牙「看见」周围
蓝牙搜索,说白了就是让手机发出询问信号,周围设备回应「我在这里」。
开始搜索:
bluetoothAdapter.startDiscovery();
停止搜索:
bluetoothAdapter.cancelDiscovery();
搜索结果通过广播接收器获取。你需要注册监听 BluetoothDevice.ACTION_FOUND:
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String name = device.getName();
String address = device.getAddress();
// 处理发现的设备
}
}
};
这里有个坑,我踩过好几次:
另外,搜索时间一般持续 12 秒左右。你可以通过 ACTION_DISCOVERY_FINISHED 监听搜索结束。
3.4 绑定配对流程 —— 建立信任关系
搜索到设备后,下一步就是配对。配对说白了就是交换密钥,建立信任关系。
配对流程分两步:
- 发起配对请求
- 用户确认 PIN 码或配对码
代码层面,你只需要调用:
device.createBond();
系统会自动弹出配对对话框。但这里有个细节:createBond() 是隐藏 API,需要通过反射调用:
Method createBondMethod = device.getClass().getMethod("createBond");
createBondMethod.invoke(device);
或者,更稳妥的方式是监听 ACTION_PAIRING_REQUEST 广播,手动处理配对:
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
registerReceiver(pairingReceiver, filter);
在广播接收器里,你可以设置 PIN 码或者确认配对:
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 自动配对(比如 PIN 码固定为 "1234")
device.setPin("1234".getBytes());
// 或者直接确认配对
device.setPairingConfirmation(true);
}
setPin 再 setPairingConfirmation,有的顺序反了就会失败。我的建议是:先查一下目标设备的蓝牙协议栈文档,别想当然。
3.5 获取已绑定设备列表
有时候你不需要重新搜索,直接拿之前配过对的设备就行:
Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : bondedDevices) {
Log.d("Bluetooth", "已绑定设备:" + device.getName() + " - " + device.getAddress());
}
这个方法返回的是已经完成配对的设备。注意,配对不等于连接。配对只是交换了密钥,连接才是真正的数据传输通道。
3.6 权限声明(Android 12+ 变化)
最后,别忘了权限。Android 12(API 31)开始,蓝牙权限有了重大变化:
| 权限 | 作用 | Android 12+ |
|---|---|---|
| BLUETOOTH | 基本蓝牙操作(连接、通信) | 需要运行时申请 |
| BLUETOOTH_ADMIN | 管理蓝牙(搜索、配对) | 需要运行时申请 |
| ACCESS_FINE_LOCATION | 传统蓝牙搜索需要位置权限 | Android 12 以下需要 |
| BLUETOOTH_SCAN | 替代位置权限,专门用于搜索 | Android 12+ 新增 |
| BLUETOOTH_CONNECT | 替代 BLUETOOTH,专门用于连接 | Android 12+ 新增 |
简单来说:如果你适配 Android 12+,请使用 BLUETOOTH_SCAN 和 BLUETOOTH_CONNECT,别再依赖位置权限了。我最近重构一个老项目时,发现很多开发者还在用旧权限,结果在 Android 13 上直接崩溃。
- BluetoothAdapter 是蓝牙操作的入口,先判空再使用
- 开启蓝牙推荐用 Intent 方式,别偷偷摸摸
- 搜索设备用 startDiscovery(),记得停止搜索再连接
- 配对用 createBond(),复杂场景用广播手动处理
- Android 12+ 权限变了,赶紧更新你的代码
下一章,咱们开始真正建立蓝牙连接,传输数据。准备好了吗?