IOException: error de lectura, el enchufe podría cerrarse - Bluetooth en Android 4.3

100

Actualmente estoy tratando de lidiar con una extraña Excepción al abrir un BluetoothSocket en mi Nexus 7 (2012), con Android 4.3 (Build JWR66Y, supongo que la segunda actualización 4.3). He visto algunas publicaciones relacionadas (por ejemplo, /programming/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), pero ninguna parece proporcionar una solución para este problema. Además, como se sugiere en estos hilos, volver a emparejar no ayuda, y tratar de conectarse constantemente (a través de un bucle estúpido) tampoco tiene ningún efecto.

Estoy tratando con un dispositivo integrado (un adaptador para automóvil OBD-II que no es de nombre, similar a http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- LUCES-CON-SU-TELÉFONO-Oceanside.jpg ). Mi teléfono Android 2.3.7 no tiene problemas para conectarse y el Xperia de un colega (Android 4.1.2) también funciona. Otro Google Nexus (no sé si 'One' o 'S', pero no '4') también falla con Android 4.3.

Aquí está el fragmento del establecimiento de la conexión. Se ejecuta en su propio subproceso, creado dentro de un servicio.

private class ConnectThread extends Thread {

    private static final UUID EMBEDDED_BOARD_SPP = UUID
        .fromString("00001101-0000-1000-8000-00805F9B34FB");

    private BluetoothAdapter adapter;
    private boolean secure;
    private BluetoothDevice device;
    private List<UUID> uuidCandidates;
    private int candidate;
    protected boolean started;

    public ConnectThread(BluetoothDevice device, boolean secure) {
        logger.info("initiliasing connection to device "+device.getName() +" / "+ device.getAddress());
        adapter = BluetoothAdapter.getDefaultAdapter();
        this.secure = secure;
        this.device = device;

        setName("BluetoothConnectThread");

        if (!startQueryingForUUIDs()) {
            this.uuidCandidates = Collections.singletonList(EMBEDDED_BOARD_SPP);
            this.start();
        } else{
            logger.info("Using UUID discovery mechanism.");
        }
        /*
         * it will start upon the broadcast receive otherwise
         */
    }

    private boolean startQueryingForUUIDs() {
        Class<?> cl = BluetoothDevice.class;

        Class<?>[] par = {};
        Method fetchUuidsWithSdpMethod;
        try {
            fetchUuidsWithSdpMethod = cl.getMethod("fetchUuidsWithSdp", par);
        } catch (NoSuchMethodException e) {
            logger.warn(e.getMessage());
            return false;
        }

        Object[] args = {};
        try {
            BroadcastReceiver receiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    BluetoothDevice deviceExtra = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
                    Parcelable[] uuidExtra = intent.getParcelableArrayExtra("android.bluetooth.device.extra.UUID");

                    uuidCandidates = new ArrayList<UUID>();
                    for (Parcelable uuid : uuidExtra) {
                        uuidCandidates.add(UUID.fromString(uuid.toString()));
                    }

                    synchronized (ConnectThread.this) {
                        if (!ConnectThread.this.started) {
                            ConnectThread.this.start();
                            ConnectThread.this.started = true;
                            unregisterReceiver(this);
                        }

                    }
                }

            };
            registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
            registerReceiver(receiver, new IntentFilter("android.bluetooth.device.action.UUID"));

            fetchUuidsWithSdpMethod.invoke(device, args);
        } catch (IllegalArgumentException e) {
            logger.warn(e.getMessage());
            return false;
        } catch (IllegalAccessException e) {
            logger.warn(e.getMessage());
            return false;
        } catch (InvocationTargetException e) {
            logger.warn(e.getMessage());
            return false;
        }           

        return true;
    }

    public void run() {
        boolean success = false;
        while (selectSocket()) {

            if (bluetoothSocket == null) {
                logger.warn("Socket is null! Cancelling!");
                deviceDisconnected();
                openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
            }

            // Always cancel discovery because it will slow down a connection
            adapter.cancelDiscovery();

            // Make a connection to the BluetoothSocket
            try {
                // This is a blocking call and will only return on a
                // successful connection or an exception
                bluetoothSocket.connect();
                success = true;
                break;

            } catch (IOException e) {
                // Close the socket
                try {
                    shutdownSocket();
                } catch (IOException e2) {
                    logger.warn(e2.getMessage(), e2);
                }
            }
        }

        if (success) {
            deviceConnected();
        } else {
            deviceDisconnected();
            openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
        }
    }

    private boolean selectSocket() {
        if (candidate >= uuidCandidates.size()) {
            return false;
        }

        BluetoothSocket tmp;
        UUID uuid = uuidCandidates.get(candidate++);
        logger.info("Attempting to connect to SDP "+ uuid);
        try {
            if (secure) {
                tmp = device.createRfcommSocketToServiceRecord(
                        uuid);
            } else {
                tmp = device.createInsecureRfcommSocketToServiceRecord(
                        uuid);
            }
            bluetoothSocket = tmp;
            return true;
        } catch (IOException e) {
            logger.warn(e.getMessage() ,e);
        }

        return false;
    }

}

