IOException : 읽기 실패, 소켓이 닫힐 수 있음-Android 4.3의 Bluetooth


100

현재 Android 4.3 (Build JWR66Y, 두 번째 4.3 업데이트)을 사용하여 Nexus 7 (2012)에서 BluetoothSocket을 열 때 이상한 예외를 처리하려고합니다. 일부 관련 게시물 (예 : /programming/13648373/bluetoothsocket-connect-throwing-exception-read-failed )을 보았지만이 문제에 대한 해결 방법을 제공하는 것은 없습니다. 또한 이러한 스레드에서 제안했듯이 재 페어링은 도움이되지 않으며 멍청한 루프를 통해 지속적으로 연결을 시도해도 효과가 없습니다.

임베디드 장치 ( http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- 와 유사한 이름 없음 OBD-II 자동차 어댑터)를 다루고 있습니다. 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 https 에서 호출되는 readInt ()를 통해 호출됩니다. : //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의 버그 일 가능성이 있습니까?


나는이 문제에 대한 도움말을 sombody 수 위의 솔루션을 시도 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아래 소스 코드와 유사한 fallback을 인스턴스화 합니다. 보시다시피 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 2015

2
@MD 나는 방법을 모른다. 방금 테스트하고 작동하는 것으로 나타났습니다.
Bobs

1
nexus 4에서는 작동하지 않습니다.이 문제를 해결하는 방법을 알려주세요. 나는 거의 모든 것을 시도했습니다. 감사.
Shah

3
@matthes 죄송하지만 폴백을 사용하는 솔루션조차 내 문제를 해결하지 못했습니다. 아래 오류가 발생했습니다. Fallback failed. Cancelling. java.io.IOException: Connection refused 도와주세요.
Tushar Banne

2
@matthes "SPP- 장치 (플러그 오프 / 플러그인)는 이러한 경우에 도움이됩니다.". on / off 성명은 세계에서 가장 과소 평가됩니다. 난 그냥 3 시간 낭비 모두 내가해야 할 일을했을 것은 -_- 및 해제를 설정했다
ADZ

98

글쎄, 나는 내 코드에 동일한 문제가 있었고 그것은 안드로이드 4.2 블루투스 스택이 변경 되었기 때문입니다. 그래서 내 코드는 android <4.2 인 장치에서 잘 실행되고 있었고 다른 장치에서는 "읽기 실패, 소켓이 닫혔거나 시간 초과, 읽기 ret : -1"라는 유명한 예외가 발생 했습니다.

socket.mPort매개 변수에 문제가 있습니다. 당신이 사용하여 소켓을 만드는 경우 socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);는이 mPort값의 정수 "얻는다 -1 ", 및 "로 설정해야합니다 있도록이 값은 4.2> = 안드로이드에 대한 작업을하지 않는 것 같다 (1) ". 나쁜 소식은 createRfcommSocketToServiceRecordUUID 만 매개 변수로 받아들이고 mPort다른 aproach를 사용해야한다는 것입니다. @matthes가 게시 한 답변 도 저에게 효과적 이지만 단순화했습니다 socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);.. 두 번째 소켓 속성을 폴백으로 사용해야합니다.

따라서 코드는 다음과 같습니다 (ELM327 장치의 SPP에 연결).

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
중재자 : 이유없이 이전 답변을 삭제 했으므로 다시 게시합니다.
George Dima 2014 년

2
mPort매개 변수에 대한 통찰력을 주신 George에게 감사드립니다 ! imho 워크 플로는 동일하게 유지되며 인터페이스를 구현하는 일부 클래스로 항목을 래핑했습니다.
matthes

5
예, 이미 귀하의 솔루션이 좋다고 말했지만, Android 4.2
부터이

2
SPP = 직렬 포트 프로필 (블루투스를 통해 직렬 포트를 에뮬레이트)하고 ELM327은 블루투스 <-> obd 자동차 장치입니다.
George Dima

10
포트 값을 1에서 2로 변경 한 후 저에게 효과적이었습니다.이 코드를 살펴보십시오. socket = (BluetoothSocket) device.getClass (). getMethod ( "createRfcommSocket", new Class [] {int.class}). invoke (device, 2); socket.connect ();
Dinesh IT

16

먼저 블루투스 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
거의 이틀 동안의 작업이 해결되었습니다. 감사 한 한숨 ...이 UUID가 없으면 소켓이 즉시 닫히고 추가 설명없이 실패합니다.
David Sinclair

