蓝牙SDP和UUID是如何工作的?(特别是对于Android)

7
我的理解是,SDP是其他设备可以获取的UUID列表。
根据MIT的这份PDF文件,“更一般的理解SDP是一个信息数据库。”这是否意味着我可以向SDP添加多个值?由于Android具有“BluetoothDevice.fetchUuidsWithSdp()”,那么如何设置设备的UUID?
此外,UUID的每个部分代表什么意思?UUID看起来像“00000000-0000-1000-8000-00805F9B34FB”,但这传达了什么信息?
1个回答

17
一个UUID标识了特定设备上可用的服务。因此,如果您调用BluetoothDevice.fetchUUidsWithSdp(),您的广播接收器将接收到相关的意图ACTION_UUID,其中包含设备和服务UUID。蓝牙规范定义了一些常见的UUIDs
如果您不想连接到这些众所周知的服务之一,而是打算实现自己的蓝牙应用程序,则必须生成自己的UUID(使用Unix控制台或在线生成器中的uuidgen),以标识您的应用程序/服务。您可以像这样在Java中创建UUID实例:UUID uuid = UUID.fromString("785da8ea-1220-11e5-9493-1697f925ec7b");
因此,如果您在Android上为蓝牙应用程序创建服务器端,则通常执行this
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("YourHumanReadableServiceName", uuid);

在这里,你可以“设置”你的UUID。安卓蓝牙API会为你创建包含应用UUID和名称的SDP条目。其他设备现在可以检索此条目。安卓蓝牙堆栈将会给你的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上出现,建议您使用“反射”来访问类似于此代码的隐藏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();
 }

大多数人在他们的开发环境中尝试这样做,它会“只是工作”,但你应该知道使用这个方法要做什么。你主动绕过SDP查找,以检索与你的服务一起使用的正确蓝牙通道,并最终连接到通道1。如果设备上运行多个服务,则在这些情况下事情将会变得复杂,你将陷入调试地狱;-)

我开发了一个名为Blaubot的小型中间件,用于使用蓝牙/ wifi / nfc创建小型网络,并在我用于测试的设备上遇到了各种问题(12个型号)。通常情况下,当蓝牙堆栈承受一定负载或进行多次连接/断开连接后(如果你正在开发应用程序),蓝牙堆栈就不再完全正常工作。在这些情况下,device.createRfcommSocketToServiceRecord(uuid)偶尔会失败,只有关闭并重新打开蓝牙适配器才能帮助恢复蓝牙适配器的功能(在某些情况下仅在完全电源循环之后)。如果出现这种情况并且你使用反射方法,那么你可能不会对蓝牙感到满意。

但是,如果你知道这一点并将对BluetoothAdapter的并发调用保持在合理范围内,蓝牙连接和适配器将非常稳定。


你知道我是否可以添加多个SDP记录吗?我尝试使用adapter.listenUsingRfcommWithServiceRecord多次,但只有一个可以被其他设备看到。 - Leo Jiang
这就是你要做的。只要你的BluetoothServerSocket存在,UUID就应该可以被其他设备发现。你尝试从另一个设备连接两者了吗?如果可以连接成功,那么你的问题可能在于发现。 - hgross
我认为我的应用正在使用缓存数据,我将尝试 fetchUuidsWithSdp 看看是否可以解决。 - Leo Jiang
是的,这是一个问题。SDP记录会被缓存一段时间,因此如果您更改了服务或设备名称等值,则会在一段时间内获取缓存的值。重新启动电源应该会有所帮助。 - hgross
1
@hna 当我使用listenUsingRfcommWithServiceRecord时,由于某种原因,当我从另一个设备扫描它时,UUID会翻转。例如,当我将其设置为:785da8ea-1220-11e5-9493-1697f925ec7b时,我得到的是7bec25f9-97114-9394-e511-2012eaa85d78。请注意每两个字符。您知道它可能是为什么吗? - mtfk
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接