IOException: falha de leitura, soquete pode ser fechado - Bluetooth no Android 4.3

100

Atualmente estou tentando lidar com uma estranha exceção ao abrir um BluetoothSocket no meu Nexus 7 (2012), com Android 4.3 (Build JWR66Y, acho que a segunda atualização 4.3). Eu vi algumas postagens relacionadas (por exemplo, /programming/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), mas nenhuma parece fornecer uma solução alternativa para esse problema. Além disso, como sugerido nesses tópicos, o reemparelhamento não ajuda e tentar conectar-se constantemente (por meio de um loop estúpido) também não tem efeito.

Estou lidando com um dispositivo incorporado (um adaptador de carro OBD-II sem nome, semelhante a http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- LUZES-COM-SEU-TELEFONE-Oceanside.jpg ). Meu telefone Android 2.3.7 não tem problemas de conexão e o Xperia de um colega (Android 4.1.2) também funciona. Outro Google Nexus (não sei se 'One' ou 'S', mas não '4') também falha com o Android 4.3.

Aqui está o snippet do estabelecimento da conexão. Ele está rodando em seu próprio Thread, criado dentro de um Service.

private class ConnectThread extends Thread {

    private static final UUID EMBEDDED_BOARD_SPP = UUID
        .fromString("00001101-0000-1000-8000-00805F9B34FB");

    private BluetoothAdapter adapter;
    private boolean secure;
    private BluetoothDevice device;
    private List<UUID> uuidCandidates;
    private int candidate;
    protected boolean started;

    public ConnectThread(BluetoothDevice device, boolean secure) {
        logger.info("initiliasing connection to device "+device.getName() +" / "+ device.getAddress());
        adapter = BluetoothAdapter.getDefaultAdapter();
        this.secure = secure;
        this.device = device;

        setName("BluetoothConnectThread");

        if (!startQueryingForUUIDs()) {
            this.uuidCandidates = Collections.singletonList(EMBEDDED_BOARD_SPP);
            this.start();
        } else{
            logger.info("Using UUID discovery mechanism.");
        }
        /*
         * it will start upon the broadcast receive otherwise
         */
    }

    private boolean startQueryingForUUIDs() {
        Class<?> cl = BluetoothDevice.class;

        Class<?>[] par = {};
        Method fetchUuidsWithSdpMethod;
        try {
            fetchUuidsWithSdpMethod = cl.getMethod("fetchUuidsWithSdp", par);
        } catch (NoSuchMethodException e) {
            logger.warn(e.getMessage());
            return false;
        }

        Object[] args = {};
        try {
            BroadcastReceiver receiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    BluetoothDevice deviceExtra = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
                    Parcelable[] uuidExtra = intent.getParcelableArrayExtra("android.bluetooth.device.extra.UUID");

                    uuidCandidates = new ArrayList<UUID>();
                    for (Parcelable uuid : uuidExtra) {
                        uuidCandidates.add(UUID.fromString(uuid.toString()));
                    }

                    synchronized (ConnectThread.this) {
                        if (!ConnectThread.this.started) {
                            ConnectThread.this.start();
                            ConnectThread.this.started = true;
                            unregisterReceiver(this);
                        }

                    }
                }

            };
            registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
            registerReceiver(receiver, new IntentFilter("android.bluetooth.device.action.UUID"));

            fetchUuidsWithSdpMethod.invoke(device, args);
        } catch (IllegalArgumentException e) {
            logger.warn(e.getMessage());
            return false;
        } catch (IllegalAccessException e) {
            logger.warn(e.getMessage());
            return false;
        } catch (InvocationTargetException e) {
            logger.warn(e.getMessage());
            return false;
        }           

        return true;
    }

    public void run() {
        boolean success = false;
        while (selectSocket()) {

            if (bluetoothSocket == null) {
                logger.warn("Socket is null! Cancelling!");
                deviceDisconnected();
                openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
            }

            // Always cancel discovery because it will slow down a connection
            adapter.cancelDiscovery();

            // Make a connection to the BluetoothSocket
            try {
                // This is a blocking call and will only return on a
                // successful connection or an exception
                bluetoothSocket.connect();
                success = true;
                break;

            } catch (IOException e) {
                // Close the socket
                try {
                    shutdownSocket();
                } catch (IOException e2) {
                    logger.warn(e2.getMessage(), e2);
                }
            }
        }

        if (success) {
            deviceConnected();
        } else {
            deviceDisconnected();
            openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
        }
    }

    private boolean selectSocket() {
        if (candidate >= uuidCandidates.size()) {
            return false;
        }

        BluetoothSocket tmp;
        UUID uuid = uuidCandidates.get(candidate++);
        logger.info("Attempting to connect to SDP "+ uuid);
        try {
            if (secure) {
                tmp = device.createRfcommSocketToServiceRecord(
                        uuid);
            } else {
                tmp = device.createInsecureRfcommSocketToServiceRecord(
                        uuid);
            }
            bluetoothSocket = tmp;
            return true;
        } catch (IOException e) {
            logger.warn(e.getMessage() ,e);
        }

        return false;
    }

}