내 UUID가 영숫자이고 HC-5를 연결하려고 시도하고 블루투스 연결 실패를 보여 주셔서 감사합니다. 그러나이 솔루션을 사용했을 때 문제가 해결되었습니다. 다시 한 번 감사드립니다
Nikhil Shende

8

여기에 설명 된 것과 같은 증상이있었습니다. 블루투스 프린터에 한 번 연결할 수 있었지만 이후 연결은 내가 무엇을하더라도 "소켓이 닫힘"으로 실패했습니다.

여기에 설명 된 해결 방법이 필요하다는 것이 조금 이상하다는 것을 알았습니다. 내 코드를 살펴본 후 소켓의 InputStream 및 OutputSteram을 닫는 것을 잊고 ConnectedThreads를 제대로 종료하지 않았 음을 발견했습니다.

내가 사용하는 ConnectedThread는 여기 예제와 동일합니다.

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

ConnectThread와 ConnectedThread는 서로 다른 두 클래스입니다.

ConnectedThread를 시작하는 모든 클래스는 스레드에서 interrupt () 및 cancel ()을 호출해야합니다. ConnectedTread.cancel () 메서드에 mmInStream.close () 및 mmOutStream.close ()를 추가했습니다.

스레드 / 스트림 / 소켓을 제대로 닫은 후 문제없이 새 소켓을 만들 수 있습니다.


감사합니다. 동일한 문제가 발생했습니다. 방금 스트림과 연결을 닫지 않았다고 생각했습니다.
Rafael

위의 모든 시나리오를 시도했습니다. (다른 페어링 된 장치를 제거하는 경우를 제외하고는 실제로 해결책이 아닙니다. 예 ... 이것은 일반적으로 입력 스트림과 소켓이 제대로 닫히지 않을 때만 발생합니다 ..... !!
Aman Satija

7

글쎄, 나는 실제로 문제를 발견했습니다.

를 사용하여 연결을 시도하는 대부분의 사람들은 socket.Connect();라는 예외 를 받습니다 Java.IO.IOException: read failed, socket might closed, read ret: -1.

경우에 따라 Bluetooth 장치에 따라 달라집니다. BLE (저에너지)와 클래식이라는 두 가지 유형의 Bluetooth가 있기 때문입니다.

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에서 소켓에 연결하려고 할 때 어댑터가 여전히 발견 중이기 때문에이 오류가 발생했습니다. Bluetooth 어댑터에서 cancelDiscovery 메서드를 호출했지만 BluetoothAdapter.ACTION_DISCOVERY_FINISHED 작업으로 BroadcastReceiver의 onReceive () 메서드에 대한 콜백이 호출 될 때까지 기다려야했습니다.

어댑터가 검색을 중지 할 때까지 기다린 후 소켓의 연결 호출이 성공했습니다.


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을 사용하므로 스캔 할 때받은 장치가 실제로 클래식 장치인지 확인해야합니다.

그러나 Classic 장치 만 필터링하는 것은 쉽습니다.

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

이 검사가 없으면 하이브리드 스캔이 클래식 장치 또는 BLE 장치를 먼저 제공할지 여부에 대한 경쟁 조건입니다. 간헐적으로 연결할 수 없거나 특정 장치가 안정적으로 연결할 수있는 반면 다른 장치는 연결할 수없는 것처럼 보일 수 있습니다.


1

나는 또한이 문제에 직면하여 앞에서 언급했듯이 리플렉션을 사용하여 소켓을 만드는 두 가지 방법으로 해결할 수 있습니다. 두 번째는 클라이언트가 주어진 UUID로 서버를 찾고 있으며 서버가 클라이언트와 병렬로 실행되지 않는 경우 이것은 발생합니다. 주어진 클라이언트 UUID로 서버를 만든 다음 서버 측에서 클라이언트를 수신하고 수락하면 작동합니다.


1

이 문제가 발생하여 소켓을 닫기 전에 입력 및 출력 스트림을 닫아 수정했습니다. 이제 연결을 끊었다가 문제없이 다시 연결할 수 있습니다.

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

Kotlin에서 :

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를 사용하고 있습니다. 하지만 도움이되지 않았습니다. 클래식 블루투스 장치 (BLE가 아님)에 연결하는 경우에만 지원됩니까? Xamarin.Forms를 사용하여 BLE 장치에 연결하기 위해해야 ​​할 일. 여기에 게시 됨 [ stackoverflow.com/questions/62371859/…
Shailesh Bhat

클래식 블루투스를 사용하고 있습니다. BLE는 쓰레기입니다.
Richard Barraclough

-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")하고 대부분의 장면을 열심히 만 때로는 블루투스 장치를 다시 시작해야합니다;

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.