1. ホーム
  2. android

[解決済み] デバイスを強制的に検出モードにすることなく、近くにあるすべてのBluetoothデバイス(ヘッドセット、電話など)を見つけることができます

2022-03-04 08:23:58

質問

私の目標は?

私のAndroidアプリケーションから、近くにあるすべてのBluetoothデバイス(電話、ヘッドセットなど)を検出すること。

以下はその例です。 デベロッパー.android.com は、ペアリング済みのデバイスのリストとともに、近くにあるBluetoothデバイスを検出します。

私の状況

2台のBluetoothヘッドセットの電源が入っていて、Bluetoothスキャンに成功した後に検出されませんでした そこで、この問題を調べてみたところ、Bluetoothヘッドセットをペアリングモードに切り替えると、アンドロイドに検出されることがわかりました。

ヘッドセットをペアリングモードに切り替えるには、電源を入れた状態で電源ボタンを長押しする必要がありました。そして、そう、ついに、私のアプリケーションからのスキャンでBluetoothヘッドセットが検出されるようになったのです。

私の問題点

ペアリングモードに切り替えなくても、ヘッドセットが自動的に検出されるようにしたい。電源が入っている近くのBluetoothデバイスをすべて検出する方法が見つかりませんでした。

解決方法を教えてください。

Android の bluetooth 検出に関して、ブログ、スレッド、ドキュメント、SO の回答などを読んで、私が見つけたすべてをここに記します。これは、私の発見をここに投稿するのに役立つかもしれないと思った。

そこで、誰かが読み始める前に、明らかにしておきたいことがあります。 電源は入っているが、検出できないBluetoothデバイスが近くにあることを検出する方法は見つかりませんでした。

近くにあるすべてのBluetoothデバイスを検出する

私の主なターゲットは、近くにあるすべてのブルートゥースデバイスを検出することです。そのために BluetoothAdapter クラスがあり、そのクラスは startDiscovery 関数を使って、近くにあるBluetoothデバイスをスキャンすることができます。なぜなら、AndroidによるBluetoothスキャンで検出されるためには、Bluetoothデバイスが検出可能である必要があるからです。私が欲しいのは、強制的に検出可能にすることなく、近くにあるすべてのBluetoothデバイスを検出することです。この目的を達成するために、私はソリューションを探し始めました。

まず勉強したのは Bluetoothプロトコル と、ブルートゥースの検出、接続、ペアリングに使用される基本的なプロトコルを発見しました。Android では、電源は入っているが検出可能な状態になっていない BT デバイスを検出するための API が見つかりませんでした。

クラス0x00のBluetoothデバイスは無視される

この検出の問題を、Bluetooth デバイスを強制的に検出可能なモードにすることなく掘り下げると、自らを「Second」と宣伝している Bluetooth デバイスを発見するポイントにたどり着きました。 class 0×00 は、近くのBTデバイスのスキャンを実行している間、自動的に無視されます。この問題については、いくつかの場所で述べられています。ここでは、そのいくつかを紹介します。

  1. スタックオーバーフローの質問
  2. Googleグループ
  3. ディスカッションDEV
  4. HTCデバイスで発見

この問題の回避策を探したところ、はい、見つけました。ただし、この回避策に付随する文書やレビューには、すべての種類のAndroidデバイスで動作するわけではない、と書かれています。とにかく、代替スキャンはデフォルトのBTスキャンと同じですが、いくつかの追加作業を行います。BT スキャンが成功した後、Android ログを読み、BT デバイスがスキップされていないかどうかを確認します。これは、以下のような簡単なハックです。 こちら . 同じ回避策について議論しているgoogleグループがあります。 こちら .

上記の回避策も私の問題を解決してくれません。Bluetoothヘッドセットは、BTスキャンで検出されるために、検出可能である必要があります。Android が近くの BT デバイスをスキャンしている間、ヘッドセットがスキップされることはありません。単に検出されないだけです。

Bluetoothページスキャン

しかし、再び解決策を探し始めたところ、また面白いものを発見しました これは、別の スタックオーバーフローの回答 というのがあります。 ブルートゥースデバイスが検出不可能なモードであっても、最初に完全なMACアドレスを知ることによって、そのデバイスが近くにあるかどうかを知ることが可能です。 . 今後の参考のため、彼の回答から再度引用します。

<ブロッククオート

テクニックとしては、PAGEリクエストを試して、シークしたBluetoothホストMAC識別子を構成する6バイトすべてを送信することです。PAGEリクエストは、BluetoothスレーブのBT ADDRを知ることで、そのスレーブとの接続を可能にします。発見不能モードのデバイスは、問い合わせスキャン(デバイス発見意図)には応答しませんが、以前から知られている別のデバイスに接続したいデバイスが使用するページスキャンには応答します。

