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?
Antworten:
Ich habe endlich eine Problemumgehung gefunden. Die Magie ist unter der Haube der
BluetoothDevice
Klasse 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 MethodecreateRfcommSocket
über Reflexionen auf. Ich habe keine Ahnung, warum diese Methode versteckt ist. Der Quellcode definiert es alspublic
...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-Anfrageconnect()
, 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.
quelle
Fallback failed. Cancelling. java.io.IOException: Connection refused
Bitte helfen Sie.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.mPort
Parameter. Wenn Sie Ihren Socket mit erstellensocket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
, wird dermPort
ganzzahlige 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, dasscreateRfcommSocketToServiceRecord
nur UUID als Parameter akzeptiert wird und nicht,mPort
dass 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):
quelle
mPort
Parameter! Imho der Workflow bleibt der gleiche, ich habe die Dinge nur mit einigen Klassen verpackt, die eine Schnittstelle implementieren.Wenn Sie mit einem Bluetooth 2.x-Gerät sprechen müssen, heißt es in dieser Dokumentation zunächst :
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 ersetztdevice.createRfcommSocketToServiceRecord(mMyUuid);
mittmp = createBluetoothSocket(mmDevice);
nach der folgenden Methode zu definieren:Der Quellcode gehört nicht mir, sondern stammt von dieser Website .
quelle
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.
quelle
Nun, ich habe das Problem tatsächlich gefunden.
Die meisten Leute, die versuchen, eine Verbindung mit herzustellen,
socket.Connect();
erhalten eine Ausnahme namensJava.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:
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).
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!
quelle
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.
quelle
Sie setzen
registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
mit "Bluetooth" buchstabiert "Bleutooth".quelle
Falls jemand Probleme mit Kotlin hat, musste ich der akzeptierten Antwort mit einigen Variationen folgen:
Ich hoffe es hilft
quelle
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.
quelle
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.
quelle
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:
quelle
Wenn ein anderer Teil Ihres Codes bereits eine Verbindung mit demselben Socket und derselben UUID hergestellt hat, wird dieser Fehler angezeigt.
quelle
Sogar ich hatte das gleiche Problem, verstehe endlich mein Problem, ich habe versucht, eine Verbindung von (außerhalb der Reichweite) Bluetooth-Reichweite herzustellen.
quelle
Ich hatte dieses Problem und die Lösung bestand darin, die spezielle magische GUID zu verwenden.
Ich vermute, dass dies die UUIDs sind, die funktionieren:
Ich habe sie jedoch nicht alle ausprobiert.
quelle
Durch Hinzufügen einer Filteraktion wurde mein Problem behoben
quelle
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")
zuUUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")
und es die meisten Szene gearbeitet, nur manchmal das Bluetooth - Gerät neu starten müssen;quelle