Per creare una connessione tra due dispositivi, devi implementare entrambi
meccanismi lato server e lato client perché un dispositivo deve aprire un server
e l'altro deve avviare la connessione utilizzando il protocollo
Indirizzo MAC. Sia il dispositivo server che il dispositivo client ottengono i contenuti necessari
BluetoothSocket
in diverse
in molti modi diversi. Il server riceve informazioni sul socket quando viene rilevata una connessione in entrata
accettato. Il client fornisce informazioni sul socket quando apre un canale RFCOMM
al server.
Il server e il client sono considerati connessi l'uno all'altro quando
BluetoothSocket
collegato sullo stesso canale RFCOMM. A questo punto, ogni
dispositivo può ricevere flussi di input e di output e il trasferimento dei dati può iniziare,
viene discussa nella sezione relativa al trasferimento Bluetooth
i tuoi dati. Questa sezione
descrive come avviare la connessione tra due dispositivi.
Assicurati di disporre dell'appropriata Autorizzazioni Bluetooth e configurare l'app per il Bluetooth prima del giorno tentativo di trovare dispositivi Bluetooth.
Tecniche di connessione
Una tecnica di implementazione è preparare automaticamente ogni dispositivo come server in modo che ogni dispositivo abbia un socket del server aperto e in ascolto delle connessioni. Nella In questo caso, uno dei due dispositivi può avviare una connessione tra loro e diventare di alto profilo. In alternativa, un dispositivo può ospitare esplicitamente la connessione e aprire dal socket del server on demand e l'altro dispositivo avvia la connessione.
e
Figura 1. La finestra di dialogo per l'accoppiamento Bluetooth.
Connettiti come server
Quando vuoi connettere due dispositivi, uno deve fungere da server tenendo un
apri
BluetoothServerSocket
Lo scopo del socket del server è ascoltare le richieste di connessione in entrata
e fornire un BluetoothSocket
collegato dopo l'accettazione della richiesta. Quando
BluetoothSocket
viene acquisito da BluetoothServerSocket
,
BluetoothServerSocket
può e deve essere eliminato, a meno che tu non voglia
sul dispositivo per accettare altre connessioni.
Per configurare un socket del server e accettare una connessione, completa la procedura seguente sequenza di passaggi:
Ricevi
BluetoothServerSocket
chiamandolistenUsingRfcommWithServiceRecord(String, UUID)
La stringa è un nome identificabile del servizio, che il sistema scrive automaticamente su una nuova voce del database Service Discovery Protocol (SDP) sul dispositivo. Il nome è arbitrario e può essere semplicemente il nome della tua app. La voce SDP include anche l'Universally Unique Identifier (UUID) e costituisce la base del contratto di connessione con il dispositivo client. Questo è che quando il client tenta di connettersi a questo dispositivo, utilizza un UUID che identifichi in modo univoco il servizio a cui vuole connettersi. Questi Gli UUID devono corrispondere affinché la connessione venga accettata.
Un UUID è un formato standardizzato a 128 bit per un ID stringa utilizzato per identificare le informazioni. L'UUID viene utilizzato per identificare le informazioni che devono essere univoco all'interno di un sistema o di una rete perché è probabile che un UUID sia ripetuto è pari a zero. Viene generato in modo indipendente, senza l'utilizzo di un'autorità centralizzata. In questo caso, viene utilizzato per identificare in modo univoco servizio Bluetooth dell'app. Per ottenere un UUID da usare con la tua app, puoi usarne uno dei molti
UUID
sul web, quindi inizializza un'immagine UUID confromString(String)
.Inizia ad ascoltare le richieste di connessione chiamando
accept()
Questa è una chiamata di blocco. Viene restituito quando una connessione è stata accettati o si è verificata un'eccezione. La connessione viene accettata solo quando il dispositivo remoto ha inviato una richiesta di connessione contenente un UUID che corrisponde quello registrato con il socket del server di ascolto. Una volta completata l'operazione,
accept()
restituisce unBluetoothSocket
connesso.A meno che tu non voglia accettare altri contatti, chiama
close()
Questa chiamata al metodo rilascia il socket del server e tutte le sue risorse, ma non chiude il dispositivo
BluetoothSocket
connesso restituito daaccept()
. A differenza di TCP/IP, RFCOMM consente un solo client connesso per canale alla volta, quindi nella maggior parte dei casi ha senso chiamareclose()
BluetoothServerSocket
subito dopo l'accettazione di un socket connesso.
Poiché la chiamata accept()
è di blocco, non eseguirla nell'istanza
thread della UI delle attività. L'esecuzione in un altro thread assicura che la tua app possa
rispondere comunque ad altre interazioni degli utenti. Di solito ha senso svolgere tutte le attività
che coinvolge BluetoothServerSocket
o BluetoothSocket
in un nuovo thread
gestiti dalla tua app. Per interrompere una chiamata bloccata, ad esempio accept()
, chiama close()
in BluetoothServerSocket
o BluetoothSocket
da un altro thread. Nota
che tutti i metodi su BluetoothServerSocket
o BluetoothSocket
siano
sicura per i thread.
Esempio
Di seguito è riportato un thread semplificato per il componente server che accetta connessioni in entrata:
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); } } }
In questo esempio, occorre una sola connessione in entrata, quindi non appena
connessione è accettata e il BluetoothSocket
viene acquisito, l'app trasmette il
acquisito BluetoothSocket
in un thread separato, chiude
BluetoothServerSocket
ed esce dal ciclo.
Tieni presente che quando accept()
restituisce BluetoothSocket
, il socket è già
connesso. Pertanto, non devi chiamare
connect()
, mentre procedi
dal lato client.
Il metodo manageMyConnectedSocket()
specifico dell'app è progettato per avviare il
per il trasferimento dei dati, di cui abbiamo parlato nell'argomento
trasferimento Bluetooth
di archiviazione dati.
In genere, devi chiudere BluetoothServerSocket
appena hai finito
per ascoltare le connessioni in arrivo. In questo esempio, close()
viene chiamato
con l'acquisizione di BluetoothSocket
. Puoi anche fornire un'interfaccia
nel thread che può chiudere l'elemento BluetoothSocket
privato nell'evento
che devi interrompere l'ascolto sul socket del server.
Connettiti come cliente
Per avviare una connessione con un dispositivo remoto che accetta
su un socket server aperto, devi prima ottenere un BluetoothDevice
che rappresenta il dispositivo remoto. Per scoprire come creare un
BluetoothDevice
, leggi l'articolo Trovare il Bluetooth
dispositivi mobili. Devi
utilizza BluetoothDevice
per acquisire un BluetoothSocket
e avviare la
connessione.
La procedura di base è la seguente:
Utilizzando l'
BluetoothDevice
, riceviBluetoothSocket
chiamandocreateRfcommSocketToServiceRecord(UUID)
Questo metodo inizializza un oggetto
BluetoothSocket
che consente al client di connettersi a unBluetoothDevice
. L'UUID trasferito qui deve corrispondere all'UUID utilizzato dal dispositivo server quando ha chiamatolistenUsingRfcommWithServiceRecord(String, UUID)
per aprire il relativoBluetoothServerSocket
. Per utilizzare un UUID corrispondente, esegui l'hard-coding del la stringa UUID nell'app e farvi riferimento sia dal server e il codice client.Avvia la connessione chiamando il numero
connect()
. Tieni presente che questo metodo è un bloccare la chiamata.Dopo che un client chiama questo metodo, il sistema esegue una ricerca SDP per trovare il dispositivo remoto con l'UUID corrispondente. Se la ricerca ha esito positivo e dispositivo remoto accetta la connessione, condivide il canale RFCOMM per l'utilizzo durante la connessione e restituisce il metodo
connect()
. Se la connessione non riesce o se il metodoconnect()
si verifica in timeout (dopo circa 12 secondi), il metodo genera unIOException
.
Poiché connect()
è una chiamata di blocco, dovresti sempre eseguirla
in un thread separato dall'attività principale (UI)
.
Esempio
Di seguito è riportato un esempio base di thread client che avvia una connessione Bluetooth connessione:
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); } } }
Tieni presente che in questo snippet, cancelDiscovery()
viene chiamato prima della connessione
che si verifica. Devi sempre chiamare cancelDiscovery()
prima del giorno connect()
,
soprattutto perché cancelDiscovery()
va a buon fine a prescindere dal fatto che il dispositivo
è attualmente in corso. Se la tua app ha bisogno di determinare
è in corso il rilevamento del dispositivo. Puoi controllare
isDiscovering()
Il metodo manageMyConnectedSocket()
specifico dell'app è progettato per avviare il
per il trasferimento dei dati, illustrato nella sezione
trasferire dati Bluetooth.
Quando hai finito di usare il tuo BluetoothSocket
, chiama sempre close()
. In questo modo
chiude immediatamente il socket collegato e rilascia tutti i componenti
Google Cloud.