IOException: échec de lecture, le socket peut être fermé - Bluetooth sur Android 4.3


100

Actuellement, j'essaie de faire face à une étrange exception lors de l'ouverture d'un BluetoothSocket sur mon Nexus 7 (2012), avec Android 4.3 (Build JWR66Y, je suppose la deuxième mise à jour 4.3). J'ai vu des publications connexes (par exemple /programming/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), mais aucune ne semble fournir une solution de contournement à ce problème. De plus, comme suggéré dans ces threads, le réappariement n'aide pas et essayer constamment de se connecter (via une boucle stupide) n'a également aucun effet.

Je travaille avec un périphérique intégré (un adaptateur de voiture OBD-II non nom, similaire à http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- LUMIÈRES-AVEC-VOTRE-TÉLÉPHONE-Oceanside.jpg ). Mon téléphone Android 2.3.7 ne rencontre aucun problème de connexion et le Xperia d'un collègue (Android 4.1.2) fonctionne également. Un autre Google Nexus (je ne sais pas si «One» ou «S», mais pas «4») échoue également avec Android 4.3.

Voici l'extrait de l'établissement de connexion. Il s'exécute dans son propre thread, créé dans un service.

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

}

Le code échoue bluetoothSocket.connect(). Je reçois un java.io.IOException: read failed, socket might closed, read ret: -1. Voici la source correspondante sur GitHub: https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504 Il est appelé via readInt (), appelé depuis https : //github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319

Certains vidages de métadonnées du socket utilisé ont généré les informations suivantes. Ce sont exactement les mêmes sur Nexus 7 et mon téléphone 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

J'ai d'autres adaptateurs OBD-II (plus expansifs) et ils fonctionnent tous. Y a-t-il une chance que je manque quelque chose ou est-ce que cela peut être un bogue dans Android?


J'ai essayé la solution ci-dessus, puis-je aider à résoudre ce problème stackoverflow.com/q/52105647/1559331
dileepVikram

Réponses:


129

J'ai enfin trouvé une solution de contournement. La magie est cachée sous le capot de la BluetoothDeviceclasse (voir https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037 ).

Maintenant, lorsque je reçois cette exception, j'instancie une solution de secours BluetoothSocket, similaire au code source ci-dessous. Comme vous pouvez le voir, invoquer la méthode masquée createRfcommSocketvia des réflexions. Je n'ai aucune idée de pourquoi cette méthode est cachée. Le code source le définit comme 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()alors n'échoue plus. J'ai encore rencontré quelques problèmes. Fondamentalement, cela bloque parfois et échoue. Le redémarrage du SPP-Device (plug off / plug in) aide dans de tels cas. Parfois, je reçois également une autre demande de couplage connect()même lorsque l'appareil est déjà lié.

METTRE À JOUR:

voici une classe complète, contenant quelques classes imbriquées. pour une implémentation réelle, ceux-ci pourraient être détenus en tant que classes séparées.

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
Hou la la! excellente solution!
Bobs

2
@MD je ne sais pas comment. Je viens de tester et j'ai trouvé que cela fonctionnait.
Bobs

1
Cela ne fonctionne pas sur nexus 4. pouvez-vous s'il vous plaît dire comment surmonter ce problème. J'ai presque tout essayé. Merci.
Shah

3
@matthes Désolé de le dire, mais même votre solution d'utilisation de la solution de secours n'a pas résolu mon problème. Passer en dessous de l'erreur. Fallback failed. Cancelling. java.io.IOException: Connection refused Veuillez aider.
Tushar Banne

2
@matthes "SPP-Device (plug off / plug in) aide dans de tels cas.". La déclaration marche / arrêt est la plus sous-estimée au monde. Je viens de perdre 3 heures et tout ce que j'avais à faire était de l'allumer et de l'éteindre -_-
Adz

98

Eh bien, j'ai eu le même problème avec mon code, et c'est parce que depuis la pile Bluetooth Android 4.2 a changé. donc mon code fonctionnait bien sur les appareils avec Android <4.2, sur les autres appareils, j'obtenais la fameuse exception «échec de lecture, socket peut être fermé ou expiration du délai, lire ret: -1»

Le problème vient du socket.mPortparamètre. Lorsque vous créez votre socket en utilisant socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);, la mPortvaleur entière obtient " -1 ", et cette valeur semble ne pas fonctionner pour android> = 4.2, vous devez donc la définir sur " 1 ". La mauvaise nouvelle est que createRfcommSocketToServiceRecordn'accepte que l'UUID comme paramètre et mPortque nous devons donc utiliser une autre approche. La réponse affichée par @matthes a également travaillé pour moi, mais je l'ai simplifié: socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);. Nous devons utiliser les deux attributs de socket, le second comme solution de secours.

