Crea uno scanner Bluetooth con l'API Bluetooth di Android

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à:

  • abilitare il Bluetooth su un dispositivo
  • mostra un elenco di dispositivi accoppiati
  • scopri ed elenca i dispositivi Bluetooth vicini

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.

1. Abilitazione Bluetooth

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); 

2. Ottenere una lista di dispositivi accoppiati

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:

  • sconosciuto
  • accoppiato
  • collegato

È 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); 

3. Scopri dispositivi Bluetooth vicini

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.

4. Connessione a un dispositivo

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.

Conclusione

Abbiamo creato con successo il nostro scanner Bluetooth e abbiamo appreso quanto segue:

  • richiedere le autorizzazioni Bluetooth necessarie
  • abilitare il Bluetooth sul telefono
  • ottieni un elenco di dispositivi associati
  • scansiona e visualizza un elenco di dispositivi Bluetooth nelle vicinanze
  • stabilire una connessione Bluetooth tra due dispositivi
  • inviare e ricevere dati tramite una connessione Bluetooth

Sentiti libero di usare il codice nel progetto finito su GitHub e modificarlo nelle tue applicazioni.