Android:在 SPP 蓝牙设备之间切换

Posted

技术标签:

【中文标题】Android:在 SPP 蓝牙设备之间切换【英文标题】:Android: Switch between SPP Bluetooth Devices 【发布时间】:2012-07-02 19:04:17 【问题描述】:

我有两台不同的蓝牙打印机。 Bixolon SPP-R200 和富士通 FTP-628WSL110。我可以分别连接到它们(使用三星 Galaxy SII)打印、断开连接和重新连接就好了。但是,如果我关闭 Bixolon 并尝试与 Fujitsu 配对(之前未配对,Bixolon 仍然配对),那么在尝试连接到创建的套接字时它会失败。反之亦然。

这是错误信息:

07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380): Failed to connect to rfcomm socket.
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380): java.io.IOException: Service discovery failed
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at android.bluetooth.BluetoothSocket$SdpHelper.doSdp(BluetoothSocket.java:406)
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:217)
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at MyApp.BluetoothConnection.connect(BluetoothConnection.java:171)
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at MyApp.AbstractBluetoothPrinter.connect(AbstractBluetoothPrinter.java:34)

这是进行连接尝试的代码,在解释的情况下失败的行是 btSocket.connect(); - 例外见上文:

/** Is set in connect() */
private BluetoothSocket btSocket = null;
/** Is set prior to connect() */
private BluetoothSocket btDevice;

public boolean connect()

        try 
            btSocket = btDevice.createRfcommSocketToServiceRecord("00001101-0000-1000-8000-00805F9B34FB");
            if (btDevice.getName().startsWith("FTP")) 
                //Special treatment for the fujitsu printer
                SystemClock.sleep(1000);
            
         catch (Throwable e) 
            LogCat.e(TAG, "Failed to create rfcomm socket.", e);
            return false;
        

        try 
            // Stop Bluetooth discovery if it's going on
            BluetoothHandler.cancelDiscovery();
            // This fails under the described circumstances
            btSocket.connect();
         catch (Throwable e) 
            LogCat.e(TAG, "Failed to connect to rfcomm socket.", e);
            return false;
        

        // Obtain streams etc...

我正在使用 相同 UUID 连接到两台设备(但一次只打开一个设备,它们从不会同时打开),来自 SDK API 的众所周知的 SPP UUID:

00001101-0000-1000-8000-00805F9B34FB

这让我想知道:难道我需要为每个设备使用不同的 UUID?如果是,有什么想法吗?

【问题讨论】:

【参考方案1】:

好的,经过几天尝试不同的解决方案,我现在可以在上述打印机之间切换。由于我不完全确定我的哪些措施是成功的原因,所以我将它们全部列出,所以偶然发现这篇文章的人会对如何解决他的蓝牙问题有一些线索。但是我很确定一件事:您不需要不同的 UUID 来连接两台不同的打印机 - 您可以使用相同的 UUID(但我只打开过其中一个)。

我缓存了上次打印到的设备 - 但与以前不同的是,我不再缓存实际的 BluetoothDevice,而是只缓存它的 mac 地址,可通过以下方式获得:

BluetoothDevice bluetoothDevice; 

//Obtain BluetoothDevice by looking through paired devices or starting discovery

bluetoothDevice.getAddress(); 

getAddress() 返回一个字符串:设备的硬件地址。我缓存了那个mac地址,下次用户想要打印时,我将缓存的mac地址与所有配对打印机的mac地址进行匹配——如果mac地址与其中一个匹配,我会尝试连接到该打印机。如果失败,我会重置我的缓存mac地址并尝试通过首先检查我的配对设备是否可以连接来找到另一个设备(如果我可以成功连接,我会相应地更新我的缓存mac地址),如果失败我开始一个寻找其他潜在设备的蓝牙发现。

现在,为了不让我的一台打印机打开任何套接字连接,我的例程如下(我将省略我在每个调用周围包裹的 try-catch 以方便阅读):

