私はブルートゥースを介してプリンタに接続する必要があるプロジェクトで作業しています。プリンタの製造元は、SPP(シリアルポートプロファイル)を持つアンドロイド携帯電話のみがプリンタに接続できると述べています。プロダクションコードでBluetooth反射ハックを残すべきですか?
これは私が最初に接続を開いた方法である:UUIDを使用して
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //SPP long UUID
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuid);
はJellyBeanのようアンドロイドパブリックAPIを使用してRFCOMM接続を開くための唯一の方法です。以前はUUIDが不要なBlackBerryとJavaMEのSPP接続で作業していましたが、これはちょっと奇妙です。 UUIDはサービス発見、つまりSDPを使用してデバイスに存在するサービスについて問い合わせることに関するものです。プリンタを事前にペア設定しているため、SPPをサポートしていることが分かっているため、実際に検出を開始する必要はありません。しかし、それはちょうどBluetoothDevice.createRfcommSocketToServiceRecord
メソッドと安全でないバージョンが行うことです。これは、我々がSDPは、同じ層で異なるプロトコルがどのように見ることができるSPPスタックであり、したがって、最初の発見を開始せずにRFCOMMを使用することが可能でなければなりません:私は私のアプリのテストを開始した
-----------------------------------
| My Application |
-----------------------------------
| Serial Port Emulation |
| or other API |
-----------------------------------
| RFCOMM | SDP |
-----------------------------------
| LMP | L2PCAP |
-----------------------------------
| Baseband |
-----------------------------------
問題のない古いHTCデバイスはほとんどありません。後で、サムスンの携帯電話でテストすると、いくつかのデバイスが接続を開くことができませんでした。
これらの電話機は、製造元とサードパーティの仕様である
(EDIT:サードパーティの仕様一覧でサポートされているSPP、製造元の仕様は十分に正確ではない)に従ってSPPプロファイルをサポートしていないと言われています。 IOExceptionが(サービス探索が失敗した)スローされた、と私はこの質問に示したアプローチに従った:
Service discovery failed exception using Bluetooth on Android
ソリューションは、以下のように、反射ハックを使用することがあります提案:
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
BluetoothSocket socket = socket = (BluetoothSocket) m.invoke(device, 1);
ハックは私のために働いた。驚いたことに、BluetoothDevice
クラスのこのメソッドはpublicですが、@hideアノテーションによってAPIから削除されています。これはJellyBeanのソースコードです:
/**
* Create an RFCOMM {@link BluetoothSocket} ready to start a secure
* outgoing connection to this remote device on given channel.
* <p>The remote device will be authenticated and communication on this
* socket will be encrypted.
* <p> Use this socket only if an authenticated socket link is possible.
* Authentication refers to the authentication of the link key to
* prevent man-in-the-middle type of attacks.
* For example, for Bluetooth 2.1 devices, if any of the devices does not
* have an input and output capability or just has the ability to
* display a numeric key, a secure socket connection is not possible.
* In such a case, use {#link createInsecureRfcommSocket}.
* For more details, refer to the Security Model section 5.2 (vol 3) of
* Bluetooth Core Specification version 2.1 + EDR.
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
* connection.
* <p>Valid RFCOMM channels are in range 1 to 30.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param channel RFCOMM channel to connect to
* @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
* @throws IOException on error, for example Bluetooth not available, or
* insufficient permissions
* @hide
*/
public BluetoothSocket createRfcommSocket(int channel) throws IOException {
return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
null);
}
このようにしてAPIからパブリックメソッドが削除された理由を理解できません。より多くの私は両方がRFCOMM接続を開くことに気づいソースのビットを掘る
public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
new ParcelUuid(uuid));
}
、:しかし、このアパートをさせる、この方法およびUUIDを使用して、公式にサポートされている1の両方が薄い異なるパラメータで同じBluetoothSocket
コンストラクタを呼び出す封筒がありますUUIDメソッドは検出を開始し、隠しメソッドは開始しません。
すべての反射ハッキングは、OS 2.2から4.1にテストしたすべてのデバイスで完璧に機能します。 EDIT:「欠陥のある」デバイスはSPPをサポートしていますが、BTスタックのカスタム実装が検出プロセスを台無しにしているだけです。 ICSの既にペアになっているデバイスのペア設定ダイアログを表示しているようなバグもあります。リフレクションを使用してこの非表示のAPIを呼び出すと、これらのすべてのバグや異なるメーカーの異なる動作が回避される可能性があります。
プロダクションコードをハックする必要がありますか?パブリックAPIで同じことを達成する方法はありますか?
ありがとうございます。
「警告なしでいつでもGoogleを変更できますが、デバイスメーカーは「警告なしでいつでも変更できます」。特定のAndroid搭載端末でこの方法が存在するか、動作するという保証はありません。 – CommonsWare