IOException: Lesen fehlgeschlagen, Socket möglicherweise geschlossen - Bluetooth unter Android 4.3

100

Derzeit versuche ich, beim Öffnen eines BluetoothSocket auf meinem Nexus 7 (2012) mit Android 4.3 (Build JWR66Y, ich denke das zweite 4.3-Update) mit einer seltsamen Ausnahme umzugehen. Ich habe einige verwandte Beiträge gesehen (z. B. /programming/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), aber keiner scheint eine Problemumgehung für dieses Problem zu bieten. Wie in diesen Threads vorgeschlagen, hilft das erneute Pairing nicht, und der ständige Versuch, eine Verbindung herzustellen (über eine dumme Schleife), hat ebenfalls keine Auswirkung.

Ich habe es mit einem eingebetteten Gerät zu tun (einem OBD-II-Autoadapter ohne Namen, ähnlich http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- LICHTER MIT IHREM TELEFON-Oceanside.jpg ). Mein Android 2.3.7-Telefon hat keine Verbindungsprobleme, und das Xperia eines Kollegen (Android 4.1.2) funktioniert ebenfalls. Ein anderes Google Nexus (ich weiß nicht, ob 'One' oder 'S', aber nicht '4') schlägt ebenfalls mit Android 4.3 fehl.

Hier ist das Snippet des Verbindungsaufbaus. Es wird in einem eigenen Thread ausgeführt, der innerhalb eines Dienstes erstellt wurde.

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

}

Der Code schlägt bei fehl bluetoothSocket.connect(). Ich bekomme eine java.io.IOException: read failed, socket might closed, read ret: -1. Dies ist die entsprechende Quelle bei GitHub: https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504 Sie wird über readInt () aufgerufen und von https aufgerufen : //github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319

Einige Metadaten-Dumps des verwendeten Sockets führten zu den folgenden Informationen. Diese sind auf dem Nexus 7 und meinem 2.3.7-Telefon genau gleich.

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

Ich habe einige andere OBD-II-Adapter (expansiver) und sie funktionieren alle. Gibt es eine Chance, dass mir etwas fehlt oder könnte dies ein Fehler in Android sein?

matthes
quelle
Ich habe die obige Lösung ausprobiert, kann jemand bei diesem Problem helfen stackoverflow.com/q/52105647/1559331
dileepVikram

Antworten:

129

Ich habe endlich eine Problemumgehung gefunden. Die Magie ist unter der Haube der BluetoothDeviceKlasse verborgen (siehe https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037 ).

Wenn ich diese Ausnahme erhalte, instanziiere ich einen Fallback BluetoothSocket, ähnlich dem folgenden Quellcode. Wie Sie sehen können, rufen Sie die versteckte Methode createRfcommSocketüber Reflexionen auf. Ich habe keine Ahnung, warum diese Methode versteckt ist. Der Quellcode definiert es als public...

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()dann scheitert nicht mehr. Ich habe noch einige Probleme erlebt. Grundsätzlich blockiert dies manchmal und schlägt fehl. In solchen Fällen hilft ein Neustart des SPP-Geräts (Plug-Off / Plug-In). Manchmal erhalte ich auch dann eine andere Pairing-Anfrage connect(), wenn das Gerät bereits verbunden ist.

AKTUALISIEREN:

Hier ist eine vollständige Klasse, die einige verschachtelte Klassen enthält. Für eine echte Implementierung könnten diese als separate Klassen gehalten werden.

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

    }
}
matthes
quelle
3
Beeindruckend! tolle Lösung!
Bobs
2
@ MD Ich weiß nicht wie. Ich habe gerade getestet und festgestellt, dass es funktioniert.
Bobs
1
Auf Nexus 4 funktioniert es nicht. Können Sie bitte sagen, wie Sie dieses Problem lösen können? Ich habe fast alles versucht. Vielen Dank.
Shah
3
@matthes Tut mir leid zu sagen, aber selbst Ihre Lösung für die Verwendung des Fallbacks hat mein Problem nicht gelöst. Unter Fehler geraten. Fallback failed. Cancelling. java.io.IOException: Connection refused Bitte helfen Sie.
Tushar Banne
2
@matthes "SPP-Gerät (Plug Off / Plug In) hilft in solchen Fällen." Die Ein / Aus-Aussage ist die am meisten unterschätzte der Welt. Ich habe gerade 3 Stunden verschwendet und alles was ich tun musste war es ein- und auszuschalten -_-
Adz
97

