我要离开蓝牙反射破解生产code?我要、蓝牙、反射、code

2023-09-04 08:40:48 作者:讨厌朕的人多了你算老几

我工作在一个项目中,我需要通过蓝牙连接到打印机。打印机制造商指出,有SPP(串行端口配置文件)只Android手机都将能够与打印机连接。

I'm working in a project where I need to connect via bluetooth to a printer. The printer manufacturer states that only android phones having SPP (Serial Port Profile) are going to be able to connect with the printer.

这是我最初是如何打开的连接:

This is how I opened the connection initially:

        UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //SPP long UUID
        BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuid);

使用UUID是一款采用Android的公共API作为软糖的打开RFCOMM连接的唯一方法。与SPP连接的黑莓和JavaME的,如果不要求的UUID之前工作过,我发现这是一个有点奇怪。的UUID约为服务发现,即,使用SDP来查询的服务质量present在设备中。我并不真的需要启动发现,因为我有我的打印机配对提前,而且我知道它支持SPP。然而这正是 BluetoothDevice.createRfcommSocketToServiceRecord 方法和不安全的版本做。这是对SPP堆栈,我们可以看出如何SDP是一个不同的协议在同一层,因此它应该是可能使用的RFCOMM没有首先启动一个发现:

Using UUIDs is the only way to open RFCOMM connections using Android public API as of JellyBean. Having worked before with SPP connections in BlackBerry and JavaME, where UUIDs are not required, I found this a bit odd. UUIDs are about service discovery, that is, using SDP to query about the services present in the device. I don't really need to initiate a discovery, since I have my printer paired in advance, and I know it supports SPP. However that is exactly what the BluetoothDevice.createRfcommSocketToServiceRecord method and the insecure version do. This is the SPP stack, where we can see how SDP is a different protocol at the same layer, and thus it should be possible to use RFCOMM without initiating a discovery first:

        -----------------------------------
        |        My Application           |
        ----------------------------------- 
        |     Serial Port Emulation       |
        |          or other API           |
        -----------------------------------
        |      RFCOMM          |    SDP   |
        -----------------------------------
        |  LMP   |   L2PCAP               |
        -----------------------------------
        |           Baseband              |
        -----------------------------------

我一开始没有问题测试在几个老HTC设备我的应用程序。后来,在测试三星手机,几台设备无法打开连接。 这些手机据说不支持SPP配置文件,根据制造商和第三方规格(编辑:第三方规格列表SPP的支持,和制造商的规格是不够准确的)。一个IOException异常(服务发现失败)被扔了,我跟着这个问题显示的方式:

I started testing my app in a few old HTC devices without problems. Later, testing on Samsung phones, several devices were unable to open a connection. These phones allegedly do not support SPP profile, according to both manufacturer and 3rd party specs( 3rd party specs list SPP as supported, and the manufacturer specs are not accurate enough). An IOException (Service Discovery failed) was thrown, and I followed the approach shown in this question:

服务发现失败使用蓝牙在Android 异常

解决方法建议有使用反射破解,如下:

The solution proposed there is to use a reflection hack, as follows:

        Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
        BluetoothSocket socket = socket = (BluetoothSocket) m.invoke(device, 1);

该黑客为我工作。令人惊讶的是,这种方法在 BluetoothDevice类类是公共的,但它是从该API由@hide注释的手段除去。这是源$ C ​​$ C作为软糖的:

The hack worked for me. Amazingly, this method in BluetoothDevice class is public, but it is removed from the API by means of the @hide annotation. This is the source code as of 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中删除。但是,让这家Appart,这两种方法和官方支持的一个使用UUID薄信封调用同一个的BluetoothSocket 构造函数使用不同的参数:

I can't understand why a public method is removed from the API in this manner. But letting this appart, both this method and the officially supported one using UUIDs are thin envelopes calling the same BluetoothSocket constructor with different parameters:

        public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
            return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
                    new ParcelUuid(uuid));
        }

挖掘更多,我意识到,无论打开一个RFCOMM连接来源位,但UUID方法启动一个发现和隐藏的人们不。

Digging a bit more in the sources I realized that both open a RFCOMM connection, but the UUID method initiates a discovery and the hidden one not.

总而言之,反射黑客在每一个设备,我测试过,从OS 2.2至4.1工作得很好。 编辑:故障的设备都支持SPP,这只是他们的自定义实现BT栈的是搞乱了发现过程;也有其他类似的错误在ICS已经配对设备的一个表现配对对话框。调用使用反射这个隐藏API使一个解决方法,所有这些错误或不同的行为由不同的厂家的。

All in all, the reflection hacks work flawlessly in every device I've tested it, from OS 2.2 to 4.1. The "faulty" devices do support SPP, it is just that their custom implementation of BT stack is messing up with the discovery process; there are also other bugs like the the one showing pairing dialog for already paired devices in ICS. Calling this hidden API using reflection enables a workaround to all these bugs or different behaviour introduced by the different manufacturers.

我应该保持生产code中的黑客?有没有一种方法来达到同样的公共API?

在此先感谢。

推荐答案

精湛的问题。基本上,你可以使用反射所有你想要的。连我自己也做了类似序计算应用程序启动时间的东西,得到通过反射的方法和它的工作就像从升级Froyo魅力,直到果冻豆。谨慎的你需要锻炼的唯一的一句话是这样的,

Superb question. Basically you can use reflection all you want. Even i did something similar inorder to calculate the application launch times, got a method via reflection and its working like a charm from FroYo till Jelly Bean. The only word of caution you need to exercise is this,

因为它不是一个公共API,谷歌可以随时改变它没有警告 如果它发生变化时,系统使用它将会做相应的修改而不会影响到任何应用程序,应用程序或HAL。

会在哪里,你需要小心?

Where will you need to be careful?

可能这方法的参数可能会在将来修改。

Chances are the arguments of this method may get modified in the future.

所以,你需要检查这与每个新的操作系统版本,以便您的应用程序不中断。否则,你不必担心使用这个技巧。许多应用程序使用,例如黑客,当事情的arent暴露的API。

So you will need to check for this with each new OS release so that your application does not break. Otherwise you need not worry about using this hack. Many applications use such hacks when things arent exposed with the API.