В настоящее время я пытаюсь справиться со странным исключением при открытии BluetoothSocket на моем Nexus 7 (2012 г.) с Android 4.3 (сборка JWR66Y, я думаю, второе обновление 4.3). Я видел некоторые связанные сообщения (например, /programming/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), но ни одна из них, похоже, не предлагает обходного пути для этой проблемы. Кроме того, как предлагается в этих потоках, повторное сопряжение не помогает, и постоянные попытки подключения (через тупой цикл) также не имеют никакого эффекта.
Я имею дело со встроенным устройством (автомобильный адаптер noname OBD-II, аналогичный http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- LIGHTS-WITH-YOUR-PHONE-Oceanside.jpg ). У моего телефона Android 2.3.7 проблем с подключением нет, Xperia коллеги (Android 4.1.2) тоже работает. Другой Google Nexus (я не знаю, «One» или «S», но не «4») также не работает с Android 4.3.
Вот фрагмент установки соединения. Он работает в собственном потоке, созданном в рамках службы.
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;
}
}
Код не работает bluetoothSocket.connect()
. Я получаю java.io.IOException: read failed, socket might closed, read ret: -1
. Это соответствующий источник на GitHub: https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504 Он
вызывается через readInt (), вызывается из https : //github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319
Дамп некоторых метаданных используемого сокета привел к следующей информации. Они точно такие же на Nexus 7 и моем телефоне 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
У меня есть несколько других адаптеров OBD-II (более обширные), и все они работают. Есть ли шанс, что я что-то упускаю или это ошибка в Android?
Ответы:
Наконец-то я нашел обходной путь. Магия скрыта под капотом
BluetoothDevice
класса (см. Https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037 ).Теперь, когда я получаю это исключение, я создаю резервный вариант
BluetoothSocket
, аналогичный приведенному ниже исходному коду. Как видите, вызов скрытого методаcreateRfcommSocket
через отражения. Понятия не имею, почему этот метод скрыт. Исходный код определяет это какpublic
будто ...connect()
тогда больше не подводит. У меня все еще есть несколько проблем. По сути, это иногда блокирует и терпит неудачу. В таких случаях помогает перезагрузка SPP-устройства (отключение / подключение). Иногда я также получаю еще один запрос на сопряжениеconnect()
даже после того, как устройство уже подключено.ОБНОВИТЬ:
вот полный класс, содержащий несколько вложенных классов. для реальной реализации они могут проводиться как отдельные классы.
источник
Fallback failed. Cancelling. java.io.IOException: Connection refused
Пожалуйста помоги.ну, у меня была такая же проблема с моим кодом, и это потому, что с момента появления Android 4.2 стек bluetooth изменился. поэтому мой код отлично работал на устройствах с android <4.2, на других устройствах я получал известное исключение «ошибка чтения, сокет мог быть закрыт или тайм-аут, прочтите ret: -1»
Проблема в
socket.mPort
параметре. Когда вы создаете свой сокет usingsocket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
, онmPort
получает целочисленное значение « -1 », и это значение, похоже, не работает для android> = 4.2, поэтому вам нужно установить его на « 1 ». Плохая новость заключается в том, что вcreateRfcommSocketToServiceRecord
качестве параметра принимается только UUID,mPort
поэтому нам не нужно использовать другой подход. Ответ, отправленный @matthes, также сработал для меня, но я упростил его:socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);
. Нам нужно использовать оба атрибута сокета, второй как запасной вариант.Итак, код (для подключения к SPP на устройстве ELM327):
источник
mPort
параметра! imho рабочий процесс остается прежним, я просто обернул вещи некоторыми классами, реализующими интерфейс.Во-первых, если вам нужно поговорить с устройством bluetooth 2.x, в этой документации указано, что:
Не думал, что это сработает, а только с заменой UUID на
00001101-0000-1000-8000-00805F9B34FB
него работает. Однако этот код, похоже, решает проблему версии SDK, и вы можете просто заменить функциюdevice.createRfcommSocketToServiceRecord(mMyUuid);
наtmp = createBluetoothSocket(mmDevice);
после определения следующего метода:Исходный код не мой, а взят с этого сайта .
источник
У меня были те же симптомы, что описаны здесь. Я мог один раз подключиться к принтеру bluetooth, но последующие подключения не удались с «закрытием сокета», что бы я ни делал.
Мне показалось немного странным, что могут потребоваться описанные здесь обходные пути. Пройдя свой код, я обнаружил, что забыл закрыть InputStream и OutputSteram сокета и не завершил ConnectedThreads должным образом.
ConnectedThread, который я использую, такой же, как в примере здесь:
http://developer.android.com/guide/topics/connectivity/bluetooth.html
Обратите внимание, что ConnectThread и ConnectedThread - это два разных класса.
Какой бы класс ни запускал ConnectedThread, он должен вызывать interrupt () и cancel () в потоке. Я добавил mmInStream.close () и mmOutStream.close () в метод ConnectedTread.cancel ().
После правильного закрытия потоков / потоков / сокетов я мог без проблем создавать новые сокеты.
источник
Что ж, я действительно нашел проблему.
Большинство людей, которые пытаются установить соединение с
socket.Connect();
помощью, вызывают исключениеJava.IO.IOException: read failed, socket might closed, read ret: -1
.В некоторых случаях это также зависит от вашего устройства Bluetooth, потому что существует два разных типа Bluetooth, а именно BLE (с низким энергопотреблением) и классический.
Если вы хотите проверить тип вашего устройства Bluetooth, вот код:
Я уже несколько дней пытаюсь решить проблему, но с сегодняшнего дня я нашел проблему. Решение от @matthes, к сожалению, все еще имеет несколько проблем, как он уже сказал, но вот мое решение.
На данный момент я работаю в Xamarin Android, но это должно работать и на других платформах.
РЕШЕНИЕ
Если есть более одного сопряженного устройства, вам следует удалить другие сопряженные устройства. Поэтому оставьте только тот, который хотите подключить (см. Изображение справа).
На левом изображении вы видите, что у меня есть два сопряженных устройства, а именно «MOCUTE-032_B52-CA7E» и «Blue Easy». Это проблема, но я понятия не имею, почему возникает эта проблема. Возможно, протокол Bluetooth пытается получить информацию от другого устройства Bluetooth.
Однако сейчас
socket.Connect();
работает отлично, без проблем. Я просто хотел поделиться этим, потому что эта ошибка действительно раздражает.Удачи!
источник
В более новых версиях Android я получал эту ошибку, потому что адаптер все еще обнаруживал, когда я пытался подключиться к сокету. Несмотря на то, что я вызвал метод cancelDiscovery на адаптере Bluetooth, мне пришлось ждать, пока не будет вызван обратный вызов метода onReceive () BroadcastReceiver с действием BluetoothAdapter.ACTION_DISCOVERY_FINISHED.
Как только я дождался, пока адаптер прекратит обнаружение, вызов подключения к сокету завершился успешно.
источник
Вы ставите
registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
с "bluetooth" пишется "bleutooth".источник
Если у кого-то возникнут проблемы с Kotlin, мне пришлось следовать принятому ответу с некоторыми вариациями:
Надеюсь, поможет
источник
Устройства Bluetooth могут работать как в классическом, так и в LE-режиме одновременно. Иногда они используют другой MAC-адрес в зависимости от того, каким способом вы подключаетесь. Вызов
socket.connect()
осуществляется с помощью Bluetooth Classic, поэтому вы должны убедиться, что устройство, которое вы получили при сканировании, действительно было классическим устройством.Однако легко отфильтровать только классические устройства:
if(BluetoothDevice.DEVICE_TYPE_LE == device.getType()){ //socket.connect() }
Без этой проверки возникает состязание по поводу того, даст ли гибридное сканирование сначала классическое устройство или устройство BLE. Это может проявляться как периодическая неспособность подключиться или как определенные устройства могут подключаться надежно, в то время как другие, казалось бы, никогда не могут.
источник
Я также столкнулся с этой проблемой, вы можете решить ее двумя способами, как упоминалось ранее, используйте отражение для создания сокета Второй: клиент ищет сервер с заданным UUID, и если ваш сервер не работает параллельно с клиентом, тогда это бывает. Создайте сервер с заданным UUID клиента, а затем слушайте и принимайте клиента со стороны сервера. Это будет работать.
источник
Я столкнулся с этой проблемой и исправил ее, закрыв потоки ввода и вывода перед закрытием сокета. Теперь я могу отключиться и снова подключиться без проблем.
https://stackoverflow.com/a/3039807/5688612
В Котлине:
источник
Если другая часть вашего кода уже установила соединение с тем же сокетом и UUID, вы получите эту ошибку.
источник
Даже у меня была такая же проблема, я, наконец, понял свою проблему, я пытался подключиться из (вне диапазона) зоны покрытия Bluetooth.
источник
У меня была эта проблема, и я решил использовать специальный волшебный GUID.
Я подозреваю, что это те UUID, которые работают:
Однако я не пробовал их все.
источник
Добавив действие фильтра, моя проблема решена
источник
Я тоже получил то же самое
IOException
, но нахожу демонстрацию системы Android: проект «BluetoothChat» работает. Я определил, что проблема в UUID.Поэтому я заменил свой
UUID.fromString("00001001-0000-1000-8000-00805F9B34FB")
на,UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")
и он работал в большинстве сцен, только иногда нужно перезапускать устройство Bluetooth;источник