Nun, ich hatte das gleiche Problem mit meinem Code, und das liegt daran, dass sich der Bluetooth-Stack für Android 4.2 geändert hat. Also lief mein Code auf Geräten mit Android <4.2 einwandfrei, auf den anderen Geräten bekam ich die berühmte Ausnahme "Lesen fehlgeschlagen, Socket möglicherweise geschlossen oder Timeout, Lesen ret: -1".

Das Problem liegt beim socket.mPortParameter. Wenn Sie Ihren Socket mit erstellen socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);, wird der mPortganzzahlige Wert " -1 " abgerufen , und dieser Wert scheint für Android> = 4.2 nicht zu funktionieren. Sie müssen ihn daher auf " 1 " setzen. Die schlechte Nachricht ist, dass createRfcommSocketToServiceRecordnur UUID als Parameter akzeptiert wird und nicht, mPortdass wir einen anderen Ansatz verwenden müssen. Die Antwort von @matthes hat auch bei mir funktioniert, aber ich habe es vereinfacht : socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);. Wir müssen beide Socket-Attribute verwenden, das zweite als Fallback.

Der Code lautet also (für die Verbindung mit einem SPP auf einem ELM327-Gerät):

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
quelle
57
Für Moderatoren: Da Sie meine vorherige Antwort ohne Grund gelöscht haben, poste ich sie erneut.
George Dima
2
danke George für die Einblicke in den mPortParameter! Imho der Workflow bleibt der gleiche, ich habe die Dinge nur mit einigen Klassen verpackt, die eine Schnittstelle implementieren.
Matthes
5
Ja, ich habe bereits gesagt, dass Ihre Lösung gut ist, aber ich wollte den Leuten verständlich machen, warum dieser Ansatz verwendet werden muss, beginnend mit Android 4.2
George Dima
2
SPP = Serial Port Profile (das eine serielle Schnittstelle über Bluetooth emuliert) und ELM327 ist ein Bluetooth <-> obd Auto-Gerät, google es.
George Dima
10
Es hat bei mir funktioniert, nachdem der Portwert von 1 auf 2 geändert wurde. Bitte schauen Sie sich diesen Code an. socket = (BluetoothSocket) device.getClass (). getMethod ("createRfcommSocket", neue Klasse [] {int.class}). invoke (device, 2); socket.connect ();
Dinesh IT
16

Wenn Sie mit einem Bluetooth 2.x-Gerät sprechen müssen, heißt es in dieser Dokumentation zunächst :

Hinweis: Wenn Sie eine Verbindung zu einer seriellen Bluetooth -Karte herstellen , verwenden Sie die bekannte SPP-UUID 00001101-0000-1000-8000-00805F9B34FB . Wenn Sie jedoch eine Verbindung zu einem Android-Peer herstellen, generieren Sie bitte Ihre eigene eindeutige UUID.

Ich dachte nicht, dass es funktionieren würde, sondern nur durch Ersetzen der UUID 00001101-0000-1000-8000-00805F9B34FB. Allerdings scheint dieser Code das Problem der SDK - Version zu handhaben , und man kann nur die Funktion ersetzt device.createRfcommSocketToServiceRecord(mMyUuid);mit tmp = createBluetoothSocket(mmDevice);nach der folgenden Methode zu definieren:

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

Der Quellcode gehört nicht mir, sondern stammt von dieser Website .

tobiasBora
quelle
1
Das löste fast 2 Arbeitstage ... dankbares Seufzen ... Ohne diese UUID würde sich die Steckdose sofort schließen und ohne weitere Erklärung ausfallen.
David Sinclair
Vielen Dank für Ihre Hilfe. Meine UUID ist alphanumerisch und ich versuche, eine Verbindung zwischen HC-5 und meinem Bluetooth herzustellen. Die Verbindung schlägt fehl, aber als ich diese Lösung verwendet habe, ist mein Problem gelöst.
Nochmals
8