El código falla en bluetoothSocket.connect(). Estoy obteniendo un java.io.IOException: read failed, socket might closed, read ret: -1. Esta es la fuente correspondiente en GitHub: https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504 Se llama a través de readInt (), llamado desde https : //github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319

Algunos volcados de metadatos del socket utilizado dieron como resultado la siguiente información. Son exactamente iguales en Nexus 7 y mi teléfono 2.3.7.

Bluetooth Device 'OBDII'
Address: 11:22:33:DD:EE:FF
Bond state: 12 (bonded)
Type: 1
Class major version: 7936
Class minor version: 7936
Class Contents: 0
Contents: 0

Tengo algunos otros adaptadores OBD-II (más expansivos) y todos funcionan. ¿Existe alguna posibilidad de que me esté perdiendo algo o podría tratarse de un error en Android?

mate
fuente
He intentado la solución anterior, puede sombody ayuda sobre este tema stackoverflow.com/q/52105647/1559331
dileepVikram

Respuestas:

129

Finalmente encontré una solución. La magia está oculta bajo el capó de la BluetoothDeviceclase (ver https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037 ).

Ahora, cuando recibo esa excepción, creo una instancia de respaldo BluetoothSocket, similar al código fuente a continuación. Como puede ver, invocando el método oculto a createRfcommSockettravés de reflejos. No tengo ni idea de por qué este método está oculto. El código fuente lo define como publicsi ...

Class<?> clazz = tmp.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE};

Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[] {Integer.valueOf(1)};

fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params);
fallbackSocket.connect();

connect()entonces ya no falla. Todavía he experimentado algunos problemas. Básicamente, esto a veces se bloquea y falla. Reiniciar el dispositivo SPP (desconectar / conectar) ayuda en tales casos. A veces también recibo otra solicitud de emparejamiento connect()incluso cuando el dispositivo ya está vinculado.

ACTUALIZAR:

aquí hay una clase completa, que contiene algunas clases anidadas. para una implementación real, estos podrían llevarse a cabo como clases separadas.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.List;
import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;

public class BluetoothConnector {

    private BluetoothSocketWrapper bluetoothSocket;
    private BluetoothDevice device;
    private boolean secure;
    private BluetoothAdapter adapter;
    private List<UUID> uuidCandidates;
    private int candidate;


