Android NDK开发详解连接性之查找蓝牙设备

Android NDK开发详解连接性之查找蓝牙设备

借助 BluetoothAdapter,您可以通过设备发现或查询已配对设备列表来查找远程蓝牙设备。

在尝试查找蓝牙设备之前,请确保您拥有适当的蓝牙权限并为应用设置蓝牙。

设备发现是一个扫描过程,它会搜索本地区域以查找支持蓝牙的设备,并请求每台设备的一些信息。此过程有时也称为发现、查询或扫描。仅当目前通过可检测到的方式接受信息请求时,附近的蓝牙设备才会响应发现请求。如果设备可被检测到,它会通过分享一些信息(例如设备的名称、类及其唯一 MAC 地址)来响应发现请求。利用这些信息,执行发现过程的设备可以选择发起与被发现设备的连接。

由于可检测设备可能会泄露有关用户位置信息的信息,因此设备发现过程需要位置信息访问权限。如果您的应用在搭载 Android 8.0(API 级别 26)或更高版本的设备上使用,请考虑改用 Companion Device Manager API。此 API 可代表您的应用执行设备发现,因此该应用无需请求位置信息权限。

在首次与远程设备建立连接后,系统会自动向用户显示配对请求。设备配对后,系统会保存该设备的基本信息(例如设备的名称、类和 MAC 地址),并且可使用 Bluetooth API 读取这些信息。使用远程设备的已知 MAC 地址,可以随时与远程设备建立连接,而无需执行发现操作(假定该设备仍处于有效范围内)。

请注意,被配对与被连接之间存在区别:

“要配对”意味着两台设备知道彼此的存在,具有可用于身份验证的共享链路密钥,并且能够与彼此建立加密连接。
“要连接”表示设备当前共享一个 RFCOMM 通道,并且能够相互传输数据。当前的蓝牙 API 要求对设备进行配对,然后才能建立 RFCOMM 连接。当您使用 Bluetooth API 发起加密连接时,系统会自动执行配对。

以下部分介绍了如何查找已配对的设备,以及如何使用设备发现来发现新设备。
注意 :默认情况下,Android 设备处于不可检测到状态。用户可以通过系统设置将设备设为在有限的时间内处于可检测到状态,或者应用可以请求用户在不离开应用的情况下启用可检测性。如需了解详情,请参阅本页面上的启用可检测性部分。

查询已配对设备

在执行设备发现之前,有必要查询已配对设备组,以了解所需的设备是否处于已知状态。为此,请调用 getBondedDevices()。这将返回一组表示已配对设备的 BluetoothDevice 对象。例如,您可以查询所有已配对的设备并获取每台设备的名称和 MAC 地址,如以下代码段所示:
Kotlin

val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
pairedDevices?.forEach { device ->
   val deviceName = device.name
   val deviceHardwareAddress = device.address // MAC address
}

Java

Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();

if (pairedDevices.size() > 0) {
   // There are paired devices. Get the name and address of each paired device.
   for (BluetoothDevice device : pairedDevices) {
       String deviceName = device.getName();
       String deviceHardwareAddress = device.getAddress(); // MAC address
   }
}


如需发起与蓝牙设备的连接,只需从关联的 BluetoothDevice 对象中获取 MAC 地址,即可通过调用 getAddress() 检索此地址。您可以参阅连接蓝牙设备,详细了解如何创建连接。

发现设备

如需开始发现设备,请调用 startDiscovery()。该过程是异步的,并且会返回一个布尔值,指示发现是否已成功启动。发现过程通常涉及大约 12 秒的查询扫描,然后对发现的每台设备进行页面扫描,以检索其蓝牙名称。

为了接收发现的每个设备的相关信息,您的应用必须为 ACTION_FOUND intent 注册一个 BroadcastReceiver。系统会为每个设备广播此 intent。该 intent 包含额外字段 EXTRA_DEVICE 和 EXTRA_CLASS,而这两个字段又分别包含 BluetoothDevice 和 BluetoothClass。以下代码段展示了如何在发现设备时通过注册来处理广播:
Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
   ...

   // Register for broadcasts when a device is discovered.
   val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)
   registerReceiver(receiver, filter)
}