Ich hatte die gleichen Symptome wie hier beschrieben. Ich konnte einmal eine Verbindung zu einem Bluetooth-Drucker herstellen, aber nachfolgende Verbindungen schlugen mit "Socket geschlossen" fehl, egal was ich tat.

Ich fand es etwas seltsam, dass die hier beschriebenen Problemumgehungen notwendig wären. Nachdem ich meinen Code durchgesehen hatte, stellte ich fest, dass ich vergessen hatte, InputStream und OutputSteram des Sockets zu schließen, und die ConnectedThreads nicht ordnungsgemäß beendete.

Der von mir verwendete ConnectedThread ist der gleiche wie im folgenden Beispiel:

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

Beachten Sie, dass ConnectThread und ConnectedThread zwei verschiedene Klassen sind.

Unabhängig von der Klasse, die ConnectedThread startet, muss Interrupt () und cancel () für den Thread aufgerufen werden. Ich habe mmInStream.close () und mmOutStream.close () in die ConnectedTread.cancel () -Methode eingefügt.

Nachdem ich die Threads / Streams / Sockets richtig geschlossen hatte, konnte ich problemlos neue Sockets erstellen.

Daniel T.
quelle
Danke, hatte das gleiche Problem, gerade jetzt dachte ich, dass ich den Stream und die Verbindung nicht geschlossen hatte ...
Rafael
habe alle oben genannten Szenarien ausprobiert (außer das Entfernen anderer gekoppelter Geräte führt dazu, dass wirklich keine Lösung gefunden wird, die ja ... dies geschieht normalerweise nur, wenn die Eingabestreams und Sockets nicht richtig geschlossen werden ..... !!
Aman Satija
7

Nun, ich habe das Problem tatsächlich gefunden.

Die meisten Leute, die versuchen, eine Verbindung mit herzustellen, socket.Connect();erhalten eine Ausnahme namens Java.IO.IOException: read failed, socket might closed, read ret: -1.

In einigen Fällen hängt dies auch von Ihrem Bluetooth-Gerät ab, da es zwei verschiedene Arten von Bluetooth gibt, nämlich BLE (Low Energy) und Classic.

Wenn Sie den Typ Ihres Bluetooth-Geräts überprüfen möchten, lautet der folgende 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);
                }
            }
        }

Ich habe tagelang versucht, das Problem zu lösen, aber seit heute habe ich das Problem gefunden. Die Lösung von @matthes hat leider noch ein paar Probleme, wie er bereits sagte, aber hier ist meine Lösung.

Im Moment arbeite ich in Xamarin Android, aber das sollte auch für andere Plattformen funktionieren.

LÖSUNG

Wenn mehr als ein gekoppeltes Gerät vorhanden ist, sollten Sie die anderen gekoppelten Geräte entfernen. Behalten Sie also nur diejenige, die Sie verbinden möchten (siehe das rechte Bild).

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Im linken Bild sehen Sie, dass ich zwei gekoppelte Geräte habe, nämlich "MOCUTE-032_B52-CA7E" und "Blue Easy". Das ist das Problem, aber ich habe keine Ahnung, warum dieses Problem auftritt. Möglicherweise versucht das Bluetooth-Protokoll, Informationen von einem anderen Bluetooth-Gerät abzurufen.

Das socket.Connect();funktioniert aber momentan ohne Probleme. Ich wollte das nur teilen, weil dieser Fehler wirklich ärgerlich ist.

Viel Glück!

Jamie
quelle
Dies funktionierte auf dem einen Gerät, auf dem dieses Problem auftritt, das nur bei einem 5.0-Telefon auftritt, und selbst dann nur, wenn ich zuerst BT aktiviere und dann eine Verbindung herstelle. Wenn BT schon eingeschaltet war, kein Verbindungsproblem! Es tritt nicht auf Geräten mit einer späteren Version von Android auf, was darauf hindeutet, dass die Entwickler den Fehler bemerkt und behoben haben, aber die Android BT-Seite sagt kein Wort darüber. Aber Ihre Lösung funktioniert, danke!
John Perry
7

Bei neueren Android-Versionen wurde dieser Fehler angezeigt, da der Adapter beim Versuch, eine Verbindung zum Socket herzustellen, immer noch festgestellt hat. Obwohl ich die cancelDiscovery-Methode auf dem Bluetooth-Adapter aufgerufen habe, musste ich warten, bis der Rückruf zur onReceive () -Methode des BroadcastReceiver mit der Aktion BluetoothAdapter.ACTION_DISCOVERY_FINISHED aufgerufen wurde.