Le code est donc (pour se connecter à un SPP sur un appareil 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
pour les modérateurs: puisque vous avez supprimé ma réponse précédente sans raison, je la poste à nouveau.
George Dima

2
merci George pour les informations sur le mPortparamètre! à mon humble avis, le flux de travail reste le même, je viens d'encapsuler les choses avec certaines classes implémentant une interface.
rencontre le

5
oui, j'ai déjà dit que votre solution était bonne, mais je voulais faire comprendre aux gens pourquoi il fallait utiliser cette approche à partir d'Android 4.2
George Dima

2
SPP = Serial Port Profile (qui émule un port série via Bluetooth) et ELM327 est un appareil de voiture bluetooth <-> obd, google.
George Dima

10
Cela a fonctionné pour moi après avoir changé la valeur du port de 1 à 2. veuillez regarder ce code. socket = (BluetoothSocket) device.getClass (). getMethod ("createRfcommSocket", new Class [] {int.class}). invoke (device, 2); socket.connect ();
Dinesh IT

16

Tout d'abord, si vous avez besoin de parler à un appareil Bluetooth 2.x, cette documentation indique que:

Astuce: si vous vous connectez à une carte série Bluetooth, essayez d'utiliser le SPP UUID 00001101-0000-1000-8000-00805F9B34FB bien connu . Cependant, si vous vous connectez à un pair Android, veuillez générer votre propre UUID unique.

Je ne pensais pas que cela fonctionnerait, mais seulement en remplaçant l'UUID par 00001101-0000-1000-8000-00805F9B34FBcela fonctionne. Cependant, ce code semble gérer le problème de la version du SDK, et vous pouvez simplement remplacer la fonction device.createRfcommSocketToServiceRecord(mMyUuid);par tmp = createBluetoothSocket(mmDevice);après avoir défini la méthode suivante:

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

Le code source n'est pas le mien, mais provient de ce site Web .


1
Cela a résolu presque 2 jours de travail ... soupir de reconnaissance ... Sans cet UUID, le socket se fermerait immédiatement et échouerait sans autre explication.
David Sinclair

merci beaucoup pour l'aide MON UUID est alphanumérique et j'essaie de connecter HC-5 et mon bluetooth montrant l'échec de la connexion, mais lorsque j'ai utilisé cette solution, mon problème est résolu. merci encore
Nikhil Shende le

8

J'ai eu les mêmes symptômes que ceux décrits ici. J'ai pu me connecter une fois à une imprimante Bluetooth, mais les connexions suivantes ont échoué avec "socket fermé", peu importe ce que j'ai fait.

J'ai trouvé un peu étrange que les solutions de contournement décrites ici soient nécessaires. Après avoir parcouru mon code, j'ai constaté que j'avais oublié de fermer InputStream et OutputSteram de la prise et que je n'avais pas terminé correctement les ConnectedThreads.

Le ConnectedThread que j'utilise est le même que dans l'exemple ici:

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

Notez que ConnectThread et ConnectedThread sont deux classes différentes.

Quelle que soit la classe qui démarre le ConnectedThread, il faut appeler interruption () et cancel () sur le thread. J'ai ajouté mmInStream.close () et mmOutStream.close () dans la méthode ConnectedTread.cancel ().

Après avoir fermé correctement les threads / streams / sockets, je pourrais créer de nouvelles sockets sans aucun problème.


Merci, j'avais le même problème, tout à l'heure je me suis dit que je n'avais pas fermé le flux et la connexion ...
Rafael

essayé tous les scénarios ci-dessus, (à l'exception de la suppression d'autres périphériques appariés, ce n'est vraiment pas une solution trouvée que oui ... cela ne se produit normalement que lorsque les flux d'entrée et les sockets ne sont pas fermés correctement ..... !!
Aman Satija

7

Eh bien, j'ai trouvé le problème.

La plupart des gens qui essaient d'établir une connexion en utilisant socket.Connect();obtiennent une exception appelée Java.IO.IOException: read failed, socket might closed, read ret: -1.

Dans certains cas, cela dépend également de votre appareil Bluetooth, car il existe deux types de Bluetooth différents, à savoir BLE (low energy) et Classic.

Si vous souhaitez vérifier le type de votre appareil Bluetooth, voici le code:

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

J'essaye depuis des jours de résoudre le problème, mais depuis aujourd'hui j'ai trouvé le problème. La solution de @matthes a malheureusement encore quelques problèmes comme il l'a déjà dit, mais voici ma solution.

Pour le moment, je travaille dans Xamarin Android, mais cela devrait également fonctionner pour d'autres plates-formes.

SOLUTION

S'il y a plus d'un appareil couplé, vous devez supprimer les autres appareils couplés. Alors ne gardez que celui que vous souhaitez connecter (voir la bonne image).

entrez la description de l'image ici entrez la description de l'image ici

Dans l'image de gauche, vous voyez que j'ai deux appareils appairés, à savoir "MOCUTE-032_B52-CA7E" et "Blue Easy". C'est le problème, mais je ne sais pas pourquoi ce problème se produit. Peut-être que le protocole Bluetooth tente d'obtenir des informations d'un autre appareil Bluetooth.

Cependant, cela socket.Connect();fonctionne très bien maintenant, sans aucun problème. Alors je voulais juste partager ceci, parce que cette erreur est vraiment ennuyeuse.

Bonne chance!


Cela a fonctionné sur le seul appareil sur lequel je rencontre ce problème, qui ne se produit que pour moi sur un téléphone 5.0, et même alors seulement lorsque j'active BT pour la première fois, puis que j'ouvre une connexion. Si BT était déjà allumé, pas de problème de connexion! Cela ne se produit pas sur les appareils dotés d'une version ultérieure d'Android, ce qui suggère que les développeurs ont remarqué le bogue et l'ont corrigé, mais la page Android BT n'en respire pas un mot. Mais votre solution fonctionne, merci!
John Perry

7

Sur les versions plus récentes d'Android, je recevais cette erreur car l'adaptateur était toujours en train de découvrir lorsque j'ai tenté de me connecter au socket. Même si j'ai appelé la méthode cancelDiscovery sur l'adaptateur Bluetooth, j'ai dû attendre que le rappel de la méthode onReceive () de BroadcastReceiver soit appelé avec l'action BluetoothAdapter.ACTION_DISCOVERY_FINISHED.

Une fois que j'ai attendu que l'adaptateur arrête la découverte, l'appel de connexion sur le socket a réussi.


6

Vous mettez registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID")); avec "bluetooth" épelé "bleutooth".


4

Au cas où quelqu'un aurait des problèmes avec Kotlin, je devais suivre la réponse acceptée avec quelques variantes:

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

J'espère que ça aide


3

Les appareils Bluetooth peuvent fonctionner en mode classique et LE en même temps. Parfois, ils utilisent une adresse MAC différente en fonction de la manière dont vous vous connectez. L'appel socket.connect()utilise Bluetooth Classic, vous devez donc vous assurer que l'appareil que vous avez obtenu lors de la numérisation était vraiment un appareil classique.

Cependant, il est facile de filtrer uniquement les appareils Classic:

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

Sans cette vérification, c'est une condition de concurrence pour savoir si une analyse hybride vous donnera d'abord le périphérique Classic ou le périphérique BLE. Cela peut apparaître comme une incapacité intermittente à se connecter ou comme certains appareils pouvant se connecter de manière fiable alors que d'autres ne le peuvent apparemment jamais.


1

J'ai également été confronté à ce problème, vous pouvez le résoudre de 2 manières, comme mentionné précédemment, utilisez la réflexion pour créer la socket.La deuxième est que le client recherche un serveur avec un UUID donné et si votre serveur ne fonctionne pas parallèlement au client, alors ceci arrive. Créez un serveur avec un UUID client donné, puis écoutez et acceptez le client du côté serveur, cela fonctionnera.


1

J'ai rencontré ce problème et je l'ai résolu en fermant les flux d'entrée et de sortie avant de fermer le socket. Maintenant, je peux me déconnecter et me reconnecter sans problème.

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

À Kotlin:

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

1

Si une autre partie de votre code a déjà établi une connexion avec le même socket et UUID, vous obtenez cette erreur.


0

Même si j'ai eu le même problème, j'ai enfin compris mon problème, j'essayais de me connecter à partir de la plage de couverture Bluetooth (hors de portée).


0

J'ai eu ce problème et la solution était d'utiliser le GUID magique spécial.

            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.

Je soupçonne que ce sont les UUID qui fonctionnent:

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

Cependant, je ne les ai pas tous essayés.


Même j'utilise le même UUID. Mais ne m'a pas aidé. Est-ce que cela prend uniquement en charge la connexion à des appareils Bluetooth classiques (pas BLE)? Ce que je dois faire pour me connecter aux appareils BLE à l'aide de Xamarin.Forms. Publié ici [ stackoverflow.com/questions/62371859/…
Shailesh Bhat

J'utilise le Bluetooth classique; BLE est de la merde.
Richard Barraclough

-1

En ajoutant une action de filtrage, mon problème a été résolu

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

J'ai également reçu la même chose IOException, mais je trouve la démo du système Android: le projet "BluetoothChat" fonctionne. J'ai déterminé que le problème était l'UUID.

Donc , je remplace mon UUID.fromString("00001001-0000-1000-8000-00805F9B34FB")à UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")et cela a fonctionné plus scène, seulement besoin parfois de redémarrer le périphérique Bluetooth;

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.