创建套接字

BluetoothSocket btSocket = btDevice.createRfcommSocketToServiceRecord(MY_UUID);

MY_UUID 指的是众所周知的用于连接 SPP 设备的 UUID:

00001101-0000-1000-8000-00805F9B34FB

如果socket creation 失败(这种情况很少见,如果发生这种情况很可能是由于权限不足或蓝牙被禁用/不可用),我们无法继续进行,因为我们需要一个套接字来连接。因此,在您的 catch 块中,您应该触发 disconnect 方法(稍后会详细介绍)。

连接到创建的套接字

bSocket.connect();

如果连接失败,我们将无法继续进行,因为我们需要一个有效的套接字连接来获取输入和输出流。因此,在您的 catch 块中,您应该触发 disconnect 方法(稍后会详细介绍)。

获取输入输出流

下一步是从套接字获取输入和输出流。我在一个 for 循环中执行此操作,该循环运行了几次(5 次就足够了) - 在每次迭代中,我检查是否有输出流,如果没有,我尝试获取它,与输入流相同。在循环结束时,我检查我是否有两个流,如果是,我退出循环(以及整个连接方法),如果没有,我继续循环并重试。通常我会在第一次循环迭代中获得两个流,但有时我需要两到三个迭代才能获得两个流。

如果我到达循环声明之后的代码,我显然没有得到我的流或其他错误。此时连接被认为失败了,我执行了我的断开代码(它会清理打开的流和套接字,稍后会详细介绍)。

读/写

现在您已连接到目标蓝牙设备,您可以执行读取和写入操作。完成后,您应该通过关闭所有流和套接字来进行清理,下一段将详细介绍:断开连接。请记住:如果在读/写操作期间发生异常,请务必触发断开连接方法以清理您的资源。如果您的打印机需要某种初始化命令,请务必在连接到打印机之后并在执行读/写操作之前立即发送该命令。

断开连接

通常有两种情况应该断开连接:

完成读/写操作后 如果在途中某处发生异常,清理您的资源

关闭您的信息流

你要做的第一件事是清理你的流,检查你的输入和输出流,如果它们不为空,关闭它们并将它们设置为空。确保将每个操作(关闭输入流、关闭输出流等)包装到自己的 try-catch 中,否则无法进行一次清理(因为引发异常)将跳过所有其他清理措施。

关闭套接字

现在您已确保清理了输入流,请继续关闭您的套接字连接,然后将其设置为 null。

还有一件事:我在断开连接方法的开头和结尾都有一个 Thread.sleep。一开始的时间大约为 2.5 秒(= 2500 毫秒),目的是确保打印机没有其他任何事情发生(例如挂起的读/写操作或打印机仍在打印等)。第二个 Thread.sleep 在我的断开方法结束时,大约 800 毫秒长。最后睡眠的原因与我在关闭一个套接字后立即尝试打开一个新套接字时遇到的问题有关。更多详情请参考this answer。

有问题吗?

如果有人对我的 OP 或我的回答有任何疑问,请在 cmets 中告诉我,我会尽力回答。

【讨论】:

请检查一下question好吗? :D @Skizo 我做了,听起来这里的答案正是你需要的?如果这对您不起作用,请告诉我问题所在。 我正在使用此代码,它或多或少是Android文档repo的示例,但它仍然说它没有连接 @Skizo:链接失效 xD。您是否尝试阅读此处提供的答案并相应地调整您的代码?另外 - 你检查过日志文件吗?请务必注意异常/原因,说明它为什么不起作用。

以上是关于Android:在 SPP 蓝牙设备之间切换的主要内容,如果未能解决你的问题,请参考以下文章

无线通信 - 由于Android应用开发蓝牙〜SPP

android开发SPP经典蓝牙

蓝牙spp协议分析

带有 Galaxy S3 的 Android 蓝牙 SPP

Android studio蓝牙app的串口是啥

SPP配置文件蓝牙iOS