简体   繁体   English

Android - 连接到多个蓝牙设备而无需配对

[英]Android - connecting to multiple bluetooth devices without pairing

I have a bunch of devices that are non-discoverable but I know the MAC addresses for them. 我有一堆不可发现的设备,但我知道它们的MAC地址。 At present I can connect to multiple devices using this in my ConnectThread: 目前我可以在ConnectThread中使用它连接到多个设备:

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

tmp = (BluetoothSocket) m.invoke(device, 1);

Problem being that I want to support insecure RFCOMM for devices previous to 2.3. 问题是我想为2.3之前的设备支持不安全的RFCOMM。 I then found this on another answer which lets me do this instead: 然后我在另一个答案中找到了这个 ,让我这样做:

tmp = InsecureBluetooth.createRfcommSocketToServiceRecord(device,MY_UUID, true);

Which works perfectly in connecting to a single device without the need for pairing. 无需配对即可完美连接单个设备。

My question is how can I get the best of both worlds and use reflection on the InsecureBluetooth class as well? 我的问题是我如何才能充分利用这两个世界并在InsecureBluetooth类上使用反射? Or does it need to be done within the InsecureBluetooth class and if so how? 或者它是否需要在InsecureBluetooth类中完成,如果是这样的话? Here is the relevant part of the InsecureBluetooth class: 以下是InsecureBluetooth类的相关部分:

private static BluetoothSocket createRfcommSocketToServiceRecord(
        BluetoothDevice device, int port, UUID uuid, boolean encrypt)
        throws IOException {
    try {
        BluetoothSocket socket = null;
        Constructor<BluetoothSocket> constructor = BluetoothSocket.class
                .getDeclaredConstructor(int.class, int.class, boolean.class,
                        boolean.class, BluetoothDevice.class, int.class, ParcelUuid.class);
        if (constructor == null)
            throw new RuntimeException("can't find the constructor for socket");

        constructor.setAccessible(true);
        Field f_rfcomm_type = BluetoothSocket.class
                .getDeclaredField("TYPE_RFCOMM");
        f_rfcomm_type.setAccessible(true);
        int rfcomm_type = (Integer) f_rfcomm_type.get(null);
        socket = constructor.newInstance(new Object[] { rfcomm_type, -1, false,
                true, device, port, uuid != null ? new ParcelUuid(uuid) : null });
        return socket;
    } catch (NoSuchMethodException e) {
        throw new RuntimeException(e);
    } catch (NoSuchFieldException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    } catch (InstantiationException e) {
        throw new RuntimeException(e);
    } catch (InvocationTargetException e) {
        if (e.getCause() instanceof IOException) {
            throw (IOException) e.getCause();
        }
        throw new RuntimeException(e.getCause());
    }
}

public static BluetoothSocket createRfcommSocketToServiceRecord(
        BluetoothDevice device, UUID uuid, boolean encrypt) throws IOException {
    return createRfcommSocketToServiceRecord(device, -1, uuid, encrypt);
}

public static BluetoothSocket createRfcommSocket(BluetoothDevice device,
        int port, boolean encrypt) throws IOException {
    return createRfcommSocketToServiceRecord(device, port, null, encrypt);
}

You may use the following class to create unsecure bluetooth socket connection. 您可以使用以下类创建不安全的蓝牙套接字连接。 It automatically handles reflections to offer this feature for SDK below 2.3.3 它会自动处理反射,为2.3.3以下的SDK提供此功能

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.util.Log;

/**
 * Class to offer unsecure bluetooth socket connection.<br />
 * It was intended to be used when building the app with API version below 10 (API < Android2.3.3)
 * @author waa
 *
 */
@SuppressWarnings("all")
public class UnpairedBluetooth {
    static private class InUse extends RuntimeException {
    }

