IOException: ошибка чтения, возможно, сокет закрыт - Bluetooth на Android 4.3

В настоящее время я пытаюсь справиться со странным исключением при открытии BluetoothSocket на моем Nexus 7 (2012 г.) с Android 4.3 (сборка JWR66Y, я думаю, второе обновление 4.3). Я видел несколько связанных сообщений (например, https://stackoverflow.com/questions/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?


person matthes    schedule 06.09.2013    source источник
comment
Я пробовал вышеуказанное решение, может ли кто-нибудь помочь в этом вопросе stackoverflow.com/q/52105647/1559331   -  person dileepVikram    schedule 31.08.2018


Ответы (16)


Наконец-то я нашел обходной путь. Магия скрыта под капотом класса BluetoothDevice (см. https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037).

Теперь, когда я получаю это исключение, я создаю резервный экземпляр BluetoothSocket, аналогичный приведенному ниже исходному коду. Как видите, вызов скрытого метода createRfcommSocket через отражения. Понятия не имею, почему этот метод скрыт. Исходный код определяет это как 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() больше не терпит неудач. У меня все еще есть несколько проблем. По сути, это иногда блокирует и терпит неудачу. В таких случаях помогает перезагрузка SPP-устройства (отключение / подключение). Иногда я также получаю еще один запрос на сопряжение после connect(), даже если устройство уже подключено.

ОБНОВИТЬ:

вот полный класс, содержащий несколько вложенных классов. для реальной реализации они могут проводиться как отдельные классы.

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

    }
}
person matthes    schedule 13.09.2013
comment
Если вы хотите подключиться к нескольким устройствам bluetooth, помните, что вам нужно увеличить номер канала. Допустимые каналы: 1–30. - person Jonno_FTW; 27.10.2014
comment
@MD Не знаю как. Я только что протестировал и обнаружил, что он работает. - person Bobs; 09.02.2015
comment
Привет! Как вы использовали этот код для подключения? Подскажите, пожалуйста - person bindal; 26.02.2015
comment
На nexus 4 не работает. Подскажите, пожалуйста, как решить эту проблему. Я почти все перепробовала. Спасибо. - person Shah; 27.02.2015
comment
Спасибо @matthes .. вы решили мой вопрос stackoverflow.com/q/29143695/1994950 Я упомянул ваш ответ там - person Kushal; 04.04.2015
comment
@matthes, как пользоваться классом BluetoothConnector? Заменяет ли он класс BluetoothSocket? Спасибо. - person The Original Android; 13.01.2016
comment
Спасибо за объяснение, я очень новичок в bluetooth, поскольку я пытаюсь это сделать в своем коде, но он показывает IOException: ошибка чтения, сокет может быть закрыт в @ fallbackSocket.connect (); Пожалуйста, помогите мне. Если возможно, вы можете прислать мне код для отправителя и получателя. - person Mukesh Garg; 20.01.2016
comment
@matthes Мне жаль, но даже ваше решение с использованием запасного варианта не решило мою проблему. Попадание ниже Ошибка. Fallback failed. Cancelling. java.io.IOException: Connection refused Помогите, пожалуйста. - person Tushar Banne; 17.02.2016
comment
@matthes SPP-Device (отключение / подключение) помогает в таких случаях. . Заявление о включении / выключении является самым недооцененным в мире. Я просто зря потратил 3 часа, и все, что мне нужно было сделать, это включить и выключить -_- - person Adz; 25.02.2016
comment
Спасибо @matthes - person Piyush Malaviya; 31.08.2016
comment
Когда я пытаюсь написать int BluetoothSocketWrapper getOutputStream (), я получаю исключение java.io.IOException: socket closed. - person Madhan; 12.10.2016
comment
@matthes: Как использовать этот класс BluetoothConnector? - person Pragya Mendiratta; 31.01.2018
comment
@matthes, большое спасибо за эту идею (и источник), я не знаю, как вы пришли к этой идее, но вы потрясающий. Работает как надо :) Кстати - нормальный способ настройки bluetooth работал, пока я обновил проект с API 21 до 24. Может, этот намек проливает свет на то, что именно здесь происходит ... - person michelson; 13.06.2018
comment
Это также работает для меня, но я хотел бы спросить, если я хочу закрыть соединение из другого метода, должен ли я снова вызвать конструктор? - person John; 27.03.2020
comment
Если это решение не работает, попробуйте заменить 1 на 2. Я заменил Object [] params = new Object [] {Integer.valueOf (1)}; с: Object [] params = new Object [] {Integer.valueOf (2)}; и теперь он работает. - person Umama Khalid; 22.02.2021