希望が見えたので、Androidでページスキャンを開始するにはどうしたらいいか、検索し始めたのですが、今回も失敗しました。ページスキャンを開始するためのAPIのようなものは見つかりませんでした。Androidのドキュメントにある BluetoothAdapter クラスで、BTスキャンが開始されるとき、私はそれを知るようになりました。

通常、約12秒間の問い合わせスキャンが行われ、その後、新しいデバイスごとにBluetooth名を取得するためのページスキャンが行われます。

Androidのドキュメントにはページスキャンについての記載がありますが、意外にもページスキャンに関する他のドキュメントはどこにもありません。そこで スタックオーバーフローの質問 をご覧ください。

BTIDのリストを"already paired"のリストに追加することによって、androidを"fool"することができますか?

いいえ、そのような方法は見つかりませんでした。Androidのbluetoothペアリングの仕組みについて読みました。以下はその例です。 フロー図と詳しい説明書 . Androidの隠しAPIを使おうとしていたところ、Reflectionを使っていくつかの隠しAPIを使うことができました。そして、私の目的を果たすために使えそうな隠しAPIを探し始めたのです。しかし、残念ながら、Android のペアリング済みリストに BT デバイスをプログラム的に追加するための hidden API を見つけることができませんでした。

bluetoothのペアリング、隠しAPI、リフレクションによる呼び出し方法について確認するのに役立つリンクをいくつか紹介しますので、今後の参考にしてください。

  1. ペアリングの開始方法
  2. Androidの隠されたAPIを操作するためのリフレクションの使い方
  3. 私がフォローしたgoogleグループのディスカッションでは、私たちと同じ問題に直面している人たちがいます。

そこで、BTデバイスが検出可能モードで、Androidのペアリング済みリストにない場合、ペアリングすることができました。私の場合、ブルートゥースヘッドセットを使用しました。電源を入れ、発見可能な状態にしました。ヘッドセットのBTアドレス(MACアドレス)は分かっていました。そこで、私は関数を呼び出した createBond を私のコードからリフレクションを使って実行すると、完璧に動作しました。デバイスはAndroidの"already-paired"リストに正常に追加されました。私の目的を果たすためのソリューションを求めて歩き回っているうちに、面白いものを見つけました...。

ペアリング済みデバイスに関する興味深い観察

アンドロイドは、すでにペアリングされたデバイスを削除しても、そのデバイスをメモリ内に保持することがわかりました。この発見をより良く理解するために、事例を紹介しましょう。私の場合、ヘッドセットは以前にペアリングされていました。

  1. Androidからヘッドセットのペアリングを解除する/忘れる
  2. その後、ヘッドセットの電源をオフにした。
  3. その後、近くにあるBluetoothデバイスのスキャンを開始
  4. もちろん、ヘッドセットは見つかりませんでした
  5. しかし、Androidのログを調べたところ、Androidはそのヘッドセットのボンディング状態(パーリング状態)の変化を記憶していることがわかりました。
  6. 以前ボンディングされたヘッドホンをスキャンして、リモートデバイスがダウンしていることを報告しました。

以下は、以前ペアリングし、その後ペアリングを解除したヘッドセットのMACアドレスとともに出力されたログです。

PREV_BOND_STATE = 11 // BOND_BONDING    (BluetoothDevice.java)
BOND_STATE = 10      // BOND_NONE
REASON = 4           // UNBOND_REASON_REMOTE_DEVICE_DOWN

そしてまた、同じテストを実行しましたが、今度はブルートゥースヘッドセットをオンにしてみました(検出不可)。この場合もヘッドセットは発見されませんでしたが、興味深いことに、今回は別のログが出力されました。

PREV_BOND_STATE = 11 // BOND_BONDING    (BluetoothDevice.java)
BOND_STATE = 10      // BOND_NONE
REASON = 2           // UNBOND_REASON_AUTH_CANCELLED

REASON が変更されているため、Android が bluetooth ヘッドセットと接続しようとしたことが理解できます。ヘッドセットは検出可能なモードではありませんでしたが、Android はヘッドセットを検出し、以前ペアリング済みリストにあったヘッドセットと接続しようとしました。

を追加してブルートゥーススキャンを実行中にこのログが出力されました。 ACTION_BOND_STATE_CHANGED アクションに intent.addAction .

Androidをビーコンとして使用することはできますか?

しかし、その場合、AndroidもBLEであることを宣伝する必要があります。これはAndroidの新機能であり、これまですべてのデバイスがこの機能をサポートしていたわけではありません。以下はその例です。 デバイス一覧 Bluetooth LEアドバタイズメント機能をサポートする しかし、Bluetooth LEアドバタイズは非常に低消費電力で高性能なので、Androidの次の大きなトレンドになると思います。

今後の研究に役立つリンク集です。

ブルートゥース操作に便利な関数とライブラリ