    public static BluetoothServerSocket listenUsingRfcommWithServiceRecord(BluetoothAdapter adapter, String name, UUID uuid, boolean encrypt) throws IOException {
        try {
            Class c_rfcomm_channel_picker = null;
            Class[] children = BluetoothAdapter.class.getDeclaredClasses();
            for(Class c : children) {
                Log.e("TO", "class " + c.getCanonicalName());
                if(c.getCanonicalName().equals(BluetoothAdapter.class.getName() + ".RfcommChannelPicker")) {
                    c_rfcomm_channel_picker = c;
                    break;
                }
            }
            if(c_rfcomm_channel_picker == null)
                throw new RuntimeException("can't find the rfcomm channel picker class");

            Constructor constructor = c_rfcomm_channel_picker.getDeclaredConstructor(UUID.class);
            if(constructor == null)
                throw new RuntimeException("can't find the constructor for rfcomm channel picker");
            Object rfcomm_channel_picker = constructor.newInstance(new Object[] {uuid});
            Method m_next_channel = c_rfcomm_channel_picker.getDeclaredMethod("nextChannel", new Class[] {});
            m_next_channel.setAccessible(true);

            BluetoothServerSocket socket = null;

            int channel;
            int errno;
            while (true) {
                channel = (Integer)m_next_channel.invoke(rfcomm_channel_picker, new Object[] {});

                if (channel == -1) {
                    throw new IOException("No available channels");
                }

                try {
                    socket = listenUsingRfcomm(channel, encrypt);
                    break;
                } catch(InUse e) {
                    continue;
                }
            }

            Field f_internal_service = adapter.getClass().getDeclaredField("mService");
            f_internal_service.setAccessible(true);
            Object internal_service = f_internal_service.get(adapter);

            Method m_add_rfcomm_service_record = internal_service.getClass().getDeclaredMethod("addRfcommServiceRecord", new Class[] {String.class, ParcelUuid.class, int.class, IBinder.class});
            m_add_rfcomm_service_record.setAccessible(true);

            int handle = (Integer)m_add_rfcomm_service_record.invoke(internal_service, new Object[] { name, new ParcelUuid(uuid), channel, new Binder() } );

            if (handle == -1) {
                try {
                    socket.close();
                } catch (IOException e) {}
                throw new IOException("Not able to register SDP record for " + name);
            }
            Field f_internal_handler = adapter.getClass().getDeclaredField("mHandler");
            f_internal_handler.setAccessible(true);
            Object internal_handler = f_internal_handler.get(adapter);

            Method m_set_close_handler = socket.getClass().getDeclaredMethod("setCloseHandler", new Class[] {Handler.class, int.class});
            m_set_close_handler.setAccessible(true);

            m_set_close_handler.invoke(socket, new Object[] { internal_handler, handle});
            return socket;
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch(IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch(InstantiationException e) {
            throw new RuntimeException(e);
        } catch(InvocationTargetException e) {
            if(e.getCause() instanceof IOException) {
                throw (IOException)e.getCause();
            }
            throw new RuntimeException(e.getCause());
        }   
    }
    private static BluetoothServerSocket listenUsingRfcomm(/*BluetoothAdapter adapter, */ int port, boolean encrypt, boolean reuse) throws IOException, InUse {
        BluetoothServerSocket socket = null;
        try {
            Constructor<BluetoothServerSocket> constructor = BluetoothServerSocket.class.getDeclaredConstructor(int.class, boolean.class, boolean.class, int.class);
            if(constructor == null)
                throw new RuntimeException("can't find the constructor");
            constructor.setAccessible(true);
            Field f_rfcomm_type = BluetoothSocket.class.getDeclaredField("TYPE_RFCOMM");
            f_rfcomm_type.setAccessible(true);
            int rfcomm_type = (Integer)f_rfcomm_type.get(null);

            Field f_e_addr_in_use = BluetoothSocket.class.getDeclaredField("EADDRINUSE");
            f_e_addr_in_use.setAccessible(true);
            int e_addr_in_use = (Integer)f_e_addr_in_use.get(null);

            socket = constructor.newInstance(new Object[] { rfcomm_type, false, encrypt, port } );

            Field f_internal_socket = socket.getClass().getDeclaredField("mSocket");
            f_internal_socket.setAccessible(true);
            Object internal_socket = f_internal_socket.get(socket);
            Method m_bind_listen = internal_socket.getClass().getDeclaredMethod("bindListen", new Class[] {});
            m_bind_listen.setAccessible(true);
            Object result = m_bind_listen.invoke(internal_socket, new Object[] {});

            int errno = (Integer)result;
            if(reuse && errno == e_addr_in_use) {
                throw new InUse();
            } else if (errno != 0) {
                try {
                    socket.close();
                } catch (IOException e) {}
                internal_socket.getClass().getMethod("throwErrnoNative", new Class[] {int.class}).invoke(internal_socket, new Object[] { errno });
            }
            return socket;
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch(IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch(InstantiationException e) {
            throw new RuntimeException(e);
        } catch(InvocationTargetException e) {
            if(e.getCause() instanceof IOException) {
                throw (IOException)e.getCause();
            }
            throw new RuntimeException(e.getCause());
        }
    }
    public static BluetoothServerSocket listenUsingRfcomm(int port, boolean encrypt) throws IOException {
        return listenUsingRfcomm(port, encrypt, false);
    }
    private static BluetoothSocket createRfcommSocketToServiceRecord(BluetoothDevice device, int port, UUID uuid, boolean encrypt) throws IOException {
        try {
            BluetoothSocket socket = null;
            Constructor<BluetoothSocket> constructor = BluetoothSocket.class.getDeclaredConstructor(
                    int.class, int.class, boolean.class, boolean.class, BluetoothDevice.class, int.class, ParcelUuid.class);
            if(constructor == null)
                throw new RuntimeException("can't find the constructor for socket");

            constructor.setAccessible(true);
            Field f_rfcomm_type = BluetoothSocket.class.getDeclaredField("TYPE_RFCOMM");
            f_rfcomm_type.setAccessible(true);
            int rfcomm_type = (Integer)f_rfcomm_type.get(null);
//          socket = constructor.newInstance(new Object[] { rfcomm_type, -1, false, true, device, port, uuid != null ? new ParcelUuid(uuid) : null} );
            socket = constructor.newInstance(new Object[] { rfcomm_type, -1, false, encrypt, device, port, uuid != null ? new ParcelUuid(uuid) : null} );
            return socket;
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch(IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch(InstantiationException e) {
            throw new RuntimeException(e);
        } catch(InvocationTargetException e) {
            if(e.getCause() instanceof IOException) {
                throw (IOException)e.getCause();
            }
            throw new RuntimeException(e.getCause());
        }
    }
    public static BluetoothSocket createRfcommSocketToServiceRecord(BluetoothDevice device, UUID uuid, boolean encrypt) throws IOException{
        return createRfcommSocketToServiceRecord(device, -1, uuid, encrypt);
    }
    public static BluetoothSocket createRfcommSocket(BluetoothDevice device, int port, boolean encrypt) throws IOException {
        return createRfcommSocketToServiceRecord(device, port, null, encrypt);
    }
}

For more info, refer to this link. 有关详细信息,请参阅链接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM