蓝牙 SDP 和 UUID 如何工作? (专门针对 Android)
How do Bluetooth SDP and UUIDs work? (specifically for Android)
我的理解是SDP是其他设备可以获取的UUID列表。
根据麻省理工学院的这个 PDF,“一种更通用的思考方式
SDP 是一个信息数据库。”这是否意味着我可以向 SDP 添加多个值?由于 Android 有 BluetoothDevice.fetchUuidsWithSdp()
,我该如何设置设备的 UUID?
此外,UUID 的每个部分是什么意思? UUID 看起来像 00000000-0000-1000-8000-00805F9B34FB
,但这传达了什么信息?
UUID 标识在特定设备上可用的服务。因此,如果您调用 BluetoothDevice.fetchUUidsWithSdp()
,您的 BroadcastReceiver 将收到包含设备和服务 UUID 的相关 Intent ACTION_UUID。
蓝牙规格 defines some common UUIDs。
如果您不想连接到这些众所周知的服务之一,而是想实现您自己的蓝牙应用程序,那么您必须生成自己的 UUID(从 unix 控制台或 online generator) 标识您的 application/service。
您可以像这样在 java 中创建一个 UUID 实例 UUID uuid = UUID.fromString("785da8ea-1220-11e5-9493-1697f925ec7b");
.
因此,如果您在 Android 上为蓝牙应用程序创建服务器端,您通常会 this
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("YourHumanReadableServiceName", uuid);
这就是您 "set" 您的 UUID。 Android 蓝牙 API 为您创建由您应用程序的 UUID 和名称组成的 SDP 条目。其他设备现在可以检索此条目。 Androids 蓝牙堆栈现在会将蓝牙通道关联到您的 BluetoothServerSocket。如果你想连接到这个 ServerSocket,连接端通常连接做 this:
// you will most likely already have this instance from a discovery or paired device list
BluetoothDevice serverDevice = adapter.getRemoteDevice(bluetoothMacAddress);
// connect to your ServerSocket using the uuid
BluetoothSocket socket = serverDevice.createRfcommSocketToServiceRecord(uuid);
socket.connect();
Android 将再次为您完成繁重的工作:它检查远程设备上的 SDP 记录,查找与您服务的 UUID 相对应的蓝牙通道,并使用此信息进行连接。
SO 上有一个常见的代码片段,它建议您使用 "reflection" 进入一个隐藏的 API,看起来类似于此代码:
try {
// this is the way to go
socket = device.createRfcommSocketToServiceRecord(uuid);
socket.connect( );
} catch ( IOException exception ) {
// don't do that! You will bypass SDP and things will go sideways.
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
socket = (BluetoothSocket) m.invoke(device, 1);
socket.connect();
}
大多数人都在他们的开发环境中尝试过此操作 "just works",但您应该知道使用它可以做什么。您主动绕过 SDP 查找,检索正确的蓝牙通道以与您的服务一起使用,您最终将连接到通道 1。如果您的设备上有多个服务 运行,事情将会发生变化案例,你最终会陷入调试地狱;-)
我开发了一个 small middleware called Blaubot 来使用 bluetooth/wifi/nfc 创建小型网络,但在我用来测试的设备(12 个型号)上遇到了各种问题。通常情况下,如果蓝牙堆栈有一些负载或经过许多 connects/disconnects(如果您正在开发您的应用程序,您通常会拥有),蓝牙堆栈不再完全正常运行。在这些情况下,device.createRfcommSocketToServiceRecord(uuid)
偶尔会出现故障,只有关闭蓝牙适配器并再次打开才有助于使蓝牙适配器恢复正常(在某些情况下仅在完全电源循环后)。如果出现这种情况,而你使用的是反射方式,那么你蓝牙的乐趣恐怕就没有了。
但如果您了解这一点并在一定范围内保持对 BluetoothAdapter 的并发调用,蓝牙连接和适配器将非常稳定。
我的理解是SDP是其他设备可以获取的UUID列表。
根据麻省理工学院的这个 PDF,“一种更通用的思考方式
SDP 是一个信息数据库。”这是否意味着我可以向 SDP 添加多个值?由于 Android 有 BluetoothDevice.fetchUuidsWithSdp()
,我该如何设置设备的 UUID?
此外,UUID 的每个部分是什么意思? UUID 看起来像 00000000-0000-1000-8000-00805F9B34FB
,但这传达了什么信息?
UUID 标识在特定设备上可用的服务。因此,如果您调用 BluetoothDevice.fetchUUidsWithSdp()
,您的 BroadcastReceiver 将收到包含设备和服务 UUID 的相关 Intent ACTION_UUID。
蓝牙规格 defines some common UUIDs。
如果您不想连接到这些众所周知的服务之一,而是想实现您自己的蓝牙应用程序,那么您必须生成自己的 UUID(从 unix 控制台或 online generator) 标识您的 application/service。
您可以像这样在 java 中创建一个 UUID 实例 UUID uuid = UUID.fromString("785da8ea-1220-11e5-9493-1697f925ec7b");
.
因此,如果您在 Android 上为蓝牙应用程序创建服务器端,您通常会 this
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("YourHumanReadableServiceName", uuid);
这就是您 "set" 您的 UUID。 Android 蓝牙 API 为您创建由您应用程序的 UUID 和名称组成的 SDP 条目。其他设备现在可以检索此条目。 Androids 蓝牙堆栈现在会将蓝牙通道关联到您的 BluetoothServerSocket。如果你想连接到这个 ServerSocket,连接端通常连接做 this:
// you will most likely already have this instance from a discovery or paired device list
BluetoothDevice serverDevice = adapter.getRemoteDevice(bluetoothMacAddress);
// connect to your ServerSocket using the uuid
BluetoothSocket socket = serverDevice.createRfcommSocketToServiceRecord(uuid);
socket.connect();
Android 将再次为您完成繁重的工作:它检查远程设备上的 SDP 记录,查找与您服务的 UUID 相对应的蓝牙通道,并使用此信息进行连接。
SO 上有一个常见的代码片段,它建议您使用 "reflection" 进入一个隐藏的 API,看起来类似于此代码:
try {
// this is the way to go
socket = device.createRfcommSocketToServiceRecord(uuid);
socket.connect( );
} catch ( IOException exception ) {
// don't do that! You will bypass SDP and things will go sideways.
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
socket = (BluetoothSocket) m.invoke(device, 1);
socket.connect();
}
大多数人都在他们的开发环境中尝试过此操作 "just works",但您应该知道使用它可以做什么。您主动绕过 SDP 查找,检索正确的蓝牙通道以与您的服务一起使用,您最终将连接到通道 1。如果您的设备上有多个服务 运行,事情将会发生变化案例,你最终会陷入调试地狱;-)
我开发了一个 small middleware called Blaubot 来使用 bluetooth/wifi/nfc 创建小型网络,但在我用来测试的设备(12 个型号)上遇到了各种问题。通常情况下,如果蓝牙堆栈有一些负载或经过许多 connects/disconnects(如果您正在开发您的应用程序,您通常会拥有),蓝牙堆栈不再完全正常运行。在这些情况下,device.createRfcommSocketToServiceRecord(uuid)
偶尔会出现故障,只有关闭蓝牙适配器并再次打开才有助于使蓝牙适配器恢复正常(在某些情况下仅在完全电源循环后)。如果出现这种情况,而你使用的是反射方式,那么你蓝牙的乐趣恐怕就没有了。
但如果您了解这一点并在一定范围内保持对 BluetoothAdapter 的并发调用,蓝牙连接和适配器将非常稳定。