Nachdem ich darauf gewartet hatte, dass der Adapter die Erkennung beendet, war der Verbindungsaufruf am Socket erfolgreich.

kmac.mcfarlane
quelle
6

Sie setzen registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID")); mit "Bluetooth" buchstabiert "Bleutooth".

Fizz Binn
quelle
4

Falls jemand Probleme mit Kotlin hat, musste ich der akzeptierten Antwort mit einigen Variationen folgen:

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

Ich hoffe es hilft

Santiago Martí Olbrich
quelle
3

Bluetooth-Geräte können gleichzeitig im klassischen und im LE-Modus betrieben werden. Manchmal verwenden sie eine andere MAC-Adresse, je nachdem, auf welche Weise Sie eine Verbindung herstellen. Beim Telefonieren socket.connect()wird Bluetooth Classic verwendet. Sie müssen also sicherstellen, dass das Gerät, das Sie beim Scannen erhalten haben, wirklich ein klassisches Gerät ist.

Es ist jedoch einfach, nur nach Classic-Geräten zu filtern:

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

Ohne diese Prüfung ist es eine Rennbedingung, ob Sie bei einem Hybrid-Scan zuerst das Classic-Gerät oder das BLE-Gerät erhalten. Es kann als zeitweise Unfähigkeit erscheinen, eine Verbindung herzustellen, oder als bestimmte Geräte, die eine zuverlässige Verbindung herstellen können, während andere dies anscheinend nie können.

kmac.mcfarlane
quelle
1

Ich habe mich auch mit diesem Problem konfrontiert. Sie können es auf zwei Arten lösen. Wie bereits erwähnt, verwenden Sie Reflection, um den Socket zu erstellen. Zweitens sucht der Client nach einem Server mit einer bestimmten UUID. Wenn Ihr Server nicht parallel zum Client ausgeführt wird, ist dies der Fall das passiert. Erstellen Sie einen Server mit der angegebenen Client-UUID und hören Sie dann zu und akzeptieren Sie den Client von der Serverseite. Es wird funktionieren.

ireshika piyumalie
quelle
1

Ich bin auf dieses Problem gestoßen und habe es behoben, indem ich die Eingabe- und Ausgabestreams geschlossen habe, bevor ich den Socket geschlossen habe. Jetzt kann ich ohne Probleme die Verbindung trennen und wieder herstellen.

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

In Kotlin:

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

Wenn ein anderer Teil Ihres Codes bereits eine Verbindung mit demselben Socket und derselben UUID hergestellt hat, wird dieser Fehler angezeigt.

user1725145
quelle
0

Sogar ich hatte das gleiche Problem, verstehe endlich mein Problem, ich habe versucht, eine Verbindung von (außerhalb der Reichweite) Bluetooth-Reichweite herzustellen.

krishnamurthy
quelle
0

Ich hatte dieses Problem und die Lösung bestand darin, die spezielle magische GUID zu verwenden.

            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.

Ich vermute, dass dies die UUIDs sind, die funktionieren:

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

Ich habe sie jedoch nicht alle ausprobiert.

Richard Barraclough
quelle
Sogar ich benutze die gleiche UUID. Hat mir aber nicht geholfen. Unterstützt dies nur die Verbindung zu klassischen Bluetooth-Geräten (nicht BLE)? Was muss ich tun, um mit Xamarin.Forms eine Verbindung zu BLE-Geräten herzustellen? Gepostet
Shailesh Bhat
Ich verwende klassisches Bluetooth. BLE ist Müll.
Richard Barraclough
-1

Durch Hinzufügen einer Filteraktion wurde mein Problem behoben

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

Ich habe auch das gleiche erhalten IOException, aber ich finde die Android-Systemdemo: "BluetoothChat" -Projekt funktioniert. Ich habe festgestellt, dass das Problem die UUID ist.

Also ich meine ersetzen UUID.fromString("00001001-0000-1000-8000-00805F9B34FB")zu UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")und es die meisten Szene gearbeitet, nur manchmal das Bluetooth - Gerät neu starten müssen;

Taotao
quelle