O código está falhando bluetoothSocket.connect(). Estou recebendo um java.io.IOException: read failed, socket might closed, read ret: -1. Esta é a fonte correspondente no GitHub: https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504 É chamado por readInt (), chamado de https : //github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319

Algum despejo de metadados do soquete usado resultou nas seguintes informações. Eles são exatamente iguais no Nexus 7 e no meu telefone 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

Eu tenho alguns outros adaptadores OBD-II (mais expansivos) e todos eles funcionam. Existe alguma chance de estar faltando alguma coisa ou pode ser um bug no Android?

Mateus
fonte
Eu tentei a solução acima, alguém pode ajudar neste problema stackoverflow.com/q/52105647/1559331
dileepVikram

Respostas:

129

Finalmente encontrei uma solução alternativa. A magia está escondida sob o capô da BluetoothDeviceclasse (consulte https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037 ).

Agora, quando recebo essa exceção, instanciamos um fallback BluetoothSocket, semelhante ao código-fonte abaixo. Como você pode ver, invocando o método oculto createRfcommSocketpor meio de reflexões. Não tenho ideia de por que esse método está oculto. O código-fonte define como publicse ...

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()então não falha mais. Eu ainda tive alguns problemas. Basicamente, isso às vezes bloqueia e falha. Reinicializar o dispositivo SPP (plug off / plug in) ajuda nesses casos. Às vezes, também recebo outra solicitação de emparelhamento connect()mesmo quando o dispositivo já está vinculado.

ATUALIZAR:

aqui está uma classe completa, contendo algumas classes aninhadas. para uma implementação real, eles podem ser mantidos como classes separadas.

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

    }
}
Mateus
fonte
3
Uau! ótima solução!
Bobs de
2
@MD não sei como. Acabei de testar e descobri que está funcionando.
Bobs de
1
Não funciona no nexo 4. você pode por favor dizer como superar este problema. Quase tentei de tudo. Obrigado.
Shah
3
@matthes Desculpe dizer, mas mesmo sua solução de usar o fallback não resolveu meu problema. Ficando abaixo do erro. Fallback failed. Cancelling. java.io.IOException: Connection refused Por favor ajude.
Tushar Banne
2
@matthes "SPP-Device (plug off / plug in) ajuda nesses casos.". A instrução liga / desliga é a mais subestimada do mundo. Eu acabei de perder 3 horas e tudo que eu tive que fazer foi ligar e desligar -_-
Adz
98

bem, eu tive o mesmo problema com meu código, e é porque desde o Android 4.2 pilha bluetooth mudou. então meu código estava funcionando bem em dispositivos com android <4.2, nos outros dispositivos eu estava recebendo a famosa exceção "falha de leitura, soquete pode ser fechado ou tempo limite, leia ret: -1"

O problema é com o socket.mPortparâmetro. Quando você cria seu soquete usando socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);, mPortobtém o valor inteiro " -1 ", e esse valor parece não funcionar para android> = 4.2, então você precisa defini-lo como " 1 ". A má notícia é que createRfcommSocketToServiceRecordsó aceita UUID como parâmetro e não mPortpor isso temos que usar outra abordagem. A resposta postado por @matthes também trabalharam para mim, mas eu simplificado-lo: socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);. Precisamos usar ambos os atributos de socket, o segundo como fallback.

Portanto, o código é (para conectar a um SPP em um dispositivo 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");
        }
    }
George Dima
fonte
57
para moderadores: como você excluiu minha resposta anterior sem motivo, eu a postarei novamente.
George Dima
2
obrigado George pelos insights sobre o mPortparâmetro! imho o fluxo de trabalho permanece o mesmo, acabei de embrulhar as coisas com algumas classes implementando uma interface.
Mateus
5
sim, eu já disse que sua solução era boa, mas queria que as pessoas entendessem por que é necessário usar essa abordagem a partir do android 4.2
George Dima
2
SPP = Perfil de porta serial (que emula uma porta serial sobre bluetooth) e ELM327 é um dispositivo bluetooth <-> obd para carro, faça um google.
George Dima
10
Funcionou para mim depois de alterar o valor da porta de 1 para 2. por favor, olhe este código. socket = (BluetoothSocket) device.getClass (). getMethod ("createRfcommSocket", new Class [] {int.class}). invoke (device, 2); socket.connect ();
Dinesh IT
16

