Para crear una conexión entre dos dispositivos, debes implementar el
Mecanismos del servidor y del cliente, ya que un dispositivo debe abrir un servidor
y el otro debe iniciar la conexión usando la interfaz del dispositivo
dirección MAC. El dispositivo del servidor y el dispositivo cliente obtienen la
BluetoothSocket
en diferentes
maneras. El servidor recibe información del socket cuando se inicia una conexión
aceptada. El cliente proporciona información del socket cuando abre un canal RFCOMM
al servidor.
El servidor y el cliente se consideran conectados entre sí cuando tienen
un BluetoothSocket
conectado en el mismo canal RFCOMM En este punto, cada
puede obtener flujos de entrada y salida, y comenzar la transferencia de datos, que
se analiza en la sección sobre cómo transferir dispositivos
los datos en la nube. Esta sección
describe cómo iniciar la conexión entre dos dispositivos.
Asegúrate de tener la información Permisos de Bluetooth y configura tu app para usar Bluetooth antes intentando encontrar dispositivos Bluetooth.
Técnicas de conexión
Una técnica de implementación consiste en preparar automáticamente cada dispositivo como un servidor de manera que cada dispositivo tenga un socket de servidor abierto y reciba conexiones. En en este caso, cualquiera de los dispositivos puede iniciar una conexión y convertirse en cliente. De manera alternativa, un dispositivo puede alojar explícitamente la conexión y abrir una un socket de servidor bajo demanda, y el otro dispositivo iniciará la conexión.
Figura 1: Diálogo de vinculación por Bluetooth
Conectarse como servidor
Cuando quieras conectar dos dispositivos, uno debe funcionar como servidor manteniendo un
abierta
BluetoothServerSocket
El propósito del socket de servidor es escuchar las solicitudes de conexión entrantes.
y proporciona un BluetoothSocket
conectado después de que se acepte una solicitud. Cuando
BluetoothSocket
se adquiere de BluetoothServerSocket
, el
BluetoothServerSocket
puede (y debe) descartarse, a menos que quieras
que el dispositivo acepte más conexiones.
Para configurar un socket de servidor y aceptar una conexión, completa los siguientes pasos: secuencia de pasos:
Obtén un
BluetoothServerSocket
llamandolistenUsingRfcommWithServiceRecord(String, UUID)
La cadena es un nombre identificable de tu servicio, que el sistema escribe automáticamente en una nueva entrada de base de datos del protocolo de detección de servicios (SDP) en el dispositivo. El nombre es arbitrario y puede ser simplemente el de tu app. El identificador único universal (UUID) también se incluye en la entrada del SDP y constituye la base del acuerdo de conexión con el dispositivo del cliente. Que es que, cuando el cliente intenta conectarse con este dispositivo, lleva un UUID que identifique de manera inequívoca el servicio con el que desea conectarse. Estos Los UUID deben coincidir a fin de que se acepte la conexión.
Un UUID es un formato estandarizado de 128 bits para un ID de cadena que se usa para identificar información. Un UUID se usa para identificar la información que se debe únicos en un sistema o red porque la probabilidad de que un UUID sea repetido es efectivamente cero. Se genera de forma independiente, sin necesidad de de una autoridad centralizada. En este caso, se usa para identificar de forma única tu servicio Bluetooth de la app. Para obtener un UUID que pueda usarse con la app, puedes usar uno de muchos modelos aleatorios
UUID
en la Web y, luego, inicializa un UUID confromString(String)
Llama para comenzar a escuchar solicitudes de conexión
accept()
Esta es una llamada de bloqueo. Se muestra cuando se establece una conexión o se produjo una excepción. Una conexión se acepta solo cuando una el dispositivo remoto envió una solicitud de conexión que contiene un UUID que coincide el que está registrado con este socket de servidor de escucha. Si tiene éxito,
accept()
muestra unBluetoothSocket
conectado.A menos que quieras aceptar conexiones adicionales, llama
close()
Este método libera el socket de servidor y todos sus recursos, pero no cierra el
BluetoothSocket
conectado que devolvióaccept()
A diferencia de TCP/IP, RFCOMM permite solo un cliente conectado por canal a la vez, así que, en la mayoría de los casos, tiene sentido llamar aclose()
en elBluetoothServerSocket
inmediatamente después de aceptar un socket conectado.
Dado que la llamada a accept()
es de bloqueo, no la ejecutes en el
de la IU de la actividad. Ejecutarla en otro subproceso garantiza que la app pueda
responder a otras interacciones del usuario. Por lo general, tiene sentido hacer todo el trabajo
que implique un BluetoothServerSocket
o BluetoothSocket
en un subproceso nuevo
administrados por tu app. Para anular una llamada bloqueada, como accept()
, llama a close()
en BluetoothServerSocket
o BluetoothSocket
de otro subproceso. Nota
que todos los métodos en un BluetoothServerSocket
o BluetoothSocket
están
de forma segura para subprocesos.
Ejemplo
El siguiente es un subproceso simplificado para el componente de servidor que acepta conexiones entrantes:
Kotlin
private inner class AcceptThread : Thread() { private val mmServerSocket: BluetoothServerSocket? by lazy(LazyThreadSafetyMode.NONE) { bluetoothAdapter?.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID) } override fun run() { // Keep listening until exception occurs or a socket is returned. var shouldLoop = true while (shouldLoop) { val socket: BluetoothSocket? = try { mmServerSocket?.accept() } catch (e: IOException) { Log.e(TAG, "Socket's accept() method failed", e) shouldLoop = false null } socket?.also { manageMyConnectedSocket(it) mmServerSocket?.close() shouldLoop = false } } } // Closes the connect socket and causes the thread to finish. fun cancel() { try { mmServerSocket?.close() } catch (e: IOException) { Log.e(TAG, "Could not close the connect socket", e) } } }
Java
private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; public AcceptThread() { // Use a temporary object that is later assigned to mmServerSocket // because mmServerSocket is final. BluetoothServerSocket tmp = null; try { // MY_UUID is the app's UUID string, also used by the client code. tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (IOException e) { Log.e(TAG, "Socket's listen() method failed", e); } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; // Keep listening until exception occurs or a socket is returned. while (true) { try { socket = mmServerSocket.accept(); } catch (IOException e) { Log.e(TAG, "Socket's accept() method failed", e); break; } if (socket != null) { // A connection was accepted. Perform work associated with // the connection in a separate thread. manageMyConnectedSocket(socket); mmServerSocket.close(); break; } } } // Closes the connect socket and causes the thread to finish. public void cancel() { try { mmServerSocket.close(); } catch (IOException e) { Log.e(TAG, "Could not close the connect socket", e); } } }
En este ejemplo, solo se desea una conexión entrante, por lo que
como se acepta la conexión y se adquiere el BluetoothSocket
, la app pasa el
adquirido BluetoothSocket
en un subproceso independiente, se cierra
BluetoothServerSocket
y sale del bucle.
Ten en cuenta que cuando accept()
devuelve BluetoothSocket
, el socket ya está
conectado. Por lo tanto, no debes llamar
connect()
, como tú
del lado del cliente.
El método manageMyConnectedSocket()
específico de la app está diseñado para iniciar la
conversación para transferir datos, que se analiza en el tema sobre
transfiriendo Bluetooth
datos.
Por lo general, debes cerrar tu BluetoothServerSocket
en cuanto termines.
a la escucha de conexiones entrantes. En este ejemplo, se llama a close()
en cuanto
a medida que se adquiere BluetoothSocket
. También puedes proporcionar una
de tu subproceso que pueda cerrar el BluetoothSocket
privado en el evento
que debes dejar de escuchar en ese socket de servidor.
Conectarse como cliente
Para iniciar una conexión con un dispositivo remoto que acepte
conexiones en un socket de servidor abierto, primero debes obtener un BluetoothDevice
que representa el dispositivo remoto. Para aprender a crear un
BluetoothDevice
, consulta Buscar Bluetooth
dispositivos. Debes
Luego, usa el BluetoothDevice
para adquirir un BluetoothSocket
e iniciar la
conexión.
El procedimiento básico es el siguiente:
Con
BluetoothDevice
, obtén unBluetoothSocket
llamandocreateRfcommSocketToServiceRecord(UUID)
Este método inicializa un objeto
BluetoothSocket
que le permite al cliente hacer lo siguiente: conectarte aBluetoothDevice
. El UUID que se pasa aquí debe coincidir con el UUID usado por el dispositivo del servidor cuando llamólistenUsingRfcommWithServiceRecord(String, UUID)
para abrir suBluetoothServerSocket
. Para usar un UUID que coincida, codifica el de UUID a tu app y, luego, hacer referencia a ella desde el servidor y el código del cliente.Llama a
connect()
para iniciar la conexión. Ten en cuenta que este método es un llamada de bloqueo.Después de que un cliente llama a este método, el sistema realiza una búsqueda de SDP para encontrar el dispositivo remoto con el UUID correspondiente. Si la búsqueda se realiza correctamente y El dispositivo remoto acepta la conexión y comparte el canal RFCOMM para usar durante la conexión, y se devuelve el método
connect()
. Si la conexión falla o si se agota el tiempo de espera del métodoconnect()
(después de unos 12 segundos), el método arroja unaIOException
.
Como connect()
es una llamada de bloqueo, siempre debes realizar esto.
procedimiento de conexión en un subproceso independiente de la actividad principal (IU)
conversación.
Ejemplo
El siguiente es un ejemplo básico de un subproceso de cliente que inicia una conexión Bluetooth conexión:
Kotlin
private inner class ConnectThread(device: BluetoothDevice) : Thread() { private val mmSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) { device.createRfcommSocketToServiceRecord(MY_UUID) } public override fun run() { // Cancel discovery because it otherwise slows down the connection. bluetoothAdapter?.cancelDiscovery() mmSocket?.let { socket -> // Connect to the remote device through the socket. This call blocks // until it succeeds or throws an exception. socket.connect() // The connection attempt succeeded. Perform work associated with // the connection in a separate thread. manageMyConnectedSocket(socket) } } // Closes the client socket and causes the thread to finish. fun cancel() { try { mmSocket?.close() } catch (e: IOException) { Log.e(TAG, "Could not close the client socket", e) } } }
Java
private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { // Use a temporary object that is later assigned to mmSocket // because mmSocket is final. BluetoothSocket tmp = null; mmDevice = device; try { // Get a BluetoothSocket to connect with the given BluetoothDevice. // MY_UUID is the app's UUID string, also used in the server code. tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { Log.e(TAG, "Socket's create() method failed", e); } mmSocket = tmp; } public void run() { // Cancel discovery because it otherwise slows down the connection. bluetoothAdapter.cancelDiscovery(); try { // Connect to the remote device through the socket. This call blocks // until it succeeds or throws an exception. mmSocket.connect(); } catch (IOException connectException) { // Unable to connect; close the socket and return. try { mmSocket.close(); } catch (IOException closeException) { Log.e(TAG, "Could not close the client socket", closeException); } return; } // The connection attempt succeeded. Perform work associated with // the connection in a separate thread. manageMyConnectedSocket(mmSocket); } // Closes the client socket and causes the thread to finish. public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "Could not close the client socket", e); } } }
Ten en cuenta que, en este fragmento, se llama a cancelDiscovery()
antes de la conexión
se produce un primer intento. Siempre debes llamar a cancelDiscovery()
antes de connect()
,
en especial porque cancelDiscovery()
funciona correctamente sin importar si el dispositivo
el descubrimiento está en curso. Si tu app necesita determinar si
la detección de dispositivos está en curso, puedes comprobarlo con
isDiscovering()
El método manageMyConnectedSocket()
específico de la app está diseñado para iniciar la
subproceso para transferir datos, que se analiza en la sección sobre
transferencia de datos de Bluetooth.
Cuando termines de usar BluetoothSocket
, siempre llama a close()
. Hacerlo
cierra de inmediato el socket conectado y libera todos los procesos
de Google Cloud.