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?
Réponses:
J'ai enfin trouvé une solution de contournement. La magie est cachée sous le capot de la
BluetoothDevice
classe (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éecreateRfcommSocket
via des réflexions. Je n'ai aucune idée de pourquoi cette méthode est cachée. Le code source le définit commepublic
si ...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 couplageconnect()
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.
la source
Fallback failed. Cancelling. java.io.IOException: Connection refused
Veuillez aider.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.mPort
paramètre. Lorsque vous créez votre socket en utilisantsocket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
, lamPort
valeur 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 quecreateRfcommSocketToServiceRecord
n'accepte que l'UUID comme paramètre etmPort
que 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):
la source
mPort
paramè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.Tout d'abord, si vous avez besoin de parler à un appareil Bluetooth 2.x, cette documentation indique que:
Je ne pensais pas que cela fonctionnerait, mais seulement en remplaçant l'UUID par
00001101-0000-1000-8000-00805F9B34FB
cela fonctionne. Cependant, ce code semble gérer le problème de la version du SDK, et vous pouvez simplement remplacer la fonctiondevice.createRfcommSocketToServiceRecord(mMyUuid);
partmp = createBluetoothSocket(mmDevice);
après avoir défini la méthode suivante:Le code source n'est pas le mien, mais provient de ce site Web .
la source
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.
la source
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éeJava.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:
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).
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!
la source
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.
la source
Vous mettez
registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
avec "bluetooth" épelé "bleutooth".la source
Au cas où quelqu'un aurait des problèmes avec Kotlin, je devais suivre la réponse acceptée avec quelques variantes:
J'espère que ça aide
la source
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.
la source
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.
la source
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:
la source
Si une autre partie de votre code a déjà établi une connexion avec le même socket et UUID, vous obtenez cette erreur.
la source
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).
la source
J'ai eu ce problème et la solution était d'utiliser le GUID magique spécial.
Je soupçonne que ce sont les UUID qui fonctionnent:
Cependant, je ne les ai pas tous essayés.
la source
En ajoutant une action de filtrage, mon problème a été résolu
la source
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;la source