ну, у меня была такая же проблема с моим кодом, потому что с момента обновления Android 4.2 стек bluetooth изменился. так что мой код работал нормально на устройствах с android ‹4.2, на других устройствах я получал известное исключение « ошибка чтения, сокет мог быть закрыт или тайм-аут, прочтите ret: -1 »

Проблема с параметром socket.mPort. Когда вы создаете сокет с помощью socket = 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):

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");
        }
    }
person George Dima    schedule 03.09.2014
comment
для модераторов: поскольку вы без всякой причины удалили мой предыдущий ответ, я отправляю его еще раз. - person George Dima; 03.09.2014
comment
Спасибо Джорджу за понимание параметра mPort! imho рабочий процесс остается прежним, я просто обернул вещи некоторыми классами, реализующими интерфейс. - person matthes; 04.09.2014
comment
да, я уже сказал, что ваше решение хорошее, но я хотел, чтобы люди поняли, почему нужно использовать этот подход, начиная с Android 4.2. - person George Dima; 04.09.2014
comment
Это не работает. :( Я использовал его в Samsung Galaxy S2 (Android 4.1.2) в качестве сервера и в Samsung Galaxy S3 (Android 4.3) в качестве клиента, предварительно обнаружив друг друга. Смена ролей также не работает. - person jsanmarb; 11.09.2014
comment
ну а точнее какая у тебя ошибка? Прежде всего, вам не нужно это резервное решение, так как вы находитесь в Android 4.1, какую службу bluetooth вы используете, мой пример для SPP - person George Dima; 12.09.2014
comment
что такое SPP и ELM327? - person An-droid; 06.02.2015
comment
SPP = профиль последовательного порта (который имитирует последовательный порт через bluetooth), а ELM327 - автомобильное устройство bluetooth ‹-› obd, погуглите. - person George Dima; 06.02.2015
comment
@GeorgeDima .. Не могли бы вы рассказать, почему этот подход работает? Также, почему socket.connect () терпит неудачу, я хотел бы знать, как человек, который подумал и нашел первое решение, подумал и пришел к этому ответу. - person Sreekanth Karumanaghat; 25.03.2015
comment
Я знаю это потому, что с тех пор, как стек bluetooth для Android 4.2 изменился, я не создатель ОС Android, чтобы узнать больше ... - person George Dima; 25.03.2015
comment
@GeorgeDima ... На откате почему работает метод отражения? Если возможно, предоставьте мне дополнительную информацию. - person Sreekanth Karumanaghat; 26.03.2015
comment
я уже объяснил в своем посте! (mPort получает целочисленное значение -1, и это значение, похоже, не работает для android ›= 4.2, поэтому вам нужно установить его на 1), поэтому резервные методы позволяют вам установить mport на 1, а не метод по умолчанию с наборами это до -1. - person George Dima; 26.03.2015
comment
Он сработал для меня после изменения значения порта с 1 на 2, посмотрите этот код. socket = (BluetoothSocket) device.getClass (). getMethod (createRfcommSocket, новый класс [] {int.class}). invoke (устройство, 2); socket.connect (); - person Dinesh IT; 09.07.2015
comment
Спасибо за все комментарии выше и опубликованный ответ. 1 не работал у меня .. socket = (BluetoothSocket) device.getClass (). GetMethod (createRfcommSocket, new Class [] {int.class}). Invoke (device, 2); socket.connect (); .. Его отображение теперь подключено. Не могли бы вы помочь мне со средствами приема данных, как я буду получать данные. - person Mukesh Garg; 20.01.2016
comment
как сделать откат, если вы изначально получили сокет через серверный сокет? - person Fuad; 19.05.2016
comment
Не работает с устройствами BLE, пожалуйста, помогите мне, я попробовал 1 и 2 оба. - person chetan; 07.03.2017
comment
Привет, Джордж, большое спасибо! На поиск в Интернете у меня ушло несколько часов, и ваше решение работает! - person Sentimental; 17.12.2017
comment
Привет, Джордж, я пробовал использовать оба значения: 1 и 2, но все равно не удалось прочитать одно и то же исключение, сокет может быть закрыт или тайм-аут, прочтите ret: -1. . .plz, помогите мне - person Nirmal Prajapat; 01.02.2018
comment
Приведенное выше решение по-прежнему дает ту же ошибку. И поскольку @NirmalPrajapat пробовал оба значения, я все еще вижу такое же поведение. Даже в Android 7.0. Это признак того, что Android просто сломан? Или все две дюжины разных устройств, которые я пробовал, сломаны? - person Logic1; 04.03.2018
comment
Спасибо за объяснение @DineshIT Спасибо за комментарий, изменение порта на 2 сработало для меня, где вы обдумываете эту идею - person dileepVikram; 29.08.2018
comment
Я пробовал вышеуказанное решение, может ли кто-нибудь помочь в этом вопросе stackoverflow.com/q/52105647/1559331 - person dileepVikram; 31.08.2018
comment
Я получаю NullPointerException на socket.connect() при попытке реализовать это - person ChumiestBucket; 28.09.2018

Во-первых, если вам нужно поговорить с устройством bluetooth 2.x, в этой документации говорится, что:

Подсказка: если вы подключаетесь к плате последовательного интерфейса Bluetooth, попробуйте использовать хорошо известный SPP UUID 00001101-0000-1000-8000-00805F9B34FB. Однако, если вы подключаетесь к одноранговому узлу Android, создайте свой собственный уникальный UUID.

Не думал, что сработает, но только при замене UUID на 00001101-0000-1000-8000-00805F9B34FB работает. Однако этот код, похоже, решает проблему версии SDK, и вы можете просто заменить функцию device.createRfcommSocketToServiceRecord(mMyUuid); на tmp = createBluetoothSocket(mmDevice); после определения следующего метода:

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

Исходный код не мой, а взят с этого веб-сайта < / а>.

person tobiasBora    schedule 13.01.2017
comment
Это решило почти 2 дня работы ... благодарный вздох ... Без этого UUID сокет немедленно закроется и выйдет из строя без дополнительных объяснений. - person David Sinclair; 17.07.2017
comment
Большое спасибо за помощь. МОЙ UUID является буквенно-цифровым, и я пытаюсь подключить HC-5, и мой Bluetooth показывает сбой подключения, но когда я использовал это решение, моя проблема решена. еще раз спасибо - person Nikhil Shende; 04.02.2020

У меня были те же симптомы, что и здесь. Я мог один раз подключиться к принтеру 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 ().

После правильного закрытия потоков / потоков / сокетов я мог без проблем создавать новые сокеты.

person Daniel T    schedule 21.12.2014
comment
Спасибо, была такая же проблема, только сейчас я подумал, что я не закрыл поток и соединение ... - person Rafael; 19.05.2017
comment
попробовал все вышеперечисленные сценарии (за исключением удаления других сопряженных устройств, это хорошо, что на самом деле не является решением, обнаруженным, что да ... это обычно происходит только тогда, когда входные потоки и сокеты не закрываются должным образом ... !! - person Aman Satija; 14.05.2019

Что ж, я действительно нашел проблему.

Большинство людей, пытающихся установить соединение с помощью socket.Connect();, получают исключение под названием Java.IO.IOException: read failed, socket might closed, read ret: -1.

В некоторых случаях это также зависит от вашего устройства Bluetooth, потому что существует два разных типа Bluetooth, а именно BLE (с низким энергопотреблением) и классический.

Если вы хотите проверить тип вашего устройства Bluetooth, вот код:

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

Я уже несколько дней пытаюсь решить проблему, но с сегодняшнего дня я нашел проблему. Решение от @matthes, к сожалению, по-прежнему имеет несколько проблем, как он уже сказал, но вот мое решение.

В настоящий момент я работаю в Xamarin Android, но это должно работать и на других платформах.

РЕШЕНИЕ

Если есть несколько сопряженных устройств, вам следует удалить другие сопряженные устройства. Поэтому оставьте только тот, который хотите подключить (см. Изображение справа).

введите здесь описание изображения  введите описание изображения здесь

На левом изображении вы видите, что у меня есть два сопряженных устройства, а именно «MOCUTE-032_B52-CA7E» и «Blue Easy». Это проблема, но я понятия не имею, почему она возникает. Возможно, протокол Bluetooth пытается получить информацию от другого устройства Bluetooth.

Однако сейчас socket.Connect(); отлично работает, без каких-либо проблем. Я просто хотел поделиться этим, потому что эта ошибка действительно раздражает.

Удачи!

person Jamie    schedule 04.04.2016
comment
Это сработало на одном устройстве, на котором я столкнулся с этой проблемой, которая возникает у меня только на телефоне 5.0, и даже тогда, когда я сначала включаю BT, а затем открываю соединение. Если бы BT уже был включен, проблем с подключением нет! Этого не происходит на устройствах с более поздней версией Android, что говорит о том, что разработчики заметили ошибку и исправили ее, но на странице Android BT об этом нет ни слова. Но ваше решение работает, спасибо! - person John Perry; 08.09.2017

В более новых версиях Android я получал эту ошибку, потому что адаптер все еще обнаруживал, когда я пытался подключиться к сокету. Несмотря на то, что я вызвал метод cancelDiscovery на адаптере Bluetooth, мне пришлось ждать, пока не будет вызван обратный вызов метода onReceive () BroadcastReceiver с действием BluetoothAdapter.ACTION_DISCOVERY_FINISHED.

Как только я дождался, пока адаптер прекратит обнаружение, вызов подключения к сокету завершился успешно.

person kmac.mcfarlane    schedule 19.12.2016

Вы ставите registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID")); с "bluetooth" пишется "bleutooth".

person Fizz Binn    schedule 24.04.2015

Если у кого-то возникли проблемы с Kotlin, мне пришлось следовать принятому ответу с некоторыми вариациями:

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

Надеюсь, поможет

person Santiago Martí Olbrich    schedule 14.03.2018

Устройства Bluetooth могут одновременно работать как в классическом, так и в LE режиме. Иногда они используют другой MAC-адрес в зависимости от того, каким способом вы подключаетесь. При вызове socket.connect() используется классический Bluetooth, поэтому вы должны убедиться, что устройство, которое вы получили при сканировании, действительно было классическим устройством.

Однако легко отфильтровать только классические устройства:

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

Без этой проверки возникает состязание относительно того, даст ли гибридное сканирование сначала классическое устройство или устройство BLE. Это может проявляться как периодическая неспособность подключиться или как некоторые устройства могут надежно подключиться, в то время как другие, по-видимому, никогда не смогут.

person kmac.mcfarlane    schedule 17.11.2017

Я также столкнулся с этой проблемой, вы можете решить ее двумя способами, как упоминалось ранее, используйте отражение для создания сокета Второй: клиент ищет сервер с заданным UUID, и если ваш сервер не работает параллельно с клиентом, тогда это бывает. Создайте сервер с заданным UUID клиента, а затем слушайте и принимайте клиента со стороны сервера. Это будет работать.

person ireshika piyumalie    schedule 24.06.2016

Даже у меня была такая же проблема, я, наконец, понял мою проблему, я пытался подключиться из (вне диапазона) покрытия Bluetooth.

person krishnamurthy    schedule 21.06.2018

Я столкнулся с этой проблемой и решил ее, закрыв потоки ввода и вывода перед закрытием сокета. Теперь я могу отключиться и снова подключиться без проблем.

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

В Котлине:

fun disconnect() {
    bluetoothSocket.inputStream.close()
    bluetoothSocket.outputStream.close()
    bluetoothSocket.close()
}
person TheoKanning    schedule 24.02.2019

Если другая часть вашего кода уже установила соединение с тем же сокетом и UUID, вы получите эту ошибку.

person user1725145    schedule 27.06.2019
comment
а если я отключусь от этого сокета и попытаюсь подключиться снова? - person Владимир Фишер; 23.06.2021
comment
Конечно, это сработает, но в моем случае это потребовало изменения архитектуры, поскольку другой модуль мне не принадлежал! - person user1725145; 24.06.2021

У меня была эта проблема, и я решил использовать специальный волшебный GUID.

            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.

Я подозреваю, что это те UUID, которые работают:

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

Однако я не пробовал их все.

person Richard Barraclough    schedule 09.06.2020
comment
Даже использую тот же UUID. Но мне не помогло. Поддерживается ли это только для подключения к классическим устройствам bluetooth (не BLE)? Что мне нужно сделать, чтобы подключиться к устройствам BLE с помощью Xamarin.Forms. Размещено здесь [stackoverflow.com/questions/62371859/ - person Shailesh Bhat; 18.06.2020
comment
Я использую классический Bluetooth; BLE - это чушь. - person Richard Barraclough; 18.06.2020

Добавив действие фильтра, моя проблема решена

 // 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);
person Vinod Ranga    schedule 17.06.2019

Я тоже получил тот же IOException, но нахожу демонстрацию системы Android: проект «BluetoothChat» работает. Я определил, что проблема в UUID.

Поэтому я заменил свой UUID.fromString("00001001-0000-1000-8000-00805F9B34FB") на UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66"), и он работал в большинстве сцен, только иногда нужно перезапускать устройство Bluetooth;

person taotao    schedule 10.08.2014