IOException: lettura non riuscita, socket potrebbe essere chiuso - Bluetooth su Android 4.3


100

Attualmente sto cercando di affrontare una strana eccezione quando apro un BluetoothSocket sul mio Nexus 7 (2012), con Android 4.3 (Build JWR66Y, immagino il secondo aggiornamento 4.3). Ho visto alcuni messaggi correlati (ad esempio /programming/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), ma nessuno sembra fornire una soluzione alternativa per questo problema. Inoltre, come suggerito in questi thread, il riaccoppiamento non aiuta e anche il tentativo costante di connettersi (attraverso uno stupido loop) non ha alcun effetto.

Ho a che fare con un dispositivo incorporato (un adattatore per auto OBD-II non identico, simile a http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- LUCI-CON-IL-TUO-TELEFONO-Oceanside.jpg ). Il mio telefono Android 2.3.7 non ha problemi di connessione e funziona anche l'Xperia di un collega (Android 4.1.2). Anche un altro Google Nexus (non so se "One" o "S", ma non "4") non funziona con Android 4.3.

Ecco lo snippet della creazione della connessione. È in esecuzione nel proprio thread, creato all'interno di un servizio.

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;
    }

}

Il codice non funziona bluetoothSocket.connect(). Sto ottenendo un java.io.IOException: read failed, socket might closed, read ret: -1. Questa è la fonte corrispondente su GitHub: https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504 Si chiama tramite readInt (), chiamato da https : //github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319

Alcuni dump dei metadati del socket utilizzato hanno prodotto le seguenti informazioni. Questi sono esattamente gli stessi su Nexus 7 e sul mio telefono 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

Ho altri adattatori OBD-II (più espansivi) e funzionano tutti. C'è qualche possibilità che mi manchi qualcosa o potrebbe essere un bug in Android?


Ho provato la soluzione di cui sopra, può sombody aiuto su questo tema stackoverflow.com/q/52105647/1559331
dileepVikram

Risposte:


129

Finalmente ho trovato una soluzione alternativa. La magia è nascosta sotto il cofano della BluetoothDeviceclasse (vedi https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037 ).

Ora, quando ricevo tale eccezione, creo un'istanza di fallback BluetoothSocket, simile al codice sorgente di seguito. Come puoi vedere, invocando il metodo nascosto createRfcommSockettramite riflessioni. Non ho idea del perché questo metodo sia nascosto. Il codice sorgente lo definisce come publicse ...

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()poi non fallisce più. Ho ancora riscontrato alcuni problemi. Fondamentalmente, questo a volte si blocca e fallisce. Il riavvio del dispositivo SPP (plug off / plug in) aiuta in questi casi. A volte ricevo anche un'altra richiesta di accoppiamento dopoconnect() anche quando il dispositivo è già collegato.

AGGIORNARE:

ecco una classe completa, contenente alcune classi annidate. per una reale implementazione queste potrebbero essere considerate classi separate.

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);
        }

    }
}

3
Wow! ottima soluzione!
Bob

2
@MD non so come. Ho appena provato e ho scoperto che funziona.
Bob

1
Non funziona su nexus 4. puoi per favore dire come superare questo problema. Ho quasi provato di tutto. Grazie.
Shah

3
@matthes Mi dispiace dirlo ma anche la tua soluzione di utilizzare il fallback non ha risolto il mio problema. Ottenere sotto Errore. Fallback failed. Cancelling. java.io.IOException: Connection refused Per favore aiuto.
Tushar Banne

2
@matthes "SPP-Device (plug off / plug in) aiuta in questi casi.". L'affermazione on / off è la più sottovalutata al mondo. Ho appena perso 3 ore e tutto quello che dovevo fare era accenderlo e spegnerlo -_-
Adz

98

beh, ho avuto lo stesso problema con il mio codice, ed è perché da quando lo stack bluetooth di Android 4.2 è cambiato. quindi il mio codice funzionava correttamente sui dispositivi con Android <4.2, sugli altri dispositivi stavo ricevendo la famosa eccezione "lettura non riuscita, il socket potrebbe essere chiuso o scaduto, leggere ret: -1"

Il problema è con il socket.mPortparametro. Quando crei il tuo socket utilizzando socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);, il mPortvalore integer " -1 " e questo valore sembra non funzionare per android> = 4.2, quindi devi impostarlo su " 1 ". La cattiva notizia è che createRfcommSocketToServiceRecordaccetta solo l'UUID come parametro e non mPortquindi dobbiamo usare un altro approccio. La risposta pubblicata da @matthes ha funzionato anche per me, ma l'ho semplificata:socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1); . Dobbiamo usare entrambi gli attributi socket, il secondo come fallback.

Quindi il codice è (per la connessione a un SPP su 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");
        }
    }