// Create a BroadcastReceiver for ACTION_FOUND.
private val receiver = object : BroadcastReceiver() {

   override fun onReceive(context: Context, intent: Intent) {
       val action: String = intent.action
       when(action) {
           BluetoothDevice.ACTION_FOUND -> {
               // Discovery has found a device. Get the BluetoothDevice
               // object and its info from the Intent.
               val device: BluetoothDevice =
                       intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
               val deviceName = device.name
               val deviceHardwareAddress = device.address // MAC address
           }
       }
   }
}

override fun onDestroy() {
   super.onDestroy()
   ...

   // Don't forget to unregister the ACTION_FOUND receiver.
   unregisterReceiver(receiver)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
   ...

   // Register for broadcasts when a device is discovered.
   IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
   registerReceiver(receiver, filter);
}

// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {
   public void onReceive(Context context, Intent intent) {
       String action = intent.getAction();
       if (BluetoothDevice.ACTION_FOUND.equals(action)) {
           // Discovery has found a device. Get the BluetoothDevice
           // object and its info from the Intent.
           BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
           String deviceName = device.getName();
           String deviceHardwareAddress = device.getAddress(); // MAC address
       }
   }
};

@Override
protected void onDestroy() {
   super.onDestroy();
   ...

   // Don't forget to unregister the ACTION_FOUND receiver.
   unregisterReceiver(receiver);
}

如需发起与蓝牙设备的连接,您可以对 BluetoothDevice 调用 getAddress(),以检索关联的 MAC 地址。
注意 :执行设备发现会消耗蓝牙适配器的大量资源。找到要连接的设备后,请确保在尝试连接之前停止使用 cancelDiscovery() 进行发现。此外,您不应在连接到设备时执行发现,因为发现过程会大幅减少任何现有连接的可用带宽。
启用可检测性

如需使本地设备可被其他设备检测到,请使用 ACTION_REQUEST_DISCOVERABLE intent 调用 startActivityForResult(Intent, int)。此操作会发出启用系统的可检测模式的请求,而无需导航到“设置”应用,这会停止您自己的应用。默认情况下,设备处于可检测到状态的时间为两分钟。您可以通过添加 EXTRA_DISCOVERABLE_DURATION extra 来定义不同的时长(最长 1 小时)。
注意 :如果将 EXTRA_DISCOVERABLE_DURATION extra 的值设置为 0,则设备始终可检测到。此配置不安全,因此强烈建议不要这样做。

以下代码段会将设备设置为可检测到 5 分钟:
Kotlin

val requestCode = 1;
val discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
   putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
}
startActivityForResult(discoverableIntent, requestCode)

Java

int requestCode = 1;
Intent discoverableIntent =
       new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivityForResult(discoverableIntent, requestCode);

图 2:启用可检测性对话框。
在这里插入图片描述

系统会显示一个对话框,请求用户授予权限以使设备可被检测到,如图 2 所示。如果用户响应“允许”,设备在指定的时间段内变为可检测到状态。然后,您的 activity 会收到对 onActivityResult() 回调的调用,其结果代码等于设备可检测到的时长。如果用户响应“拒绝”或出现错误,则结果代码为 RESULT_CANCELED。
注意 :如果设备上未启用蓝牙,则将设备设为可检测到的状态会自动启用蓝牙。

设备会在分配的时间内静默地保持可检测模式。如需在可检测到模式发生变化时收到通知,请为 ACTION_SCAN_MODE_CHANGED intent 注册 BroadcastReceiver。此 intent 包含 extra 字段 EXTRA_SCAN_MODE 和 EXTRA_PREVIOUS_SCAN_MODE,分别提供新旧扫描模式。每个 extra 的可能值如下:

SCAN_MODE_CONNECTABLE_DISCOVERABLE
设备处于可检测到模式。
SCAN_MODE_CONNECTABLE
设备未处于可检测到模式,但仍然可以接收连接。
SCAN_MODE_NONE
设备不处于可检测到模式,且无法接收连接。

如果您要发起与远程设备的连接,则无需启用设备可检测性。仅当您希望应用托管用于接受传入连接的服务器套接字时,才有必要启用可检测性,因为远程设备必须能够在发起与其他设备的连接之前发现其他设备。

本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。

最后更新时间 (UTC):2023-11-08。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五一编程

程序之路有我与你同行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值