2

2 つの異なる Bluetooth プリンターがあります。Bixolon SPP-R200 と富士通 FTP-628WSL110。それぞれに個別に接続して(Samsung Galaxy SIIを使用)、印刷、切断、再接続を問題なく行うことができます。ただし、Bixolon の電源を切って富士通とペアリングしようとすると (以前はペアリングされていませんでしたが、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 を使用しています (ただし、一度に 1 つのデバイスのみがオンになり、同時にオンになることはありません)、よく知られている SDK API の SPP UUID:

00001101-0000-1000-8000-00805F9B34FB

これは私が疑問に思うことです: デバイスごとに異なる UUID が必要なのでしょうか? はいの場合、どの考えですか?

4

1 に答える 1

10

さまざまなソリューションを数日間試した後、前述のプリンターを切り替えることができるようになりました。私の対策のどれが成功の理由だったのか完全にはわからないので、それらをすべてリストします. ただし、私が確信していることの1つは、2つの異なるプリンターを接続するために異なるUUIDは必要ありません.同じUUIDを使用できます(ただし、そのうちの1つだけをオンにしたことがあります)。

最後に出力されたデバイスをキャッシュします - ただし、以前とは異なり、実際のBluetoothDeviceをキャッシュしなくなり、代わりに次の方法で取得できる MAC アドレスのみをキャッシュします。

BluetoothDevice bluetoothDevice; 

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

bluetoothDevice.getAddress(); 

getAddress()は文字列を返します: デバイスのハードウェア アドレス。その MAC アドレスをキャッシュし、次にユーザーが印刷したいときに、キャッシュされた MAC アドレスをペアリングされたすべてのプリンターの MAC アドレスと照合します。MAC アドレスがこれらのいずれかに一致する場合、そのプリンターに接続しようとします。それが失敗した場合は、キャッシュされた mac アドレスをリセットし、ペアリングされたデバイスのいずれかが接続できるかどうかを最初に確認して別のデバイスを見つけようとします (接続に成功した場合は、それに応じてキャッシュされた mac アドレスを更新します)。他の潜在的なデバイスを探している bluetooth の検出。

プリンターの 1 つにソケット接続を開いたままにしないために、私のルーチンは次のとおりです (読み取りを容易にするために、各呼び出しをラップした try-catch を省略します)。

ソケットを作成する

BluetoothSocket btSocket = btDevice.createRfcommSocketToServiceRecord(MY_UUID);

MY_UUID は、SPP デバイスへの接続に使用される既知の UUID を参照します。

00001101-0000-1000-8000-00805F9B34FB

ソケットの作成に失敗した場合 (これはまれなケースです。発生する場合は、アクセス許可が不十分であるか、Bluetooth が無効になっている/利用できないことが原因である可能性が最も高い)、接続先のソケットが必要なため、先に進むことはできません。したがって、catch ブロックで disconnect メソッドをトリガーする必要があります (詳細は後述)。

作成したソケットに接続

bSocket.connect();

接続が失敗した場合、入力ストリームと出力ストリームを取得するには有効なソケット接続が必要なため、先に進むことはできません。したがって、catch ブロックで disconnect メソッドをトリガーする必要があります (詳細は後述)。

入力ストリームと出力ストリームを取得する

次のステップは、ソケットから入力ストリームと出力ストリームを取得することです。数回実行される for ループでこれを行います (5 回で十分です)。反復ごとに、出力ストリームがあるかどうかを確認し、そうでない場合は、入力ストリームと同じように取得しようとします。ループの最後で、両方のストリームがあるかどうかを確認し、ある場合はループを終了し (および接続メソッド全体)、ない場合はループを続行して再試行します。通常、最初のループ反復で両方のストリームを取得しますが、両方のストリームを取得するために 2 回または 3 回の反復が必要になる場合があります。

ループ宣言の後に続くコードに到達すると、明らかにストリームを取得できなかったか、何か問題が発生しました。この時点で、接続は失敗したと見なされ、切断コードを実行します (これにより、開いているストリームとソケットがクリーンアップされます。これについては後で詳しく説明します)。

読み書き

ターゲットの Bluetooth デバイスへの接続が確立されたので、読み取りおよび書き込み操作を実行できます。完了したら、すべてのストリームとソケットを閉じてクリーンアップする必要があります。これについては、次の段落で詳しく説明します: 切断. 注意: 読み取り/書き込み操作中に例外が発生した場合は、リソースをクリーンアップするために必ず切断メソッドをトリガーしてください。プリンターに何らかの初期化コマンドが必要な場合は、プリンターに接続した直後、読み取り/書き込み操作を実行する前に送信してください。

切断中

通常、切断する必要があるのは次の 2 つの場合です。

  • 読み取り/書き込み操作が完了したら
  • 途中で例外が発生した場合は、リソースをクリーンアップするために

ストリームを閉じる

最初に行うことは、ストリームをクリーンアップし、入力ストリームと出力ストリームの両方をチェックし、null でない場合はそれらを閉じて null に設定することです。各操作 (入力ストリームを閉じる、出力ストリームを閉じるなど) を必ず独自の try-catch にラップしてください。そうしないと、(例外が発生するため) 1 つのクリーンアップを実行できないと、他のすべてのクリーンアップ手段がスキップされます。

ソケットを閉じる

入力ストリームがクリーンアップされたことを確認したら、ソケット接続を閉じてから null に設定します。

もう 1 つ: 切断メソッドの最初と最後に Thread.sleep があります。最初のものは約 2.5 秒 (= 2500 ミリ秒) の長さで、その目的は、プリンターで他に何も起こっていないことを確認することです (保留中の読み取り/書き込み操作やプリンターがまだ印刷中など)。2 番目の Thread.sleep は、切断メソッドの最後にあり、長さは約 800 ミリ秒です。最後のスリープの理由は、新しいソケットを閉じた直後に新しいソケットを開こうとしたときに発生した問題に関連しています。詳細については、この回答を参照してください。

質問?

私の OP または私の回答に関連する質問がある場合は、コメントでお知らせください。回答できるよう最善を尽くします。

于 2012-07-06T08:20:57.703 に答える