Primeiro, se você precisar falar com um dispositivo bluetooth 2.x, esta documentação afirma que:

Dica: se você estiver se conectando a uma placa serial Bluetooth, tente usar o conhecido SPP UUID 00001101-0000-1000-8000-00805F9B34FB . No entanto, se você estiver se conectando a um par Android, gere seu próprio UUID exclusivo.

Não achei que fosse funcionar, mas apenas substituindo o UUID por 00001101-0000-1000-8000-00805F9B34FBele funciona. No entanto, este código parece lidar com o problema da versão do SDK, e você pode simplesmente substituir a função device.createRfcommSocketToServiceRecord(mMyUuid);por tmp = createBluetoothSocket(mmDevice);após definir o seguinte método:

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

O código-fonte não é meu, mas vem deste site .

TobiasBora
fonte
1
Isso resolveu quase 2 dias de trabalho ... suspiro agradecido ... Sem esse UUID o soquete fecharia imediatamente e falharia sem maiores explicações.
David Sinclair
muito obrigado pela ajuda MY UUID é alfanumérico e estou tentando conectar o HC-5 e meu bluetooth mostrando falha na conexão, mas quando usei essa solução meu problema resolveu. obrigado novamente
Nikhil Shende
8

Tive os mesmos sintomas descritos aqui. Pude conectar uma vez a uma impressora bluetooth, mas as conexões subsequentes falharam com "soquete fechado", não importa o que eu fiz.

Achei um pouco estranho que as soluções alternativas descritas aqui fossem necessárias. Depois de examinar meu código, descobri que havia esquecido de fechar o InputStream e o OutputSteram do soquete e não finalizei o ConnectedThreads corretamente.

O ConnectedThread que uso é o mesmo do exemplo aqui:

http://developer.android.com/guide/topics/connectivity/bluetooth.html

Observe que ConnectThread e ConnectedThread são duas classes diferentes.

Qualquer classe que iniciar o ConnectedThread deve chamar interrupt () e cancel () no thread. Adicionei mmInStream.close () e mmOutStream.close () ao método ConnectedTread.cancel ().

Depois de fechar os threads / streams / sockets corretamente eu poderia criar novos sockets sem nenhum problema.

