如何以编程方式判断蓝牙设备是不是已连接?

Posted

技术标签:

【中文标题】如何以编程方式判断蓝牙设备是不是已连接?【英文标题】:How can I programmatically tell if a Bluetooth device is connected?如何以编程方式判断蓝牙设备是否已连接? 【发布时间】:2011-01-17 17:13:45 【问题描述】:

我了解如何获取已配对设备的列表,但如何判断它们是否已连接?

这一定是可能的,因为我看到它们列在我手机的蓝牙设备列表中,并说明了它们的连接状态。

【问题讨论】:

【参考方案1】:

将蓝牙权限添加到您的 androidManifest,

<uses-permission android:name="android.permission.BLUETOOTH" />

然后使用意图过滤器收听ACTION_ACL_CONNECTEDACTION_ACL_DISCONNECT_REQUESTEDACTION_ACL_DISCONNECTED 广播:

public void onCreate() 
    ...
    IntentFilter filter = new IntentFilter();
    filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
    this.registerReceiver(mReceiver, filter);


//The BroadcastReceiver that listens for bluetooth broadcasts
private final BroadcastReceiver mReceiver = new BroadcastReceiver() 
    @Override
    public void onReceive(Context context, Intent intent) 
        String action = intent.getAction();
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

        if (BluetoothDevice.ACTION_FOUND.equals(action)) 
           ... //Device found
        
        else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) 
           ... //Device is now connected
        
        else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) 
           ... //Done searching
        
        else if (BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) 
           ... //Device is about to disconnect
        
        else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) 
           ... //Device has disconnected
        
    
;

几点说明:

无法在应用程序启动时检索已连接设备的列表。蓝牙 API 不允许您查询,而是允许您收听更改。 解决上述问题的一个好方法是检索所有已知/配对设备的列表...然后尝试连接每个设备(以确定您是否已连接)。 或者,您可以让后台服务监视蓝牙 API 并将设备状态写入磁盘以供您的应用程序在以后使用。

【讨论】:

这很好,只要我的应用程序正在运行,但我怎样才能获得当前列表? 在应用程序“运行”的情况下如何执行代码?如果您的意思是您需要从 Activity 以外的其他东西访问它...去谷歌 Android 服务,构建其中一个来收听广播,并将其保存到列表中。 我可以监听意图,但是如何获取已连接蓝牙设备的初始列表?如果在我的活动或服务启动时已经连接,我不知道。我想(希望)这些数据在某处可用?我不想仅仅为了监听这些意图而创建一个服务(只要手机开机就一直运行)。 无法在应用程序启动时检索已连接设备的列表。蓝牙 API 只会让您收听连接更改。所以,是的,唯一的方法是创建一个长期运行的服务并添加/删除到公共列表。这是许多开发人员的一大抱怨。根据您的性能需求,您可以检索配对设备列表并尝试连接到每个设备。如果失败,则不可用。警告的话:.connect() 是一个阻塞操作。 @skylarsutton +1 非常感谢这个答案,帮助我开始使用蓝牙【参考方案2】:

在我的用例中,我只想查看是否为 VoIP 应用连接了蓝牙耳机。以下解决方案对我有用。

科特林:

fun isBluetoothHeadsetConnected(): Boolean 
    val mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
    return (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled
        && mBluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED)

Java:

public static boolean isBluetoothHeadsetConnected() 
    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()
            && mBluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED;
 

当然你需要蓝牙权限:

<uses-permission android:name="android.permission.BLUETOOTH" />

【讨论】:

这是我一直在寻找的。只是在启动时检查蓝牙是否已连接。谢谢它的工作! 此解决方案一直有效,直到我将 Android Studio 升级到版本 2021.1.1。现在getProfileConnectionState(BluetoothHeadset.HEADSET) 调用显示错误“调用需要可能被用户拒绝的权限:代码应显式检查权限是否可用(使用 checkPermission)或显式处理潜在的 SecurityException”。所需的权限是Manifest.permission.BLUETOOTH_CONNECT 我看到一个问题,即三星 Galaxy Watch4 在此通话中显示为耳机,即使 device.bluetoothClass.hasService(BluetoothClass.Service.AUDIO)=false。我试图弄清楚如何确定是否有任何连接的设备支持音频,但isConnected 调用仅是 SystemApi。目前我可以看到所有绑定的设备,但无法判断它们是否已连接 - 所以我无法确定耳机是否真的连接或只是手表(即我有未连接的耳机)。有人对此有解决方案吗?【参考方案3】:

由于某种原因,Android Studio 无法解析 BluetoothAdapter.ACTION_ACL_CONNECTED。也许它在 Android 4.2.2 中已被弃用?

