BluetoothSocket не подключается к целевому устройству

Я пытаюсь подключить свое устройство к другому через Bluetooth, но когда я выбираю устройство, с которым хочу подключиться, я получаю сообщение об IOException

read failed, сокет может быть закрыт или таймаут, read ret: -1

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

Ниже мой код для моей темы подключения:

 private val MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb") private lateinit var device: BluetoothDevice private lateinit var onDeviceActionListener: OnDeviceActionListener private lateinit var socket: BluetoothSocket fun init(device: BluetoothDevice, onDeviceActionListener: OnDeviceActionListener): ConnectionThread { this.device = device this.onDeviceActionListener = onDeviceActionListener try { socket = device.createRfcommSocketToServiceRecord(MY_UUID) } catch (e: IOException) { Log.e(TAG, "Error creating socket", e) } return this } override fun run() { try { socket.connect() } catch (openException: IOException) { Log.e(TAG, "Error opening connection. Trying to close...", openException) try { socket.close() } catch (closeException: IOException) { Log.e(TAG, "Error closing socket", closeException) } return } onDeviceActionListener.onDeviceConnect(device) } 

Я думаю, что что-то не так с моим UUID. Я пробовал некоторые другие значения, но все еще не работал.

Любая помощь будет высоко ценится.

    Ну, я не понимаю, что вы здесь делаете неправильно. Тем не менее, я сделал довольно много работы Bluetooth. Совсем недавно просто сосредоточился на BLE. Вы должны быть в состоянии обнаружить ваши близлежащие устройства BT и посмотреть их UUID.

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

     public class BluetoothConnector { private static final String TAG = Globals.SEARCH_STRING + BluetoothConnector.class.getSimpleName(); private static final String DEFAULT_SERVER_NAME_FOR_APP = "tn_bt_default_server"; private static final int DEFAULT_DISCOVERABLE_DURATION_MS = 30000; private static final UUID DEFAULT_UUID = UUID.fromString("6534c201-039c-4e4f-89f9-5ca8cfeb9667"); public static final int ENABLE_DISCOVER_INTENT = 1002; protected boolean mIsToastEnabled = false; //Access from calling class to enable toasting of progress to screen if necessary private Handler mUIHandler; private static ServerSocketThread mServerSocketThread; private static ClientSocketThread mClientSocketThread; private ManageConnectionThread mManageConnectionThread; private Context mContext; private IBluetoothDataListener mBluetoothDataListener; public final Object ServerSocketLock = new Object(); public final Object ClientSocketLock = new Object(); public final Object ManageConnectionLock = new Object(); public BluetoothConnector(Context context, IBluetoothDataListener listener){ this(context, new Handler(Looper.getMainLooper()), listener); } public BluetoothConnector(Context context, Handler UIHandler, IBluetoothDataListener listener){ Log.v(TAG, "BluetoothConnector(context=" + context + ", Handler=" + UIHandler.getClass().getSimpleName() + ", IBluetoothDataListener=" + listener.getClass().getSimpleName()); mContext = context; mUIHandler = UIHandler; mBluetoothDataListener = listener; } public void makeThisDeviceDiscoverable(Activity callingActivity){ makeThisDeviceDiscoverable(callingActivity, BluetoothAdapter.getDefaultAdapter(), DEFAULT_DISCOVERABLE_DURATION_MS); } public void makeThisDeviceDiscoverable(Activity callingActivity, BluetoothAdapter adapter){ makeThisDeviceDiscoverable(callingActivity, adapter, DEFAULT_DISCOVERABLE_DURATION_MS); } public void makeThisDeviceDiscoverable(Activity callingActivity, int durationInMs){ makeThisDeviceDiscoverable(callingActivity, BluetoothAdapter.getDefaultAdapter(), durationInMs); } public void makeThisDeviceDiscoverable(Activity callingActivity, BluetoothAdapter adapter, int durationInMs) { Log.v(TAG, "makeThisDeviceDiscoverable(callingActivity=" + callingActivity.getClass().getSimpleName() + ", BluetoothAdapter=" + (adapter == null ? "null" : adapter.getName()) + ", duration=" + String.valueOf(durationInMs)); if(adapter == null){ Log.v(TAG, "adapter is null"); }else if(adapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { Log.v(TAG, "Launching Activity to request Discoverable Permission"); Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, durationInMs); callingActivity.startActivityForResult(discoverableIntent, ENABLE_DISCOVER_INTENT); }else{ Log.v(TAG, "adapter is already in SCAN MODE"); } } public void awaitConnectionFromDevice(){ awaitConnectionFromDevice(DEFAULT_UUID, BluetoothAdapter.getDefaultAdapter()); } public void awaitConnectionFromDevice(UUID commonKey){ awaitConnectionFromDevice(commonKey, BluetoothAdapter.getDefaultAdapter()); } public void awaitConnectionFromDevice(BluetoothAdapter adapter){ awaitConnectionFromDevice(DEFAULT_UUID, adapter); } public void awaitConnectionFromDevice(UUID commonKey, BluetoothAdapter adapter){ Log.v(TAG, "awaitConnectionFromDevice for UUID: " + String.valueOf(commonKey) + ", BluetoothAdapter=" + (adapter == null ? "null" : adapter.getName())); cancelDiscovery(); synchronized (ServerSocketLock){ if(mServerSocketThread != null){ Log.v(TAG, "Server Socket Thread was not null so canceling current Thread"); mServerSocketThread.cancel(); } Log.v(TAG, "Attempting to Start new ServerThread"); mServerSocketThread = new ServerSocketThread(commonKey, adapter); mServerSocketThread.start(); } } public void cancelAwaitingConnectionFromDevice(){ Log.v(TAG, "cancelAwaitingConnectionFromDevice"); synchronized (ServerSocketLock){ if(mServerSocketThread != null){ mServerSocketThread.cancel(); mServerSocketThread = null; Log.v(TAG, "canceling Server Socket Thread"); }else{ Log.v(TAG, "Server Socket null, so not canceling"); } } } public void startDiscovery() { startDiscovery(BluetoothAdapter.getDefaultAdapter()); } public void startDiscovery(BluetoothAdapter adapter){ Log.v(TAG, "startDiscovery to find list of devices in range"); adapter.startDiscovery(); } public void cancelDiscovery() { cancelDiscovery(BluetoothAdapter.getDefaultAdapter()); } public void cancelDiscovery(BluetoothAdapter adapter){ Log.v(TAG, "cancelDiscovery"); adapter.cancelDiscovery(); } public void connectToDevice(BluetoothDevice device){ connectToDevice(device, DEFAULT_UUID); } public void connectToDevice(BluetoothDevice device, UUID commonKey){ Log.v(TAG, "connectToDevice(BluetoothDevice=" + (device == null ? "null" : device.getName()) + ", UUID=" + String.valueOf(commonKey)); synchronized (ClientSocketLock){ if(mClientSocketThread != null){ Log.v(TAG, "Client Socket Thread was not null so canceling current Thread"); mClientSocketThread.cancel(); }else{ Log.v(TAG, "Client Socket Thread is NULL so not canceling"); } Log.v(TAG, "ClientSocketThread Starting"); mClientSocketThread = new ClientSocketThread(device, commonKey); mClientSocketThread.start(); } } public BluetoothDevice getBluetoothDeviceByMac(String mac){ Log.v(TAG, "getBluetoothDeviceByMac(mac=" + mac); return getBluetoothDeviceByMac(mac, BluetoothAdapter.getDefaultAdapter()); } public BluetoothDevice getBluetoothDeviceByMac(String mac, BluetoothAdapter adapter) { Log.v(TAG, "getBluetoothDeviceByMac(mac=" + mac + ", BluetoothAdapter=" + (adapter == null ? "null" : adapter.getName())); return adapter.getRemoteDevice(mac); } public ArrayList<KeyValueModel> getPairedDevices(){ return getPairedDevices(BluetoothAdapter.getDefaultAdapter()); } public ArrayList<KeyValueModel> getPairedDevices(BluetoothAdapter adapter){ ArrayList<KeyValueModel> bondedDevices = new ArrayList<KeyValueModel>(); Set<BluetoothDevice> pairedDevices = adapter.getBondedDevices(); Log.v(TAG, "getPairedDevices Found " + pairedDevices.size() + " number of paired devices"); // If there are paired devices if (pairedDevices.size() > 0) { // Loop through paired devices for (BluetoothDevice device : pairedDevices) { // Add the name and address to an array adapter to show in a ListView bondedDevices.add(new KeyValueModel(device.getAddress(), device.getName())); } } return bondedDevices; } public static void unpairDevice(BluetoothDevice device){ Log.v(TAG, "unpairDevice"); try{ Method method = device.getClass().getMethod("removeBond", (Class[]) null); method.invoke(device, (Object[]) null); }catch (Exception ex){ Log.e(TAG, "Error Unpairing Device: " + ex.getMessage()); } } public boolean sendDataToConnectedDevice(byte[] data){ Log.v(TAG, "sendDataToConnectedDevice"); synchronized (ManageConnectionLock){ mManageConnectionThread.write(data); return true; } } public void setBluetoothDataListener(IBluetoothDataListener listener){ mBluetoothDataListener = listener; } public boolean getIsConnected(){ synchronized (ManageConnectionLock) { return mManageConnectionThread != null && mManageConnectionThread.isAlive(); } } private void startManageConnectionThread(BluetoothSocket socket){ Log.v(TAG, "startManageConnectionThread for Socket: " + (socket == null ? "null" : socket.getClass().getSimpleName())); synchronized (ManageConnectionLock) { mManageConnectionThread = new ManageConnectionThread(socket); mManageConnectionThread.start(); } } private void handleDataReceivedFromConnectedDevice(final byte[] bytes){ Log.v(TAG, "handleDataReceivedFromConnectedDevice"); Log.v(TAG, "bytes to Listener: " + new String(bytes)); if(mUIHandler != null && mBluetoothDataListener != null){ mUIHandler.post(new Runnable() { @Override public void run() { if (mBluetoothDataListener != null) { mBluetoothDataListener.onReceivedPayloadFromConnectedDevice(bytes); } } }); }else{ Log.v(TAG, "UIHandler was null so skipped sending payload to listener"); } } private void handleConnected(){ Log.e(TAG, "handleConnected"); if(mUIHandler != null && mBluetoothDataListener != null){ mUIHandler.post(new Runnable() { @Override public void run() { if(mBluetoothDataListener != null){ mBluetoothDataListener.onConnectedToTargetDevice(); } } }); }else{ Log.v(TAG, "UIHandler was null so skipped sending payload to listener"); } } private void handleDisconnected(){ Log.e(TAG, "handleDisconnected"); if(mUIHandler != null && mBluetoothDataListener != null){ mUIHandler.post(new Runnable() { @Override public void run() { if(mBluetoothDataListener != null){ mBluetoothDataListener.onDisconnectedFromTargetDevice(); } } }); }else{ Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener"); } } private void handleFailedToConnectAsServer(final Exception ex){ Log.e(TAG, "handleFailedToConnectAsServer ex: " + ex.getMessage()); if(mUIHandler != null && mBluetoothDataListener != null){ mUIHandler.post(new Runnable() { @Override public void run() { if(mBluetoothDataListener != null){ mBluetoothDataListener.onFailedToReceiveConnectionFromTargetDevice(ex); } } }); }else{ Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener"); } } private void handleFailedToConnectAsClient(final Exception ex){ Log.e(TAG, "handleFailedToConnectAsClient ex: " + ex.getMessage()); if(mUIHandler != null && mBluetoothDataListener != null){ mUIHandler.post(new Runnable() { @Override public void run() { if(mBluetoothDataListener != null){ mBluetoothDataListener.onFailedToConnectToTargetDevice(ex); } } }); }else{ Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener"); } } private void handleErrorInRetrievingData(final Exception ex){ Log.e(TAG, "handleErrorInRetrievingData ex: " + ex.getMessage()); if(mUIHandler != null && mBluetoothDataListener != null){ mUIHandler.post(new Runnable() { @Override public void run() { if(mBluetoothDataListener != null){ mBluetoothDataListener.onErrorReceivingPayloadFromConnectedDevice(ex); } } }); }else{ Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener"); } } private void handleFailedToSendDataToConnectedDevice(final Exception ex){ Log.e(TAG, "handleFailedToSendDataToConnectedDevice ex: " + ex.getMessage()); if(mUIHandler != null && mBluetoothDataListener != null){ mUIHandler.post(new Runnable() { @Override public void run() { if(mBluetoothDataListener != null){ mBluetoothDataListener.onFailedToSendDataToConnectedDevice(ex); } } }); }else{ Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener"); } } private void toastMessage(final String value){ if(!mIsToastEnabled || mUIHandler == null) { return; } mUIHandler.post(new Runnable() { @Override public void run() { try{ Toast.makeText(mContext, value, Toast.LENGTH_SHORT).show(); }catch(Exception ex){ Log.v(TAG, "Error Toasting, possibly bad handler, or context: " + ex.getMessage()); } } }); } private class ServerSocketThread extends Thread{ private final String TAG = Globals.SEARCH_STRING + ServerSocketThread.class.getSimpleName(); private final BluetoothServerSocket mServerSocket; public ServerSocketThread(UUID commonKey, BluetoothAdapter adapter) { Log.v(TAG, "ServerSocketThread Constructor"); BluetoothServerSocket tmp = null; try { Log.v(TAG, "listening for RFComas Server: " + DEFAULT_SERVER_NAME_FOR_APP + ", and commonKey: " + String.valueOf(commonKey)); // MY_UUID is the app's UUID string, also used by the client code tmp = adapter.listenUsingRfcommWithServiceRecord(DEFAULT_SERVER_NAME_FOR_APP, commonKey); toastMessage("Listening for RFComm As Server on UUID: " + String.valueOf(commonKey)); } catch (IOException e) { Log.e(TAG, "Error creating ServerSocket: " + e.getMessage()); toastMessage("Error Creating ServerSocket: " + e.getMessage()); } mServerSocket = tmp; } public void run() { Log.v(TAG, "ServerSocket run"); BluetoothSocket socket = null; // Keep listening until exception occurs or a socket is returned while (mServerSocket != null) { try { Log.v(TAG, "ServerSocket.accept()"); toastMessage("ServerSocket.accept()"); //Waits for Client Connection to pass Socket, then we close down socket = mServerSocket.accept(); } catch (IOException e) { Log.e(TAG, "ServerSocket.accept() Error: " + e.getMessage()); toastMessage("ServerSocket.accept() Error: " + e.getMessage()); handleFailedToConnectAsServer(e); break; } // If a connection was accepted we don't need to keep server listening, so close unless multiple client/server connections is desired if (socket != null) { try{ Log.v(TAG, "ServerSocket Accepted Client Socket, Begin Listening Connect Thread"); toastMessage("ServerSocket Accepted Client Socket, Begin Listening Connect Thread"); // Do work to manage the connection (in a separate thread) startManageConnectionThread(socket); //mServerSocket.close(); }catch(Exception ex){ Log.e(TAG, "Exception closing Server Socket"); } //break; //Add in Break if you want to shut down listening for connections }else{ Log.v(TAG, "Socket wasn't accepted"); toastMessage("Socket wasn't accepted"); handleFailedToConnectAsServer(new Exception("Socket is Null")); } } Log.v(TAG, "Exiting Server Accept Thread"); } public void cancel() { try { Log.v(TAG, "ServerSocketThread Canceled"); mServerSocket.close(); } catch (IOException e) { Log.e(TAG, "ServerSocketThread Error: " + e.getMessage()); } } } private class ClientSocketThread extends Thread{ private BluetoothSocket mSocket; private final BluetoothDevice mDevice; public ClientSocketThread(BluetoothDevice device, UUID commonKey) { Log.v(TAG, "ClientSocketThread Constructor"); // Use a temporary object that is later assigned to mmSocket, // because mmSocket is final BluetoothSocket tmp = null; mDevice = device; // Get a BluetoothSocket to connect with the given BluetoothDevice try { Log.v(TAG, "Client creating RFComm Socket to Server with UUID: " + String.valueOf(commonKey)); toastMessage("Client creating RFComm Socket to Server with UUID: " + String.valueOf(commonKey)); // MY_UUID is the app's UUID string, also used by the server code tmp = device.createRfcommSocketToServiceRecord(commonKey); } catch (IOException e) { Log.e(TAG, "Error creating Client Socket: " + e.getMessage()); toastMessage("Creating Socket Exception: " + e.getMessage()); handleFailedToConnectAsClient(e); } mSocket = tmp; } public void run() { try { if(mSocket == null){ Log.e(TAG, "Error Client Socket is Null, Canceling Client Thread"); return; } Log.v(TAG, "Client Connecting"); // Connect to the server, or timeout eventually toastMessage("Client Connecting"); mSocket.connect(); } catch (IOException connectException) { // Unable to connect; close the socket and try the fallback method of reflection with port to connect try { Log.e("", "trying fallback..."); toastMessage("Client Connection Failed Exception: " + connectException.getMessage()); mSocket = (BluetoothSocket) mDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(mDevice, 1); toastMessage("Client Connect Again Attempt 2, but with fall back Reflection and port"); Log.v(TAG, "Client Connect Again Attempt 2, but with fall back Reflection and port"); mSocket.connect(); Log.e("", "Connected"); toastMessage("Client Connected"); } catch (Exception ex) { Log.e("", "Couldn't establish Bluetooth connection!"); toastMessage("Client Couldn't Establish Connection to Server: " + ex.getMessage()); handleFailedToConnectAsClient(ex); return; } } // Do work to manage the connection (in a separate thread) startManageConnectionThread(mSocket); } public void cancel() { try { Log.v(TAG, "Client Socket cancel"); mSocket.close(); } catch (IOException e) { Log.e(TAG, "Error Closing Socket"); } } } private class ManageConnectionThread extends Thread { ///////////// // MEMBERS // ///////////// private final String TAG = Globals.SEARCH_STRING + ManageConnectionThread.class.getSimpleName(); private final BluetoothSocket mSocket; private final InputStream mInStream; private final OutputStream mOutStream; ////////////////// // CONSTRUCTOR // ////////////////// public ManageConnectionThread(BluetoothSocket socket) { mSocket = socket; handleConnected(); InputStream tmpIn = null; OutputStream tmpOut = null; // Get the input and output streams, using temp objects because try { Log.v(TAG, "ManageConnectionThread Constructor"); Log.v(TAG, "Connected to Socket = " + String.valueOf(socket.isConnected())); toastMessage("Listening for input or output Stream"); Log.v(TAG, "Get InputStream"); tmpIn = socket.getInputStream(); Log.v(TAG, "Get OutputStream"); tmpOut = socket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "Error getting Socket Streams: " + e.getMessage()); toastMessage("Connect Thread: Error: " + e.getMessage()); handleErrorInRetrievingData(e); } mInStream = tmpIn; mOutStream = tmpOut; } /////////////// // OVERRIDES // /////////////// public void run() { // Keep listening to the InputStream until an exception occurs while (true) { try { // Read from the InputStream byte[] data = new byte[16384]; int nRead; ByteArrayOutputStream buffer = new ByteArrayOutputStream(); while ((nRead = mInStream.read(data, 0, data.length)) != -1) { //Log.v(TAG, "bytes Read: " + String.valueOf(nRead)); buffer.write(data, 0, nRead); //TODO Find better way to find End Of Message rather than looking for } String temp = new String(buffer.toByteArray()); //Log.v(TAG, "current Data: " + temp); if(temp.contains("}")){ Log.v(TAG, "bytes reading complete"); handleDataReceivedFromConnectedDevice(buffer.toByteArray()); buffer.flush(); buffer = new ByteArrayOutputStream(); }else{ Log.v(TAG, "More bytes Available"); } } } catch (IOException e) { Log.e(TAG, "Error reading inputStream"); handleErrorInRetrievingData(e); break; } } Log.v(TAG, "Exiting Managed Connection Thread"); handleDisconnected(); } ///////////// // METHODS // ///////////// public void write(byte[] bytes) { try { Log.v(TAG, "ManageConnectionThread write(bytes)"); mOutStream.write(bytes); } catch (IOException e) { Log.e(TAG, "Error Writing Stream: " + e.getMessage()); handleFailedToSendDataToConnectedDevice(e); } } public void cancel() { try { Log.v(TAG, "ManageConnectionThread cancel"); handleDisconnected(); mSocket.close(); } catch (IOException e) { Log.e(TAG, "Error Closing BluetoothSocket: " + e.getMessage()); } } } public interface IBluetoothDataListener{ ////////////////////// // OVERRIDE METHODS // ////////////////////// void onReceivedPayloadFromConnectedDevice(byte[] payload); void onErrorReceivingPayloadFromConnectedDevice(Exception ex); void onFailedToConnectToTargetDevice(Exception ex); void onFailedToReceiveConnectionFromTargetDevice(Exception ex); void onFailedToSendDataToConnectedDevice(Exception ex); void onConnectedToTargetDevice(); void onDisconnectedFromTargetDevice(); } 

    }

    Тогда, конечно, вы захотите убедиться, что у вас настроены ваши радиоприемники:

      <receiver android:name=".receivers.BluetoothChangedReceiver" android:enabled="true" > <intent-filter> <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" /> <action android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" /> <action android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" /> <action android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" /> <action android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" /> <action android:name="android.bluetooth.device.action.FOUND" /> <action android:name="android.bluetooth.device.action.DISAPPEARED" /> </intent-filter> </receiver> <receiver android:name=".receivers.BluetoothDeviceReceiver" android:enabled="true" > <intent-filter> <action android:name="android.bluetooth.device.action.FOUND" /> <action android:name="android.bluetooth.device.action.DISAPPEARED" /> <action android:name="android.bluetooth.device.action.ACL_CONNECTED" /> <action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" /> <action android:name="android.bluetooth.device.action.ACTION_ACL_DISCONNECT_REQUESTED" /> <action android:name="android.bluetooth.device.action.BOND_STATE_CHANGED" /> <action android:name="android.bluetooth.device.action.UUID" /> </intent-filter> </receiver>