Obecnie próbuję poradzić sobie z dziwnym Wyjątkiem podczas otwierania BluetoothSocket na moim Nexusie 7 (2012), z Androidem 4.3 (kompilacja JWR66Y, myślę, że druga aktualizacja 4.3). Widziałem kilka pokrewnych postów (np. Https://stackoverflow.com/questions/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), ale żadna z nich nie zapewnia obejścia tego problemu. Ponadto, jak sugerowano w tych wątkach, ponowne parowanie nie pomaga, a ciągłe próby połączenia (przez głupią pętlę) również nie przynoszą efektu.
Mam do czynienia z urządzeniem wbudowanym (adapter samochodowy noname OBD-II, podobny do http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- ŚWIATŁA-Z-TWOIM-TELEFONEM-Oceanside.jpg ). Mój telefon z Androidem 2.3.7 nie ma żadnych problemów z połączeniem, działa też Xperia kolegi (Android 4.1.2). Inny Google Nexus (nie wiem, czy „Jeden” czy „S”, ale nie „4”) również nie działa z Androidem 4.3.
Oto fragment zestawienia połączenia. Działa we własnym wątku utworzonym w ramach usługi.
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;
}
}
Kod nie działa pod adresem bluetoothSocket.connect()
. Dostaję java.io.IOException: read failed, socket might closed, read ret: -1
. To jest odpowiednie źródło w GitHub: https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504
Jest wywoływany przez readInt (), wywoływany z https : //github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319
Niektóre zrzuty metadanych używanego gniazda zwróciły następujące informacje. Są dokładnie takie same na Nexusie 7 i moim telefonie 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
Mam kilka innych adapterów OBD-II (więcej ekspansji) i wszystkie działają. Czy jest szansa, że czegoś mi brakuje lub może to być błąd w Androidzie?
Odpowiedzi:
W końcu znalazłem obejście. Magia jest ukryta pod maską
BluetoothDevice
klasy (patrz https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037 ).Teraz, kiedy otrzymam ten wyjątek, tworzę instancję rezerwową
BluetoothSocket
, podobną do kodu źródłowego poniżej. Jak widać, przywołanie metody ukrytejcreateRfcommSocket
za pomocą odbić. Nie mam pojęcia, dlaczego ta metoda jest ukryta. Kod źródłowy definiuje to tak,public
jakby ...connect()
to już nie zawodzi. Wciąż napotkałem kilka problemów. Zasadniczo to czasami blokuje i kończy się niepowodzeniem. W takich przypadkach pomaga ponowne uruchomienie urządzenia SPP (podłączenie / wyłączenie). Czasami otrzymuję również kolejną prośbę o parowanie,connect()
nawet gdy urządzenie jest już połączone.AKTUALIZACJA:
tutaj jest pełna klasa, zawierająca kilka zagnieżdżonych klas. dla rzeczywistej implementacji mogłyby się one odbywać jako oddzielne klasy.
źródło
Fallback failed. Cancelling. java.io.IOException: Connection refused
Proszę pomóż.cóż, miałem ten sam problem z moim kodem, a to dlatego, że od czasu zmiany stosu bluetooth Androida 4.2. więc mój kod działał poprawnie na urządzeniach z Androidem <4.2, na innych urządzeniach występował słynny wyjątek „błąd odczytu, gniazdo mogło zostać zamknięte lub przekroczono limit czasu, odczyt ret: -1”
Problem dotyczy
socket.mPort
parametru. Kiedy tworzysz swoje gniazdo za pomocąsocket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
,mPort
otrzymujesz wartość całkowitą " -1 ", a ta wartość wydaje się nie działać dla Androida> = 4.2, więc musisz ustawić ją na " 1 ". Zła wiadomość jest taka, żecreateRfcommSocketToServiceRecord
akceptuje tylko UUID jako parametr, amPort
więc nie musimy używać innego podejścia. Odpowiedź wysłane przez @matthes również pracował dla mnie, ale uproszczone go:socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);
. Musimy użyć obu atrybutów gniazda, drugiego jako rezerwy.Więc kod to (do połączenia z SPP na urządzeniu ELM327):
źródło
mPort
parametr! imho przepływ pracy pozostaje taki sam, po prostu opakowałem rzeczy niektórymi klasami implementującymi interfejs.Po pierwsze, jeśli chcesz rozmawiać z urządzeniem Bluetooth 2.x, w tej dokumentacji stwierdza się, że:
Nie sądziłem, że to zadziała, ale działa tylko zastępując UUID
00001101-0000-1000-8000-00805F9B34FB
. Jednak ten kod zdaje sobie z problemem wersji SDK, i można po prostu zastąpić funkcjędevice.createRfcommSocketToServiceRecord(mMyUuid);
ztmp = createBluetoothSocket(mmDevice);
po zdefiniowaniu w następujący sposób:Kod źródłowy nie jest mój, ale pochodzi z tej witryny .
źródło
Miałem takie same objawy, jak opisane tutaj. Mogłem raz połączyć się z drukarką bluetooth, ale kolejne połączenia kończyły się niepowodzeniem z powodu „zamkniętego gniazda” bez względu na to, co zrobiłem.
Wydało mi się trochę dziwne, że opisane tutaj obejścia byłyby konieczne. Po przejrzeniu mojego kodu stwierdziłem, że zapomniałem zamknąć InputStream i OutputSteram gniazda i nie zakończyłem poprawnie ConnectedThreads.
ConnectedThread, którego używam, jest taki sam jak w przykładzie tutaj:
http://developer.android.com/guide/topics/connectivity/bluetooth.html
Zwróć uwagę, że ConnectThread i ConnectedThread to dwie różne klasy.
Każda klasa, która uruchamia ConnectedThread, musi wywołać przerwanie () i anulowanie () w wątku. Dodałem mmInStream.close () i mmOutStream.close () w metodzie ConnectedTread.cancel ().
Po poprawnym zamknięciu wątków / strumieni / gniazd mogłem bez problemu tworzyć nowe gniazda.
źródło
Cóż, faktycznie znalazłem problem.
Większość osób, które próbują nawiązać połączenie za pomocą protokołu,
socket.Connect();
otrzymuje wyjątek o nazwieJava.IO.IOException: read failed, socket might closed, read ret: -1
.W niektórych przypadkach zależy to również od urządzenia Bluetooth, ponieważ istnieją dwa różne typy Bluetooth, a mianowicie BLE (low energy) i Classic.
Jeśli chcesz sprawdzić typ swojego urządzenia Bluetooth, oto kod:
Od dni próbuję rozwiązać ten problem, ale od dzisiaj go znalazłem. Rozwiązanie z @matthes ma niestety wciąż kilka problemów, jak już powiedział, ale oto moje rozwiązanie.
W tej chwili pracuję w Xamarin Android, ale powinno to zadziałać również na innych platformach.
ROZWIĄZANIE
Jeśli jest więcej niż jedno sparowane urządzenie, należy usunąć pozostałe sparowane urządzenia. Więc zachowaj tylko ten, który chcesz podłączyć (patrz prawy obraz).
Na lewym obrazku widać, że mam dwa sparowane urządzenia, a mianowicie „MOCUTE-032_B52-CA7E” i „Blue Easy”. To jest problem, ale nie mam pojęcia, dlaczego ten problem występuje. Może protokół Bluetooth próbuje uzyskać jakieś informacje z innego urządzenia Bluetooth.
Jednak teraz
socket.Connect();
działa świetnie, bez żadnych problemów. Chciałem się tym tylko podzielić, ponieważ ten błąd jest naprawdę irytujący.Powodzenia!
źródło
W nowszych wersjach Androida otrzymywałem ten błąd, ponieważ adapter nadal wykrywał, gdy próbowałem połączyć się z gniazdem. Mimo że wywołałem metodę cancelDiscovery na karcie Bluetooth, musiałem poczekać, aż wywołanie zwrotne metody onReceive () BroadcastReceiver z akcją BluetoothAdapter.ACTION_DISCOVERY_FINISHED.
Gdy czekałem, aż adapter zakończy wykrywanie, wywołanie connect w gnieździe powiodło się.
źródło
Można umieścić
registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
z „Bluetooth” pisane „bleutooth”.źródło
W przypadku, gdy ktoś ma problemy z Kotlinem, musiałem postępować zgodnie z zaakceptowaną odpowiedzią z kilkoma wariacjami:
Mam nadzieję, że to pomoże
źródło
Urządzenia Bluetooth mogą działać jednocześnie w trybie klasycznym i LE. Czasami używają innego adresu MAC w zależności od tego, w jaki sposób się łączysz. Dzwonienie
socket.connect()
odbywa się za pomocą Bluetooth Classic, więc musisz upewnić się, że urządzenie, które otrzymałeś podczas skanowania, było naprawdę klasycznym urządzeniem.Łatwo jest jednak filtrować tylko dla urządzeń Classic, jednak:
if(BluetoothDevice.DEVICE_TYPE_LE == device.getType()){ //socket.connect() }
Bez tego sprawdzenia jest to warunek wyścigu, czy skanowanie hybrydowe da najpierw urządzenie Classic, czy BLE. Może się to wydawać jako sporadyczna niemożność połączenia lub jako że niektóre urządzenia są w stanie połączyć się niezawodnie, podczas gdy inne pozornie nigdy nie mogą.
źródło
też napotkałem ten problem, możesz go rozwiązać na dwa sposoby, jak wspomniano wcześniej użyj refleksji do stworzenia gniazda Po drugie, klient szuka serwera o podanym UUID i jeśli twój serwer nie działa równolegle do klienta, to dzieje się. Stwórz serwer o podanym UUID klienta, a następnie nasłuchuj i zaakceptuj klienta od strony serwera.
źródło
Natknąłem się na ten problem i naprawiłem go, zamykając strumienie wejściowe i wyjściowe przed zamknięciem gniazda. Teraz mogę się rozłączyć i połączyć ponownie bez żadnych problemów.
https://stackoverflow.com/a/3039807/5688612
W Kotlinie:
źródło
Jeśli inna część twojego kodu już nawiązała połączenie z tym samym gniazdem i UUID, pojawi się ten błąd.
źródło
Nawet ja miałem ten sam problem, w końcu zrozumiałem mój problem, próbowałem połączyć się z (poza zasięgiem) zasięgu zasięgu Bluetooth.
źródło
Miałem ten problem i rozwiązaniem było użycie specjalnego magicznego identyfikatora GUID.
Podejrzewam, że są to UUID, które działają:
Jednak nie wypróbowałem ich wszystkich.
źródło
Po dodaniu akcji filtrowania mój problem został rozwiązany
źródło
Otrzymałem również to samo
IOException
, ale znalazłem demo systemu Android: projekt "BluetoothChat" działa. Ustaliłem, że problemem jest UUID.Więc zamieniam
UUID.fromString("00001001-0000-1000-8000-00805F9B34FB")
naUUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")
i działało w większości scen, tylko czasami trzeba ponownie uruchomić urządzenie Bluetooth;źródło