57
per i moderatori: poiché hai cancellato la mia precedente risposta senza motivo, la posto di nuovo.
George Dima

2
grazie Giorgio per gli approfondimenti sul mPortparametro! imho il flusso di lavoro rimane lo stesso, ho appena avvolto le cose con alcune classi che implementano un'interfaccia.
matthes

5
sì, ho già detto che la tua soluzione era buona, ma volevo far capire alle persone perché è necessario utilizzare questo approccio a partire da Android 4.2
George Dima

2
SPP = Serial Port Profile (che emula una porta seriale su bluetooth) e ELM327 è un dispositivo per auto bluetooth <-> obd, google it.
George Dima

10
Ha funzionato per me dopo aver modificato il valore della porta da 1 a 2, per favore guarda questo codice. socket = (BluetoothSocket) device.getClass (). getMethod ("createRfcommSocket", nuova classe [] {int.class}). invoke (device, 2); socket.connect ();
Dinesh IT

16

Innanzitutto, se devi parlare con un dispositivo bluetooth 2.x, questa documentazione afferma che:

Suggerimento: se ti stai collegando a una scheda seriale Bluetooth, prova a utilizzare il noto SPP UUID 00001101-0000-1000-8000-00805F9B34FB . Tuttavia, se ti connetti a un peer Android, genera il tuo UUID univoco.

Non pensavo che avrebbe funzionato, ma solo sostituendo l'UUID con 00001101-0000-1000-8000-00805F9B34FBesso funziona. Tuttavia, questo codice sembra gestire il problema della versione SDK e puoi semplicemente sostituire la funzione device.createRfcommSocketToServiceRecord(mMyUuid);con tmp = createBluetoothSocket(mmDevice);dopo aver definito il seguente metodo:

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);
}

Il codice sorgente non è mio, ma proviene da questo sito web .


1
Ciò ha risolto quasi 2 giorni di lavoro ... sospiro di gratitudine ... Senza questo UUID il socket si chiuderebbe immediatamente e fallirebbe senza ulteriori spiegazioni.
David Sinclair

grazie mille per l'aiuto IL MIO UUID è alfanumerico e sto cercando di connettere HC-5 e il mio bluetooth mostra che la connessione non riesce ma quando ho usato questa soluzione il mio problema risolve. grazie ancora
Nikhil Shende

8

Ho avuto gli stessi sintomi descritti qui. Potrei connettermi una volta a una stampante Bluetooth, ma le connessioni successive non sono riuscite con "socket chiuso", non importa quello che ho fatto.

Ho trovato un po 'strano che le soluzioni alternative descritte qui fossero necessarie. Dopo aver esaminato il mio codice ho scoperto di aver dimenticato di chiudere InputStream e OutputSteram del socket e di non aver terminato correttamente i ConnectedThreads.

Il ConnectedThread che uso è lo stesso dell'esempio qui:

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

Notare che ConnectThread e ConnectedThread sono due classi differenti.

Qualunque sia la classe che avvia ConnectedThread deve chiamare interrupt () e cancel () sul thread. Ho aggiunto mmInStream.close () e mmOutStream.close () nel metodo ConnectedTread.cancel ().

Dopo aver chiuso correttamente i thread / flussi / socket, ho potuto creare nuovi socket senza alcun problema.


Grazie, stavo avendo lo stesso problema, solo ora ho pensato di non aver chiuso lo stream e la connessione ...
Rafael

provato tutti gli scenari di cui sopra, (eccetto per la rimozione di altri dispositivi accoppiati fa bene che in realtà non è una soluzione trovata che sì ... questo normalmente accade solo quando i flussi di ingresso e le prese non vengono chiusi correttamente ..... !!
Aman Satija

7

Bene, ho effettivamente trovato il problema.

La maggior parte delle persone che tentano di stabilire una connessione utilizzando socket.Connect();viene chiamata un'eccezione Java.IO.IOException: read failed, socket might closed, read ret: -1.

In alcuni casi dipende anche dal proprio dispositivo Bluetooth, perché esistono due diversi tipi di Bluetooth, ovvero BLE (low energy) e Classic.

Se vuoi controllare il tipo del tuo dispositivo Bluetooth, ecco il codice:

        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);
                }
            }
        }

Sono giorni che cerco di risolvere il problema, ma da oggi ho trovato il problema. La soluzione di @matthes ha purtroppo ancora alcuni problemi come ha già detto, ma ecco la mia soluzione.

Al momento lavoro su Xamarin Android, ma dovrebbe funzionare anche per altre piattaforme.

SOLUZIONE