Daniel T
fonte
Obrigado, estava com o mesmo problema, só agora percebi que não tinha fechado o stream e a conexão ...
Rafael
tentei todos os cenários acima, (exceto para remover outros dispositivos emparelhados causa bem que realmente não é uma solução encontrada que sim ... isso normalmente só acontece quando os fluxos de entrada e os soquetes não fecham corretamente ... !!
Aman Satija
7

Bem, eu realmente encontrei o problema.

A maioria das pessoas que tenta fazer uma conexão usando socket.Connect();uma exceção é chamada Java.IO.IOException: read failed, socket might closed, read ret: -1.

Em alguns casos, também depende do seu dispositivo Bluetooth, porque existem dois tipos diferentes de Bluetooth, nomeadamente BLE (baixa energia) e Classic.

Se você deseja verificar o tipo de seu dispositivo Bluetooth, este é o código:

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

Há dias tento resolver o problema, mas desde hoje encontrei o problema. A solução de @matthes infelizmente ainda tem alguns problemas como ele já disse, mas aqui está minha solução.

No momento eu trabalho no Xamarin Android, mas também deve funcionar para outras plataformas.

SOLUÇÃO

Se houver mais de um dispositivo emparelhado, você deve remover os outros dispositivos emparelhados. Portanto, mantenha apenas aquele que deseja conectar (veja a imagem certa).

insira a descrição da imagem aqui insira a descrição da imagem aqui

Na imagem à esquerda, você vê que tenho dois dispositivos emparelhados, ou seja, "MOCUTE-032_B52-CA7E" e "Blue Easy". Esse é o problema, mas não tenho ideia de por que esse problema ocorre. Talvez o protocolo Bluetooth esteja tentando obter algumas informações de outro dispositivo Bluetooth.

No entanto, socket.Connect();funciona muito bem agora, sem problemas. Então, eu só queria compartilhar isso, porque esse erro é realmente irritante.

Boa sorte!

Jamie
fonte
Isso funcionou no único dispositivo em que encontro esse problema, que só ocorre em um telefone 5.0 e, mesmo assim, apenas quando estou habilitando o BT e, em seguida, abrindo uma conexão. Se o BT já estava ligado, sem problemas de conexão! Isso não ocorre em dispositivos com uma versão posterior do Android, sugerindo que os desenvolvedores notaram o bug e o corrigiram, mas a página Android BT não diz uma palavra sobre isso. Mas sua solução funciona, obrigado!
John Perry,
7

Em versões mais recentes do Android, recebia este erro porque o adaptador ainda estava descobrindo quando tentei conectar ao soquete. Embora eu tenha chamado o método cancelDiscovery no adaptador Bluetooth, tive que esperar até que o retorno de chamada para o método onReceive () do BroadcastReceiver fosse chamado com a ação BluetoothAdapter.ACTION_DISCOVERY_FINISHED.

Assim que esperei que o adaptador parasse de detectar, a chamada de conexão no soquete foi bem-sucedida.

kmac.mcfarlane
fonte
6

Você coloca registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID")); com "bluetooth" escrito "bleutooth".

Fizz Binn
fonte
4

Caso alguém esteja tendo problemas com o Kotlin, tive que seguir a resposta aceita com algumas variações:

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

Espero que ajude

Santiago Martí Olbrich
fonte
3

Os dispositivos Bluetooth podem operar nos modos clássico e LE ao mesmo tempo. Às vezes, eles usam um endereço MAC diferente, dependendo de como você está se conectando. Chamar socket.connect()é usar o Bluetooth Classic, então você deve se certificar de que o dispositivo que você recebeu ao fazer a varredura é realmente um dispositivo clássico.

É fácil filtrar apenas para dispositivos clássicos, no entanto:

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

Sem essa verificação, é uma condição de corrida se uma varredura híbrida fornecerá primeiro o dispositivo Classic ou o dispositivo BLE. Pode parecer uma incapacidade intermitente de se conectar, ou alguns dispositivos sendo capazes de se conectar de forma confiável, enquanto outros aparentemente nunca conseguem.

kmac.mcfarlane
fonte
1

Eu também enfrentei esse problema, você poderia resolvê-lo de 2 maneiras, como mencionei anteriormente, use reflexão para criar o soquete. A segunda é, o cliente está procurando por um servidor com o UUID fornecido e se o seu servidor não estiver rodando paralelo ao cliente, então isso acontece. Crie um servidor com o UUID do cliente fornecido e, em seguida, ouça e aceite o cliente do lado do servidor. Isso funcionará.

ireshika piyumalie
fonte
1

Corri para esse problema e corrigi-lo fechando os fluxos de entrada e saída antes de fechar o soquete. Agora posso desconectar e conectar novamente sem problemas.

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

Em Kotlin:

fun disconnect() {
    bluetoothSocket.inputStream.close()
    bluetoothSocket.outputStream.close()
    bluetoothSocket.close()
}
TheoKanning
fonte
1

Se outra parte do seu código já fez uma conexão com o mesmo soquete e UUID, você receberá este erro.

user1725145
fonte
0

Mesmo eu tendo o mesmo problema, finalmente entendi meu problema, eu estava tentando conectar de (fora do alcance) cobertura de Bluetooth.

Krishnamurthy
fonte
0

Eu tive esse problema e a solução foi usar o GUID mágico especial.

            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.

Suspeito que estes são os UUIDs que funcionam:

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

No entanto, não experimentei todos eles.

Richard Barraclough
fonte
Até estou usando o mesmo UUID. Mas não me ajudou. Isso é compatível apenas com a conexão de dispositivos bluetooth Classic (não BLE)? O que tenho que fazer para me conectar a dispositivos BLE usando Xamarin.Forms. Postado aqui [ stackoverflow.com/questions/62371859/…
Shailesh Bhat
Estou usando o Bluetooth clássico; BLE é um lixo.
Richard Barraclough
-1

Ao adicionar ação de filtro, meu problema foi resolvido

 // 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);
Vinod Ranga
fonte
-3

Também recebi o mesmo IOException, mas acho que a demo do sistema Android: projeto "BluetoothChat" funcionou. Eu determinei que o problema é o UUID.

Então eu troquei o meu UUID.fromString("00001001-0000-1000-8000-00805F9B34FB")para UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")e funcionou na maioria das cenas, só às vezes preciso reiniciar o dispositivo Bluetooth;

taotao
fonte