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


100

В настоящее время я пытаюсь справиться со странным исключением при открытии 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?


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

Ответы:


129

Наконец-то я нашел обходной путь. Магия скрыта под капотом 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);
        }

    }
}

3
Вот Это Да! отличное решение!
Bobs

2
@MD Не знаю как. Я только что протестировал и обнаружил, что он работает.
Bobs

1
На nexus 4 не работает. Подскажите, пожалуйста, как решить эту проблему. Я почти все перепробовала. Спасибо.
Shah

3
@matthes Мне жаль, но даже ваше решение с использованием запасного варианта не решило мою проблему. Попадание ниже Ошибка. Fallback failed. Cancelling. java.io.IOException: Connection refused Пожалуйста помоги.
Tushar Banne

2
@matthes "В таких случаях помогает SPP-Device (отключение / подключение).". Заявление о включении / выключении является самым недооцененным в мире. Я просто потратил 3 часа впустую, и все, что мне нужно было сделать, это включить и выключить -_-
Adz

98

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

Проблема в socket.mPortпараметре. Когда вы создаете свой сокет using 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");
        }
    }

57
для модераторов: поскольку вы удалили мой предыдущий ответ без причины, я отправляю его снова.
Георгий Дима

2
Спасибо Джорджу за понимание этого mPortпараметра! imho рабочий процесс остается прежним, я просто обернул вещи некоторыми классами, реализующими интерфейс.
Matthes

5
да, я уже сказал, что ваше решение хорошее, но я хотел, чтобы люди поняли, почему нужно использовать этот подход, начиная с Android 4.2
Джордж Дима

2
SPP = профиль последовательного порта (который имитирует последовательный порт через bluetooth), а ELM327 - автомобильное устройство bluetooth <-> obd, погуглите.
Георгий Дима

10
Он сработал для меня после изменения значения порта с 1 на 2, посмотрите этот код. socket = (BluetoothSocket) device.getClass (). getMethod ("createRfcommSocket", новый класс [] {int.class}). invoke (устройство, 2); socket.connect ();
Dinesh IT

16

Во-первых, если вам нужно поговорить с устройством 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);
}

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


1
Это решило почти 2 дня работы ... благодарный вздох ... Без этого UUID сокет немедленно закроется и выйдет из строя без дополнительных объяснений.
Дэвид Синклер

Большое спасибо за помощь. МОЙ UUID является буквенно-цифровым, и я пытаюсь подключить HC-5, и мой Bluetooth показывает сбой подключения, но когда я использовал это решение, моя проблема решена. еще раз спасибо
Нихил Шенде

8

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

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


Спасибо, была та же проблема, только сейчас я подумал, что я не закрыл поток и соединение ...
Рафаэль

попробовал все вышеперечисленные сценарии (за исключением удаления других сопряженных устройств, это хорошо, что на самом деле не является решением, обнаруженным, что да ... это обычно происходит только тогда, когда входные потоки и сокеты не закрываются должным образом ... !!
Аман Сатия

7

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

Большинство людей, которые пытаются установить соединение с 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();работает отлично, без проблем. Я просто хотел поделиться этим, потому что эта ошибка действительно раздражает.

Удачи!


Это сработало на одном устройстве, где я столкнулся с этой проблемой, которая возникает у меня только на телефоне 5.0, и даже тогда только тогда, когда я сначала включаю BT, а затем открываю соединение. Если BT уже был включен, проблем с подключением нет! Этого не происходит на устройствах с более поздней версией Android, что говорит о том, что разработчики заметили ошибку и исправили ее, но на странице Android BT об этом нет ни слова. Но ваше решение работает, спасибо!
Джон Перри

7

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

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


6

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


4

Если у кого-то возникнут проблемы с 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()
            }
        }
    }
}

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


3

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

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

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

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


1

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


1

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

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

В Котлине:

fun disconnect() {
    bluetoothSocket.inputStream.close()
    bluetoothSocket.outputStream.close()
    bluetoothSocket.close()
}

1

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


0

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


0

У меня была эта проблема, и я решил использовать специальный волшебный 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

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


Даже использую тот же UUID. Но мне не помогло. Поддерживается ли это только для подключения к классическим устройствам Bluetooth (не BLE)? Что мне нужно сделать, чтобы подключиться к устройствам BLE с помощью Xamarin.Forms. Размещено здесь [ stackoverflow.com/questions/62371859/…
Шайлеш Бхат

Я использую классический Bluetooth; BLE - это чушь.
Ричард Барраклаф,

-1

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

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

-3

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.