    /**
     * @param device the device
     * @param secure if connection should be done via a secure socket
     * @param adapter the Android BT adapter
     * @param uuidCandidates a list of UUIDs. if null or empty, the Serial PP id is used
     */
    public BluetoothConnector(BluetoothDevice device, boolean secure, BluetoothAdapter adapter,
            List<UUID> uuidCandidates) {
        this.device = device;
        this.secure = secure;
        this.adapter = adapter;
        this.uuidCandidates = uuidCandidates;

        if (this.uuidCandidates == null || this.uuidCandidates.isEmpty()) {
            this.uuidCandidates = new ArrayList<UUID>();
            this.uuidCandidates.add(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
        }
    }

    public BluetoothSocketWrapper connect() throws IOException {
        boolean success = false;
        while (selectSocket()) {
            adapter.cancelDiscovery();

            try {
                bluetoothSocket.connect();
                success = true;
                break;
            } catch (IOException e) {
                //try the fallback
                try {
                    bluetoothSocket = new FallbackBluetoothSocket(bluetoothSocket.getUnderlyingSocket());
                    Thread.sleep(500);                  
                    bluetoothSocket.connect();
                    success = true;
                    break;  
                } catch (FallbackException e1) {
                    Log.w("BT", "Could not initialize FallbackBluetoothSocket classes.", e);
                } catch (InterruptedException e1) {
                    Log.w("BT", e1.getMessage(), e1);
                } catch (IOException e1) {
                    Log.w("BT", "Fallback failed. Cancelling.", e1);
                }
            }
        }

        if (!success) {
            throw new IOException("Could not connect to device: "+ device.getAddress());
        }

        return bluetoothSocket;
    }

    private boolean selectSocket() throws IOException {
        if (candidate >= uuidCandidates.size()) {
            return false;
        }

        BluetoothSocket tmp;
        UUID uuid = uuidCandidates.get(candidate++);

        Log.i("BT", "Attempting to connect to Protocol: "+ uuid);
        if (secure) {
            tmp = device.createRfcommSocketToServiceRecord(uuid);
        } else {
            tmp = device.createInsecureRfcommSocketToServiceRecord(uuid);
        }
        bluetoothSocket = new NativeBluetoothSocket(tmp);

        return true;
    }

    public static interface BluetoothSocketWrapper {

        InputStream getInputStream() throws IOException;

        OutputStream getOutputStream() throws IOException;

        String getRemoteDeviceName();

        void connect() throws IOException;

        String getRemoteDeviceAddress();

        void close() throws IOException;

        BluetoothSocket getUnderlyingSocket();

    }


    public static class NativeBluetoothSocket implements BluetoothSocketWrapper {

        private BluetoothSocket socket;

        public NativeBluetoothSocket(BluetoothSocket tmp) {
            this.socket = tmp;
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return socket.getInputStream();
        }

        @Override
        public OutputStream getOutputStream() throws IOException {
            return socket.getOutputStream();
        }

        @Override
        public String getRemoteDeviceName() {
            return socket.getRemoteDevice().getName();
        }

        @Override
        public void connect() throws IOException {
            socket.connect();
        }

        @Override
        public String getRemoteDeviceAddress() {
            return socket.getRemoteDevice().getAddress();
        }

        @Override
        public void close() throws IOException {
            socket.close();
        }

        @Override
        public BluetoothSocket getUnderlyingSocket() {
            return socket;
        }

    }

    public class FallbackBluetoothSocket extends NativeBluetoothSocket {

        private BluetoothSocket fallbackSocket;

        public FallbackBluetoothSocket(BluetoothSocket tmp) throws FallbackException {
            super(tmp);
            try
            {
              Class<?> clazz = tmp.getRemoteDevice().getClass();
              Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE};
              Method m = clazz.getMethod("createRfcommSocket", paramTypes);
              Object[] params = new Object[] {Integer.valueOf(1)};
              fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params);
            }
            catch (Exception e)
            {
                throw new FallbackException(e);
            }
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return fallbackSocket.getInputStream();
        }

        @Override
        public OutputStream getOutputStream() throws IOException {
            return fallbackSocket.getOutputStream();
        }


        @Override
        public void connect() throws IOException {
            fallbackSocket.connect();
        }


        @Override
        public void close() throws IOException {
            fallbackSocket.close();
        }

    }

    public static class FallbackException extends Exception {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        public FallbackException(Exception e) {
            super(e);
        }

    }
}
mate
fuente
3
¡Guauu! gran solucion!
Bobs
2
@MD No sé cómo. Lo probé y descubrí que funciona.
Bobs
1
No funciona en nexus 4. ¿Puede decirnos cómo solucionar este problema? Casi lo he probado todo. Gracias.
Shah
3
@matthes Lamento decirlo, pero incluso su solución de usar el respaldo no ha resuelto mi problema. Obteniendo debajo de Error. Fallback failed. Cancelling. java.io.IOException: Connection refused Por favor ayuda.
Tushar Banne
2
@matthes "SPP-Device (plug off / plug in) ayuda en tales casos". La declaración de encendido / apagado es la más subestimada del mundo. Perdí 3 horas y todo lo que tenía que hacer era encenderlo y apagarlo -_-
Adz
98

Bueno, tuve el mismo problema con mi código, y es porque desde Android 4.2 la pila bluetooth ha cambiado. así que mi código funcionaba bien en dispositivos con Android <4.2, en los otros dispositivos recibía la famosa excepción "falló la lectura, el socket podría cerrarse o se agotó el tiempo de espera, leer ret: -1"

El problema está en el socket.mPortparámetro. Cuando crea su socket usando socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);, mPortobtiene el valor entero " -1 ", y este valor parece no funcionar para android> = 4.2, por lo que debe establecerlo en " 1 ". La mala noticia es que createRfcommSocketToServiceRecordsolo acepta UUID como parámetro y no mPortpor eso tenemos que usar otro enfoque. La respuesta Publicado por @matthes también trabajó para mí, pero yo lo simplificó: socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);. Necesitamos usar ambos atributos de socket, el segundo como respaldo.