Se è presente più di un dispositivo accoppiato, è necessario rimuovere gli altri dispositivi accoppiati. Quindi mantieni solo quello che vuoi connettere (vedi l'immagine a destra).

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

Nell'immagine a sinistra si vede che ho due dispositivi accoppiati, ovvero "MOCUTE-032_B52-CA7E" e "Blue Easy". Questo è il problema, ma non ho idea del motivo per cui si verifica questo problema. Forse il protocollo Bluetooth sta cercando di ottenere alcune informazioni da un altro dispositivo Bluetooth.

Tuttavia, socket.Connect();funziona alla grande in questo momento, senza problemi. Quindi volevo solo condividerlo, perché quell'errore è davvero fastidioso.

In bocca al lupo!


Questo ha funzionato sull'unico dispositivo in cui ho riscontrato questo problema, che si verifica solo su un telefono 5.0, e anche in questo caso solo quando abilito BT per la prima volta, quindi apro una connessione. Se BT fosse già acceso, nessun problema di connessione! Non si verifica su dispositivi con una versione successiva di Android, suggerendo che gli sviluppatori hanno notato il bug e lo hanno risolto, ma la pagina Android BT non ne parla. Ma la tua soluzione funziona, grazie!
John Perry

7

Sulle versioni più recenti di Android, ricevevo questo errore perché l'adattatore stava ancora scoprendo quando ho tentato di connettermi al socket. Anche se ho chiamato il metodo cancelDiscovery sull'adattatore Bluetooth, ho dovuto attendere fino a quando la richiamata al metodo onReceive () di BroadcastReceiver è stata chiamata con l'azione BluetoothAdapter.ACTION_DISCOVERY_FINISHED.

Dopo aver atteso che l'adattatore interrompesse il rilevamento, la chiamata di connessione sul socket è riuscita.


6

Hai messo registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID")); con "bluetooth" scritto "bleutooth".


4

Nel caso in cui qualcuno abbia problemi con Kotlin, ho dovuto seguire la risposta accettata con alcune variazioni:

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()
            }
        }
    }
}

Spero che sia d'aiuto


3

I dispositivi Bluetooth possono funzionare contemporaneamente in modalità classica e LE. A volte usano un indirizzo MAC diverso a seconda del modo in cui ti connetti. Le chiamate socket.connect()utilizzano Bluetooth Classic, quindi devi assicurarti che il dispositivo che hai ricevuto durante la scansione fosse davvero un dispositivo classico.

Tuttavia, è facile filtrare solo per i dispositivi classici:

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

Senza questo controllo, è una condizione difficile stabilire se una scansione ibrida fornirà prima il dispositivo Classic o il dispositivo BLE. Può sembrare un'incapacità intermittente di connettersi o che alcuni dispositivi sono in grado di connettersi in modo affidabile mentre altri apparentemente non possono mai farlo.


1

ho anche affrontato questo problema, potresti risolverlo in 2 modi, come accennato in precedenza usa la riflessione per creare il socket Il secondo è, il client sta cercando un server con un dato UUID e se il tuo server non è in esecuzione parallelamente al client, allora questo accade. Crea un server con un dato client UUID, quindi ascolta e accetta il client dal lato server. Funzionerà.


1

Mi sono imbattuto in questo problema e l'ho risolto chiudendo i flussi di input e output prima di chiudere il socket. Ora posso disconnettermi e ricollegarmi senza problemi.

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

A Kotlin:

fun disconnect() {
    bluetoothSocket.inputStream.close()
    bluetoothSocket.outputStream.close()
    bluetoothSocket.close()
}

1

Se un'altra parte del codice ha già effettuato una connessione con lo stesso socket e UUID, viene visualizzato questo errore.


0

Anche io ho avuto lo stesso problema, finalmente ho capito il mio problema, stavo cercando di connettermi dal raggio di copertura Bluetooth (fuori portata).


0

Ho avuto questo problema e la soluzione era utilizzare lo speciale GUID magico.

            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.

Sospetto che questi siano gli UUID che funzionano:

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

Tuttavia, non li ho provati tutti.


Anche io sto usando lo stesso UUID. Ma non mi ha aiutato. Supporta solo la connessione a dispositivi Bluetooth classici (non BLE)? Cosa devo fare per connettermi ai dispositivi BLE usando Xamarin.Forms. Postato qui [ stackoverflow.com/questions/62371859/…
Shailesh Bhat

Sto usando il Bluetooth classico; BLE è spazzatura.
Richard Barraclough,

-1

Aggiungendo l'azione del filtro il mio problema è stato risolto

 // 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);

-3

Ho anche ricevuto lo stesso IOException, ma trovo la demo del sistema Android: il progetto "BluetoothChat" è funzionante. Ho determinato che il problema è l'UUID.

Quindi ho sostituito il mio UUID.fromString("00001001-0000-1000-8000-00805F9B34FB")con UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")e ha funzionato quasi sempre, solo a volte è necessario riavviare il dispositivo Bluetooth;

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.