Il Bluetooth è diventato una tecnologia molto popolare, specialmente sui dispositivi mobili. È una tecnologia per scoprire e trasferire dati tra dispositivi vicini. Praticamente ogni moderno dispositivo mobile ha funzionalità Bluetooth in questi giorni. Se si desidera creare un'interfaccia di app con un altro dispositivo abilitato Bluetooth, che va dai telefoni agli altoparlanti, è necessario sapere come utilizzare l'API Bluetooth di Android.
In questo tutorial, creeremo un'app simile all'app Bluetooth integrata nelle impostazioni di Android. Comprenderà le seguenti funzionalità:
Verranno inoltre illustrati i concetti di base per connettere e inviare dati a un altro dispositivo Bluetooth. Ho creato un progetto per iniziare, che puoi scaricare da GitHub. L'immagine sottostante mostra come appare il progetto iniziale. Se rimani bloccato o incappi in problemi, allora puoi dare un'occhiata al progetto finito su GitHub.
Prima di poter abilitare il Bluetooth su un dispositivo Android, dobbiamo richiedere le autorizzazioni necessarie. Lo facciamo nel manifest di app. Il BLUETOOTH
permesso consente alla nostra app di connettersi, disconnettersi e trasferire dati con un altro dispositivo Bluetooth. Il BLUETOOTH_ADMIN
permesso consente alla nostra app di scoprire nuovi dispositivi Bluetooth e modificare le impostazioni Bluetooth del dispositivo.
Useremo l'adattatore Bluetooth per interfacciarsi con Bluetooth. Istanziamo l'adattatore nel ListActivity
classe. Se l'adattatore è nullo
, questo significa che Bluetooth non è supportato dal dispositivo e l'app non funzionerà sul dispositivo corrente. Gestiamo questa situazione mostrando una finestra di avviso all'utente e uscendo dall'app.
@Override protected void onCreate (Bundle savedInstanceState) ... BTAdapter = BluetoothAdapter.getDefaultAdapter (); // Il telefono non supporta il Bluetooth, quindi informalo e esci. if (BTAdapter == null) new AlertDialog.Builder (this) .setTitle ("Not compatible") .setMessage ("Il telefono non supporta Bluetooth") .setPositiveButton ("Exit", new DialogInterface.OnClickListener () public void onClick (DialogInterface dialog, int which) System.exit (0);) .setIcon (android.R.drawable.ic_dialog_alert) .show ();
Se Bluetooth è disponibile sul dispositivo, è necessario abilitarlo. Per abilitare il Bluetooth, iniziamo un intento fornitoci dall'SDK di Android, BluetoothAdapter.ACTION_REQUEST_ENABLE
. Questo presenterà una finestra di dialogo all'utente, chiedendo il permesso di abilitare il Bluetooth sul dispositivo. REQUEST_BLUETOOTH
è un numero intero statico che impostiamo per identificare la richiesta di attività.
public class ListActivity estende ActionBarActivity implementa DeviceListFragment.OnFragmentInteractionListener public static int REQUEST_BLUETOOTH = 1; ... protected void onCreate (Bundle savedInstanceState) ... if (! BTAdapter.isEnabled ()) Intent enableBT = new Intent (BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult (enableBT, REQUEST_BLUETOOTH);
In questo passaggio, scansioniamo i dispositivi Bluetooth accoppiati e li visualizziamo in un elenco. Nel contesto di un dispositivo mobile, un dispositivo Bluetooth può essere:
È importante conoscere la differenza tra un dispositivo Bluetooth associato e un dispositivo Bluetooth connesso. I dispositivi accoppiati sono a conoscenza dell'esistenza reciproca e condividono una chiave di collegamento, che può essere utilizzata per l'autenticazione, determinando una connessione. I dispositivi vengono accoppiati automaticamente una volta stabilita una connessione crittografata.
I dispositivi connessi condividono un canale RFCOMM, consentendo loro di inviare e ricevere dati. Un dispositivo può avere molti dispositivi associati, ma può essere connesso a un solo dispositivo alla volta.
I dispositivi Bluetooth sono rappresentati dal BluetoothDevice
oggetto. Un elenco di dispositivi associati può essere ottenuto invocando il getBondedDevices ()
metodo, che restituisce un insieme di BluetoothDevice
oggetti. Invochiamo il getBondedDevices ()
metodo nel DeviceListFragment
'S onCreate ()
metodo.
public void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); Log.d ("DEVICELIST", "Super called for DeviceListFragment onCreate \ n"); deviceItemList = new ArrayList(); Impostato pairedDevices = bTAdapter.getBondedDevices ();
Noi usiamo il getName ()
e getAddress ()
metodi per ottenere ulteriori informazioni sui dispositivi Bluetooth. Il getName ()
metodo restituisce l'identificatore pubblico del dispositivo mentre il getAddress ()
metodo restituisce l'indirizzo MAC del dispositivo, un identificatore che identifica in modo univoco il dispositivo.
Ora che abbiamo un elenco dei dispositivi associati, creiamo a DeviceItem
oggetto per ciascuno BluetoothDevice
oggetto. Quindi aggiungiamo ciascuno DeviceItem
oggetto a un array chiamato deviceItemList
. Useremo questo array per visualizzare l'elenco dei dispositivi Bluetooth accoppiati nella nostra app. Il codice per la visualizzazione dell'elenco di DeviceItem
gli oggetti sono già presenti nel progetto iniziale.
if (pairedDevices.size ()> 0) for (dispositivo BluetoothDevice: pairedDevices) DeviceItem newDevice = new DeviceItem (device.getName (), device.getAddress (), "false"); deviceItemList.add (newDevice);
Il passo successivo è quello di scoprire i dispositivi con i quali il dispositivo non è ancora associato, sconosciuto dispositivi e aggiungerli all'elenco dei dispositivi associati. Lo facciamo quando l'utente tocca il pulsante di scansione. Il codice per gestire questo è situato in DeviceListFragment
.
Prima dobbiamo fare un BroadcastReceiver
e scavalcare il OnReceive ()
metodo. Il OnReceive ()
il metodo viene richiamato ogni volta che viene trovato un dispositivo Bluetooth.
Il OnReceive ()
il metodo prende un intento come secondo argomento. Possiamo verificare con quale tipo di intento viene trasmesso invocando getAction ()
. Se l'azione è BluetoothDevice.ACTION_FOUND
, allora sappiamo di aver trovato un dispositivo Bluetooth. Quando ciò accade, creiamo a DeviceItem
oggetto utilizzando il nome del dispositivo e l'indirizzo MAC. Infine, aggiungiamo il DeviceItem
oggetto al ArrayAdapter
per visualizzarlo nella nostra app.
public class DeviceListFragment extends Fragment implements AbsListView.OnItemClickListener ... private final BroadcastReceiver bReciever = new BroadcastReceiver () public void onReceive (Contesto contesto, Intento intento) String action = intent.getAction (); if (BluetoothDevice.ACTION_FOUND.equals (action)) Dispositivo BluetoothDevice = intent.getParcelableExtra (BluetoothDevice.EXTRA_DEVICE); // Crea un nuovo dispositivo DeviceItem newDevice = new DeviceItem (device.getName (), device.getAddress (), "false"); // Aggiungilo al nostro adattatore mAdapter.add (newDevice); ;
Quando si attiva il pulsante di scansione, è sufficiente registrare il ricevitore appena creato e richiamare il startDiscovery ()
metodo. Se il pulsante di scansione è disattivato, annulliamo la registrazione del ricevitore e invochiamo cancelDiscovery ()
. Tieni presente che la scoperta richiede molte risorse. Se la tua applicazione si connette con un altro dispositivo Bluetooth, dovresti sempre annullare l'individuazione prima di connetterti.
Abbiamo anche chiaro il ArrayAdapter
oggetto, mAdapter
, quando inizia la scoperta Quando iniziamo la scansione, non vogliamo includere i vecchi dispositivi che potrebbero non essere più nel raggio di azione del dispositivo.
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) Visualizza view = inflater.inflate (R.layout.fragment_deviceitem_list, container, false); ToggleButton scan = (ToggleButton) view.findViewById (R.id.scan); ... scan.setOnCheckedChangeListener (new CompoundButton.OnCheckedChangeListener () public void onCheckedChanged (Pulsante CompoundButtonView, boolean isChecked) Filtro IntentFilter = new IntentFilter (BluetoothDevice.ACTION_FOUND) ; if (isChecked) mAdapter.clear (); getActivity (). registerReceiver (bReciever, filter); bTAdapter.startDiscovery (); else getActivity (). unregisterReceiver (bReciever); bTAdapter.cancelDiscovery (); );
Questo è tutto. Abbiamo finito il nostro scanner Bluetooth.
Le connessioni Bluetooth funzionano come qualsiasi altra connessione. C'è un server e un client, che comunicano tramite socket RFCOMM. Su Android, i socket RFCOMM sono rappresentati come BluetoothSocket
oggetto. Fortunatamente per noi, la maggior parte del codice tecnico per i server è gestito da Android SDK e disponibile tramite l'API Bluetooth.
Connettersi come client è semplice. La prima volta ottenere la presa RFCOMM dal desiderato BluetoothDevice
a chiamata createRfcommSocketToServiceRecord ()
, passando un UUID, un valore a 128 bit che crei. L'UUID è simile a un numero di porta.
Ad esempio, supponiamo che tu stia creando un'app di chat che utilizza Bluetooth per chattare con altri utenti nelle vicinanze. Per trovare altri utenti con cui chattare, dovresti cercare altri dispositivi con la tua app di chat installata. Per fare ciò, cercheremo l'UUID nell'elenco dei servizi dei dispositivi vicini. L'utilizzo di un UUID per ascoltare e accettare le connessioni Bluetooth aggiunge automaticamente l'UUID all'elenco dei servizi del telefono o al protocollo di rilevamento dei servizi.
Una volta il BluetoothSocket
viene creato, tu chiami Collegare()
sul BluetoothSocket
. Ciò inizializzerà una connessione con il BluetoothDevice
attraverso la presa RFCOMM. Una volta collegato il dispositivo, è possibile utilizzare la presa per scambiare dati con il dispositivo collegato. Fare ciò è simile a qualsiasi implementazione standard del server.
Mantenere una connessione Bluetooth è costoso, quindi abbiamo bisogno di chiudere il socket quando non ne abbiamo più bisogno. Per chiudere il socket, chiamiamo vicino()
sul BluetoothSocket
.
Il seguente frammento di codice mostra come connettersi con un dato BluetoothDevice
:
la classe pubblica ConnectThread estende Thread private BluetoothSocket bTSocket; collegamento booleano pubblico (BluetoothDevice bTDevice, UUID mUUID) BluetoothSocket temp = null; prova temp = bTDevice.createRfcommSocketToServiceRecord (mUUID); catch (IOException e) Log.d ("CONNECTTHREAD", "Impossibile creare socket RFCOMM:" + e.toString ()); restituisce falso; prova bTSocket.connect (); catch (IOException e) Log.d ("CONNECTTHREAD", "Impossibile connettersi:" + e.toString ()); prova bTSocket.close (); catch (IOException close) Log.d ("CONNECTTHREAD", "Impossibile chiudere la connessione:" + e.toString ()); restituisce falso; return true; public boolean cancel () try bTSocket.close (); catch (IOException e) Log.d ("CONNECTTHREAD", "Impossibile chiudere la connessione:" + e.toString ()); restituisce falso; return true;
La connessione come server è leggermente più difficile. Primo, dal tuo BluetoothAdapter
, devi ottenere un BluetoothServerSocket
, che sarà usato per ascoltare una connessione. Viene utilizzato solo per ottenere il socket RFCOMM condiviso della connessione. Una volta stabilita la connessione, il socket del server non è più necessario e può essere chiuso chiamando vicino()
su di esso.
Istanziamo un socket del server chiamando listenUsingRfcommWithServiceRecord (Nome stringa, UUID mUUID)
. Questo metodo richiede due parametri, un nome di tipo Stringa
e un identificatore univoco di tipo UUID
. Il parametro name è il nome che forniamo al servizio quando viene aggiunto alla voce SDP (Service Discovery Protocol) del telefono. L'identificatore univoco deve corrispondere all'UUID che sta utilizzando il client che tenta di connettersi.
Allora chiamiamo accettare()
sul nuovo ottenuto BluetoothServerSocket
aspettare una connessione. Quando il accettare()
la chiamata restituisce qualcosa che non lo è nullo
, lo assegniamo al nostro BluetoothSocket
, che possiamo quindi utilizzare per scambiare dati con il dispositivo connesso.
Il seguente frammento di codice mostra come accettare una connessione come server:
la classe pubblica ServerConnectThread estende Thread private BluetoothSocket bTSocket; public ServerConnectThread () public void acceptConnect (BluetoothAdapter bTAdapter, UUID mUUID) BluetoothServerSocket temp = null; prova temp = bTAdapter.listenUsingRfcommWithServiceRecord ("Service_Name", mUUID); catch (IOException e) Log.d ("SERVERCONNECT", "Impossibile ottenere un BluetoothServerSocket:" + e.toString ()); while (true) try bTSocket = temp.accept (); catch (IOException e) Log.d ("SERVERCONNECT", "Impossibile accettare una connessione in entrata."); rompere; if (bTSocket! = null) try temp.close (); catch (IOException e) Log.d ("SERVERCONNECT", "Impossibile chiudere ServerSocket:" + e.toString ()); rompere; public void closeConnect () try bTSocket.close (); catch (IOException e) Log.d ("SERVERCONNECT", "Impossibile chiudere la connessione:" + e.toString ());
La lettura e la scrittura della connessione vengono eseguite utilizzando i flussi, InputStream
e OutputStream
. Possiamo ottenere un riferimento a questi flussi chiamando getInputStream ()
e getOutputStream ()
sul BluetoothSocket
. Per leggere e scrivere su questi flussi, chiamiamo leggere()
e Scrivi()
rispettivamente.
Il seguente frammento di codice mostra come eseguire questa operazione per un singolo intero:
public class ManageConnectThread estende Thread public ManageConnectThread () public void sendData (socket BluetoothSocket, int data) genera IOException ByteArrayOutputStream output = new ByteArrayOutputStream (4); output.write (dati); OutputStream outputStream = socket.getOutputStream (); outputStream.write (output.toByteArray ()); public int receiveData (socket BluetoothSocket) genera IOException byte [] buffer = new byte [4]; ByteArrayInputStream input = new ByteArrayInputStream (buffer); InputStream inputStream = socket.getInputStream (); inputStream.read (buffer); return input.read ();
Puoi trovare entrambi gli esempi nel progetto finito su GitHub.
Abbiamo creato con successo il nostro scanner Bluetooth e abbiamo appreso quanto segue:
Sentiti libero di usare il codice nel progetto finito su GitHub e modificarlo nelle tue applicazioni.