如何获取Android Oreo系统下已连接蓝牙设备的名称
解决Android Oreo获取已连接蓝牙设备名称的问题
我之前在Android 8.0(Oreo)上也碰到过一模一样的坑——那些老的蓝牙设备查询方法要么失效,要么直接抛出IOException: read failed, socket might closed错误。这主要是因为Oreo开始对蓝牙API的权限和访问限制做了调整,老方法已经不适用了。给你两个亲测有效的方案:
方案一:通过BluetoothManager直接获取已连接设备
这是最直接的方式,利用系统提供的BluetoothManager API来获取当前处于连接状态的蓝牙设备,不需要手动操作socket,自然不会触发那个IO错误。
步骤:
- 添加权限:在
AndroidManifest.xml里声明必要的蓝牙权限(Oreo属于正常权限,无需动态申请):
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
- 获取已连接设备:通过BluetoothManager获取指定蓝牙Profile的已连接设备,比如音频设备用
BluetoothProfile.A2DP或BluetoothProfile.HEADSET,通用设备用BluetoothProfile.GATT:
// 获取BluetoothManager实例 BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); // 获取连接中的A2DP设备(比如蓝牙耳机、音箱) List<BluetoothDevice> connectedAudioDevices = bluetoothManager.getConnectedDevices(BluetoothProfile.A2DP); // 遍历设备列表获取名称 for (BluetoothDevice device : connectedAudioDevices) { String deviceName = device.getName(); String deviceAddress = device.getAddress(); // 处理设备信息 }
- 监听连接状态(可选):如果
getConnectedDevices返回空,可能是设备刚连接还没同步状态,可以注册BluetoothProfile.ServiceListener来监听连接变化:
bluetoothManager.getProfileProxy(this, new BluetoothProfile.ServiceListener() { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { List<BluetoothDevice> connectedDevices = proxy.getConnectedDevices(); // 处理已连接设备 bluetoothManager.closeProfileProxy(profile, proxy); // 记得用完关闭代理 } @Override public void onServiceDisconnected(int profile) { // 服务断开处理 } }, BluetoothProfile.A2DP);
方案二:动态注册广播接收器监听连接事件
Oreo限制了隐式广播的静态注册,所以我们需要动态注册广播接收器来监听蓝牙设备的连接动作,一旦设备连接成功,直接从Intent中获取设备信息。
实现代码:
- 创建广播接收器:
private BroadcastReceiver bluetoothConnectReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) { // 从Intent中取出已连接的蓝牙设备 BluetoothDevice connectedDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (connectedDevice != null) { String deviceName = connectedDevice.getName(); // 这里处理设备名称 } } } };
- 动态注册/注销接收器:
@Override protected void onResume() { super.onResume(); // 注册广播接收器,监听设备连接事件 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED); registerReceiver(bluetoothConnectReceiver, filter); } @Override protected void onPause() { super.onPause(); // 记得注销接收器,避免内存泄漏 unregisterReceiver(bluetoothConnectReceiver); }
为什么老方法会报错?
那些依赖蓝牙Socket连接获取设备信息的方法,在Oreo开始被严格限制——系统会阻止未授权的Socket访问,尤其是当设备未配对或者App没有足够权限时,就会抛出read failed, socket might closed的错误。上面的两种方案都是利用系统提供的官方API,避开了直接操作Socket的风险,所以能稳定运行。
额外注意事项:
- 确保设备蓝牙已经开启,可以用
BluetoothAdapter.getDefaultAdapter().isEnabled()检查,未开启的话可以通过Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)请求用户打开。 - 部分设备的
getName()可能返回null,这时候可以用getAddress()(蓝牙MAC地址)作为备选标识。
内容的提问来源于stack exchange,提问作者Hossain Ehsani
相关产品推荐
相关产品推荐