Entonces el código es (para conectarse a un SPP en un dispositivo ELM327):

BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();

    if (btAdapter.isEnabled()) {
        SharedPreferences prefs_btdev = getSharedPreferences("btdev", 0);
        String btdevaddr=prefs_btdev.getString("btdevaddr","?");

        if (btdevaddr != "?")
        {
            BluetoothDevice device = btAdapter.getRemoteDevice(btdevaddr);

            UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); // bluetooth serial port service
            //UUID SERIAL_UUID = device.getUuids()[0].getUuid(); //if you don't know the UUID of the bluetooth device service, you can get it like this from android cache

            BluetoothSocket socket = null;

            try {
                socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
            } catch (Exception e) {Log.e("","Error creating socket");}

            try {
                socket.connect();
                Log.e("","Connected");
            } catch (IOException e) {
                Log.e("",e.getMessage());
                try {
                    Log.e("","trying fallback...");

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

                    Log.e("","Connected");
                }
             catch (Exception e2) {
                 Log.e("", "Couldn't establish Bluetooth connection!");
              }
            }
        }
        else
        {
            Log.e("","BT device not selected");
        }
    }
George Dima
fuente
57
para los moderadores: ya que borraste mi respuesta anterior sin ningún motivo, la vuelvo a publicar.
George Dima
2
¡Gracias George por las ideas sobre el mPortparámetro! En mi humilde opinión, el flujo de trabajo sigue siendo el mismo, acabo de envolver las cosas con algunas clases que implementan una interfaz.
Matthes
5
sí, ya dije que su solución era buena, pero quería que la gente entienda por qué necesita usar este enfoque comenzando con Android 4.2
George Dima
2
SPP = Perfil de puerto serie (que emula un puerto serie a través de bluetooth) y ELM327 es un dispositivo de coche bluetooth <-> obd, búscalo en Google.
George Dima
10
Me funcionó después de cambiar el valor del puerto de 1 a 2, mire este código. socket = (BluetoothSocket) dispositivo.getClass (). getMethod ("createRfcommSocket", nueva clase [] {int.class}). invoke (dispositivo, 2); socket.connect ();
Dinesh IT
16

Primero, si necesita hablar con un dispositivo bluetooth 2.x, esta documentación establece que:

Sugerencia: si se está conectando a una placa serie Bluetooth, intente utilizar el conocido UUID SPP 00001101-0000-1000-8000-00805F9B34FB . Sin embargo, si se está conectando a un par de Android, genere su propio UUID único.

No pensé que funcionaría, pero solo reemplazando el UUID con 00001101-0000-1000-8000-00805F9B34FBél funciona. Sin embargo, este código parece manejar el problema de la versión del SDK, y puede reemplazar la función device.createRfcommSocketToServiceRecord(mMyUuid);con tmp = createBluetoothSocket(mmDevice);después de definir el siguiente método:

private BluetoothSocket createBluetoothSocket(BluetoothDevice device)
    throws IOException {
    if(Build.VERSION.SDK_INT >= 10){
        try {
            final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
            return (BluetoothSocket) m.invoke(device, mMyUuid);
        } catch (Exception e) {
            Log.e(TAG, "Could not create Insecure RFComm Connection",e);
        }
    }
    return  device.createRfcommSocketToServiceRecord(mMyUuid);
}

El código fuente no es mío, sino que proviene de este sitio web .

tobiasBora
fuente
1
Eso resolvió casi 2 días de trabajo ... suspiro de agradecimiento ... Sin este UUID el socket se cerraría inmediatamente y fallaría sin más explicación.
David Sinclair
muchas gracias por la ayuda MI UUID es alfanumérico y estoy tratando de conectar el HC-5 y mi bluetooth muestra que la conexión falla, pero cuando usé esta solución, mi problema se resolvió. gracias de nuevo
Nikhil Shende
8

Tuve los mismos síntomas que se describen aquí. Pude conectarme una vez a una impresora bluetooth, pero las conexiones posteriores fallaron con el "enchufe cerrado" sin importar lo que hice.

Me pareció un poco extraño que fueran necesarias las soluciones que se describen aquí. Después de revisar mi código, descubrí que había olvidado cerrar InputStream y OutputSteram del socket y no había terminado ConnectedThreads correctamente.

El ConnectedThread que uso es el mismo que en el ejemplo aquí:

http://developer.android.com/guide/topics/connectivity/bluetooth.html

Tenga en cuenta que ConnectThread y ConnectedThread son dos clases diferentes.

Cualquier clase que inicie ConnectedThread debe llamar a interrupt () y cancel () en el hilo. Agregué mmInStream.close () y mmOutStream.close () en el método ConnectedTread.cancel ().

Después de cerrar los subprocesos / flujos / sockets correctamente, pude crear nuevos sockets sin ningún problema.

Daniel T
fuente
Gracias, estaba teniendo el mismo problema, justo ahora pensé que no había cerrado la transmisión y la conexión ...
Rafael
probé todos los escenarios anteriores, (excepto para eliminar otros dispositivos emparejados, bien eso realmente no es una solución que sí ... esto normalmente solo sucede cuando los flujos de entrada y los enchufes no se cierran correctamente ... !!
Aman Satija
7

Bueno, de hecho encontré el problema.

La mayoría de las personas que intentan establecer una conexión con socket.Connect();obtienen una excepción llamadaJava.IO.IOException: read failed, socket might closed, read ret: -1 .

En algunos casos, también depende de su dispositivo Bluetooth, porque hay dos tipos diferentes de Bluetooth, a saber, BLE (baja energía) y Classic.

Si desea verificar el tipo de dispositivo Bluetooth que es, aquí está el código:

        String checkType;
        var listDevices = BluetoothAdapter.BondedDevices;
        if (listDevices.Count > 0)
        {
            foreach (var btDevice in listDevices)
            {
                if(btDevice.Name == "MOCUTE-032_B52-CA7E")
                {
                    checkType = btDevice.Type.ToString();
                    Console.WriteLine(checkType);
                }
            }
        }

Llevo días intentando solucionar el problema, pero desde hoy he encontrado el problema. La solución de @matthes lamentablemente todavía tiene algunos problemas como ya dijo, pero aquí está mi solución.

Actualmente trabajo en Xamarin Android, pero esto también debería funcionar para otras plataformas.

SOLUCIÓN

Si hay más de un dispositivo emparejado, debe eliminar los otros dispositivos emparejados. Así que conserve solo el que desea conectar (vea la imagen de la derecha).

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

En la imagen de la izquierda puede ver que tengo dos dispositivos emparejados, a saber, "MOCUTE-032_B52-CA7E" y "Blue Easy". Ese es el problema, pero no tengo idea de por qué ocurre ese problema. Quizás el protocolo Bluetooth esté intentando obtener información de otro dispositivo Bluetooth.

sin embargo, el socket.Connect(); funciona muy bien ahora mismo, sin ningún problema. Así que solo quería compartir esto, porque ese error es realmente molesto.

¡Buena suerte!

Jamie
fuente
Esto funcionó en el único dispositivo en el que me encuentro con este problema, que solo me ocurre en un teléfono 5.0, e incluso entonces solo cuando habilito BT por primera vez y luego abro una conexión. Si BT ya estaba encendido, ¡no hay problema de conexión! No ocurre en dispositivos con una versión posterior de Android, lo que sugiere que los desarrolladores notaron el error y lo solucionaron, pero la página de Android BT no dice una palabra al respecto. Pero tu solución funciona, ¡gracias!
John Perry
7

En las versiones más recientes de Android, recibía este error porque el adaptador todavía estaba descubriendo cuando intenté conectarme al enchufe. Aunque llamé al método cancelDiscovery en el adaptador Bluetooth, tuve que esperar hasta que se llamara a la devolución de llamada al método onReceive () de BroadcastReceiver con la acción BluetoothAdapter.ACTION_DISCOVERY_FINISHED.

Una vez que esperé a que el adaptador detuviera el descubrimiento, la llamada de conexión en el socket se realizó correctamente.

kmac.mcfarlane
fuente
6

Lo pones registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID")); con "bluetooth" deletreado "bleutooth".

Fizz Binn
fuente
4

En caso de que alguien tenga problemas con Kotlin, tuve que seguir la respuesta aceptada con algunas variaciones:

fun print(view: View, text: String) {
    var adapter = BluetoothAdapter.getDefaultAdapter();
    var pairedDevices = adapter.getBondedDevices()
    var uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
    if (pairedDevices.size > 0) {
        for (device in pairedDevices) {
            var s = device.name
            if (device.getName().equals(printerName, ignoreCase = true)) {
                Thread {
                    var socket = device.createInsecureRfcommSocketToServiceRecord(uuid)
                    var clazz = socket.remoteDevice.javaClass
                    var paramTypes = arrayOf<Class<*>>(Integer.TYPE)
                    var m = clazz.getMethod("createRfcommSocket", *paramTypes)
                    var fallbackSocket = m.invoke(socket.remoteDevice, Integer.valueOf(1)) as BluetoothSocket
                    try {
                        fallbackSocket.connect()
                        var stream = fallbackSocket.outputStream
                        stream.write(text.toByteArray(Charset.forName("UTF-8")))
                    } catch (e: Exception) {
                        e.printStackTrace()
                        Snackbar.make(view, "An error occurred", Snackbar.LENGTH_SHORT).show()
                    }
                }.start()
            }
        }
    }
}

Espero eso ayude

Santiago Martí Olbrich
fuente
3

Los dispositivos Bluetooth pueden funcionar en modo clásico y LE al mismo tiempo. A veces usan una dirección MAC diferente dependiendo de la forma en que se conecte. Vocaciónsocket.connect() se usa Bluetooth Classic, por lo que debe asegurarse de que el dispositivo que obtuvo cuando escaneó fuera realmente un dispositivo clásico.

Sin embargo, es fácil filtrar solo para dispositivos Classic:

if(BluetoothDevice.DEVICE_TYPE_LE == device.getType()){ //socket.connect() }

Sin esta verificación, es una condición de carrera si un escaneo híbrido le dará primero el dispositivo Classic o el dispositivo BLE. Puede parecer como una incapacidad intermitente para conectarse, o como ciertos dispositivos que pueden conectarse de manera confiable mientras que otros aparentemente nunca pueden hacerlo.

kmac.mcfarlane
fuente
1

También me enfrenté a este problema, podría resolverlo de 2 maneras, como se mencionó anteriormente, use la reflexión para crear el socket.La segunda es, el cliente está buscando un servidor con UUID dado y si su servidor no se ejecuta en paralelo al cliente, entonces esto sucede. Cree un servidor con el UUID de cliente dado y luego escuche y acepte el cliente desde el lado del servidor.

ireshika piyumalie
fuente
1

Me encontré con este problema y lo solucioné cerrando los flujos de entrada y salida antes de cerrar el socket. Ahora puedo desconectarme y conectarme de nuevo sin problemas.

https://stackoverflow.com/a/3039807/5688612

En Kotlin:

fun disconnect() {
    bluetoothSocket.inputStream.close()
    bluetoothSocket.outputStream.close()
    bluetoothSocket.close()
}
TheoKanning
fuente
1

Si otra parte de su código ya ha realizado una conexión con el mismo socket y UUID, obtiene este error.

usuario1725145
fuente
0

Incluso tuve el mismo problema, finalmente entendí mi problema, estaba tratando de conectarme desde el rango de cobertura de Bluetooth (fuera del alcance).

Krishnamurthy
fuente
0

Tuve este problema y la solución fue usar el GUID mágico especial.

            val id: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") // Any other GUID doesn't work.
            val device: BluetoothDevice = bta!!.bondedDevices.first { z -> z.name == deviceName }

            bts = device.createRfcommSocketToServiceRecord(id) // mPort is -1
            bts?.connect()
            // Start processing thread.

Sospecho que estos son los UUID que funcionan:

var did: Array<ParcelUuid?> = device.uuids

Sin embargo, no los he probado todos.

Richard Barraclough
fuente
Incluso estoy usando el mismo UUID. Pero no me ayudó. ¿Esto solo es compatible con la conexión a dispositivos bluetooth clásicos (no BLE)? Qué tengo que hacer para conectarme a dispositivos BLE usando Xamarin.Forms. Publicado aquí [ stackoverflow.com/questions/62371859/…
Shailesh Bhat
Estoy usando Bluetooth clásico; BLE es una basura.
Richard Barraclough
-1

Al agregar una acción de filtro, mi problema se resolvió

 // Register for broadcasts when a device is discovered
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
    intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
    intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    registerReceiver(mReceiver, intentFilter);
Vinod Ranga
fuente
-3

También he recibido lo mismo IOException, pero encuentro la demostración del sistema Android: el proyecto "BluetoothChat" está funcionando. Determiné que el problema es el UUID.

Así reemplazo mi UUID.fromString("00001001-0000-1000-8000-00805F9B34FB")a UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")y funcionó más escena, sólo a veces tenga que reiniciar el dispositivo Bluetooth;

taotao
fuente