这是对 Skylarsutton 代码的修改(非常感谢Skylarsutton for his answer。)。注册码相同;接收器代码略有不同。我在一项服务中使用它来更新应用程序其他部分引用的蓝牙连接标志。

    public void onCreate() 
        //...
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        this.registerReceiver(BTReceiver, filter);
    

    //The BroadcastReceiver that listens for bluetooth broadcasts
    private final BroadcastReceiver BTReceiver = new BroadcastReceiver() 
    @Override
    public void onReceive(Context context, Intent intent) 
        String action = intent.getAction();

        if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) 
            //Do something if connected
            Toast.makeText(getApplicationContext(), "BT Connected", Toast.LENGTH_SHORT).show();
        
        else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) 
            //Do something if disconnected
            Toast.makeText(getApplicationContext(), "BT Disconnected", Toast.LENGTH_SHORT).show();
        
        //else if...
    
;

【讨论】:

你的代码是正确的;它在 4.2.2 中没有被弃用。 BluetoothAdapter 类不包含 ACTION_ACL_CONNECTED。该字符串在 BluetoothDevice 类中。 感谢您的澄清!【参考方案4】:

https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth/BluetoothDevice.java中的BluetoothDevice系统API中有一个isConnected函数。

如果您想知道当前是否连接了有界(配对)设备,以下功能对我来说很好:

public static boolean isConnected(BluetoothDevice device) 
    try 
        Method m = device.getClass().getMethod("isConnected", (Class[]) null);
        boolean connected = (boolean) m.invoke(device, (Object[]) null);
        return connected;
     catch (Exception e) 
        throw new IllegalStateException(e);
    

【讨论】:

你有没有看到这与仅仅检查bluetoothManager.getConnectionState(device, BluetoothProfile.GATT) == BluetoothProfile.STATE_CONNECTED是否有不同的结果? 据我所知,它们确实给出了相同的结果。请注意,对于 Kotlin 用户,前两行只是 val m: Method = device.javaClass.getMethod("isConnected")val connected = m.invoke(device) 谢谢你,正是我需要的!这是此方法的 kotlin 等效项:fun isConnected(device: BluetoothDevice): Boolean return try val m: Method = device.javaClass.getMethod( "isConnected" ) m.invoke(device) as Boolean catch (e: Exception) throw IllegalStateException(e) 【参考方案5】:

此代码适用于耳机配置文件,可能也适用于其他配置文件。

首先您需要提供一个配置文件监听器(Kotlin 代码):

private val mProfileListener = object : BluetoothProfile.ServiceListener 
    override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) 
        if (profile == BluetoothProfile.HEADSET)
            mBluetoothHeadset = proxy as BluetoothHeadset
    

    override fun onServiceDisconnected(profile: Int) 
        if (profile == BluetoothProfile.HEADSET) 
            mBluetoothHeadset = null
        
    

然后在检查蓝牙时:

mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET)
if (!mBluetoothAdapter.isEnabled) 
    return Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)

调用 onServiceConnected 需要一些时间。之后,您可以从以下位置获取已连接耳机设备的列表:

mBluetoothHeadset!!.connectedDevices

【讨论】:

【参考方案6】:

我真的在寻找一种方法来获取设备的连接状态,而不是监听连接事件。这对我有用:

BluetoothManager bm = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
List<BluetoothDevice> devices = bm.getConnectedDevices(BluetoothGatt.GATT);
int status = -1;

for (BluetoothDevice device : devices) 
  status = bm.getConnectionState(device, BLuetoothGatt.GATT);
  // compare status to:
  //   BluetoothProfile.STATE_CONNECTED
  //   BluetoothProfile.STATE_CONNECTING
  //   BluetoothProfile.STATE_DISCONNECTED
  //   BluetoothProfile.STATE_DISCONNECTING

【讨论】:

【参考方案7】:

BluetoothAdapter.getDefaultAdapter().isEnabled -> 蓝牙打开时返回 true。

val audioManager = this.getSystemService(Context.AUDIO_SERVICE) as AudioManager

audioManager.isBluetoothScoOn -> 当设备连接时返回 true

【讨论】:

以上是关于如何以编程方式判断蓝牙设备是不是已连接?的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式连接安卓设备和蓝牙耳机

Android 蓝牙开发-打开蓝牙后能不能立即连接固定地址的蓝牙设备??还是需要进行判断啥的?

有没有办法通过 iOS/swift 中的蓝牙以编程方式连接 android 和 IOS 设备?

哪位清楚android判断蓝牙是不是连接

如何以编程方式确定蓝牙主/从角色?

以编程方式连接到蓝牙