Maak een Bluetooth-scanner met de Bluetooth-API van Android

Bluetooth is een zeer populaire technologie geworden, vooral op mobiele apparaten. Het is een technologie om gegevens te detecteren en over te zetten tussen apparaten in de buurt. Vrijwel elk modern mobiel apparaat heeft tegenwoordig Bluetooth-mogelijkheden. Als u een app-interface met een ander Bluetooth-apparaat wilt maken, van telefoons tot luidsprekers, moet u weten hoe u de Bluetooth API van Android moet gebruiken.

In deze zelfstudie maken we een app die vergelijkbaar is met de ingebouwde Bluetooth-app in de instellingen van Android. Het bevat de volgende functies:

  • schakel Bluetooth op een apparaat in
  • een lijst met gepaarde apparaten weergeven
  • Ontdek en vermeld Bluetooth-apparaten in de buurt

We zullen ook de basis bespreken om verbinding te maken en gegevens naar een ander Bluetooth-apparaat te verzenden. Ik heb een project gemaakt om ons op weg te helpen, dat je kunt downloaden van GitHub. De onderstaande schermafbeelding illustreert hoe het startersproject eruit ziet. Als je vastloopt of problemen tegenkomt, kun je het voltooide project op GitHub bekijken.

1. Bluetooth inschakelen

Voordat we Bluetooth op een Android-apparaat kunnen inschakelen, moeten we de benodigde machtigingen aanvragen. We doen dit in het manifest van de app. De BLUETOOTH Met toestemming kan onze app gegevens verbinden, ontkoppelen en overbrengen met een ander Bluetooth-apparaat. De BLUETOOTH_ADMIN Met toestemming kan onze app nieuwe Bluetooth-apparaten ontdekken en de Bluetooth-instellingen van het apparaat wijzigen.

  

We zullen de Bluetooth-adapter gebruiken om te communiceren met Bluetooth. We plaatsen de adapter in de ListActivity klasse. Als de adapter is nul, dit betekent dat Bluetooth niet wordt ondersteund door het apparaat en dat de app niet werkt op het huidige apparaat. We verwerken deze situatie door een waarschuwingsdialoogvenster voor de gebruiker weer te geven en de app te verlaten.

@Override protected void onCreate (Bundle savedInstanceState) ... BTAdapter = BluetoothAdapter.getDefaultAdapter (); // Telefoon ondersteunt geen Bluetooth, dus laat de gebruiker het weten en verlaat het. if (BTAdapter == null) new AlertDialog.Builder (this) .setTitle ("Not compatible") .setMessage ("Uw telefoon ondersteunt geen Bluetooth") .setPositiveButton ("Exit", nieuwe DialogInterface.OnClickListener () public void onClick (dialoog DialogInterface, int die) System.exit (0);) .setIcon (android.R.drawable.ic_dialog_alert) .show (); 

Als Bluetooth beschikbaar is op het apparaat, moeten we dit inschakelen. Om Bluetooth in te schakelen, starten we een intentie die ons wordt geboden door de Android SDK, BluetoothAdapter.ACTION_REQUEST_ENABLE. Hiermee wordt een dialoogvenster voor de gebruiker weergegeven met toestemming om Bluetooth op het apparaat in te schakelen. REQUEST_BLUETOOTH is een statisch geheel getal dat we instellen om het activiteitsverzoek te identificeren.

public class ListActivity breidt ActionBarActivity implementeert 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. Een lijst met gepaarde apparaten verkrijgen

In deze stap scannen we naar gekoppelde Bluetooth-apparaten en geven deze weer in een lijst. In de context van een mobiel apparaat kan een Bluetooth-apparaat zijn:

  • onbekend
  • gepaarde
  • verbonden

Het is belangrijk om het verschil te weten tussen een gekoppeld en een verbonden Bluetooth-apparaat. Gekoppelde apparaten zijn zich bewust van elkaars bestaan ​​en delen een link-sleutel, die kan worden gebruikt om te authenticeren, resulterend in een verbinding. Apparaten worden automatisch gekoppeld zodra een gecodeerde verbinding tot stand is gebracht.

Verbonden apparaten delen een RFCOMM-kanaal, waardoor ze gegevens kunnen verzenden en ontvangen. Een apparaat kan veel gepaarde apparaten hebben, maar kan slechts op één apparaat tegelijkertijd worden aangesloten.

Bluetooth-apparaten worden weergegeven door de BluetoothDevice voorwerp. Een lijst met gepaarde apparaten kan worden verkregen door de getBondedDevices () methode, die een set retourneert BluetoothDevice voorwerpen. We roepen het getBondedDevices () methode in de DeviceListFragment's onCreate () methode.

public void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); Log.d ("DEVICELIST", "Super riep op tot DeviceListFragment onCreate \ n"); deviceItemList = nieuwe ArrayList(); set pairedDevices = bTAdapter.getBondedDevices (); 

Wij gebruiken de getName () en getAddress ()  methoden om meer informatie over de Bluetooth-apparaten te verkrijgen. De getName () methode retourneert de publieke id van het apparaat terwijl het getAddress () methode retourneert het MAC-adres van het apparaat, een ID die het apparaat op unieke wijze identificeert.

Nu we een lijst hebben van de gekoppelde apparaten, maken we een DeviceItem object voor elk BluetoothDevice voorwerp. We voegen vervolgens elk toe DeviceItem bezwaar maken tegen een array met de naam deviceItemList. We gebruiken deze array om de lijst met gekoppelde Bluetooth-apparaten in onze app weer te geven. De code voor het weergeven van de lijst met DeviceItem objecten zijn al aanwezig in het startersproject.

if (paired Devices.size ()> 0) for (Bluetooth Device apparaat: paired Devices) DeviceItem newDevice = new DeviceItem (device.getName (), device.getAddress (), "false"); deviceItemList.add (newDevice); 

3. Ontdek Bluetooth-apparaten in de buurt

De volgende stap is het ontdekken van apparaten waarmee het apparaat nog niet is gekoppeld, onbekend apparaten en voeg ze toe aan de lijst met gekoppelde apparaten. We doen dit wanneer de gebruiker op de scanknop tikt. De code om dit aan te pakken bevindt zich in DeviceListFragment.

We moeten eerst een maken Uitzending ontvanger en negeer de onReceive () methode. De onReceive () methode wordt aangeroepen wanneer een Bluetooth-apparaat wordt gevonden.

De onReceive () methode neemt een intentie als zijn tweede argument. We kunnen controleren met wat voor intentie wordt uitgezonden door aan te roepen getAction (). Als de actie is BluetoothDevice.ACTION_FOUND, dan weten we dat we een Bluetooth-apparaat hebben gevonden. Wanneer dit gebeurt, maken we een DeviceItem object met behulp van de naam van het apparaat en het MAC-adres. Ten slotte voegen we de DeviceItem bezwaar tegen de ArrayAdapter om het in onze app weer te geven.

public class DeviceListFragment breidt Fragment-implementaties uit AbsListView.OnItemClickListener ... private final BroadcastReceiver bReciever = new BroadcastReceiver () public void onReceive (Context-context, Intent opzet) String action = intent.getAction (); if (BluetoothDevice.ACTION_FOUND.equals (action)) BluetoothDevice device = intent.getParcelableExtra (BluetoothDevice.EXTRA_DEVICE); // Maak een nieuw apparaatitem DeviceItem newDevice = nieuw DeviceItem (device.getName (), device.getAddress (), "false"); // Voeg het toe aan onze adapter mAdapter.add (newDevice); ; 

Wanneer de scanknop is ingeschakeld, moeten we gewoon de ontvanger registreren die we zojuist hebben gemaakt en de startDiscovery () methode. Als de scanknop is uitgeschakeld, wordt de registratie van de ontvanger ongedaan gemaakt en wordt er een beroep op gedaan cancelDiscovery (). Houd er rekening mee dat ontdekking veel bronnen in beslag neemt. Als uw toepassing verbinding maakt met een ander Bluetooth-apparaat, moet u de ontdekking altijd annuleren voordat u verbinding maakt.

We wissen ook de ArrayAdapter voorwerp, mAdapter, wanneer de ontdekking begint. Wanneer we beginnen met scannen, willen we geen oude apparaten toevoegen die zich mogelijk niet meer binnen het bereik van het apparaat bevinden.

public Bekijk onCreateView (LayoutInflater inflater, ViewGroup-container, Bundel savedInstanceState) View 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 (CompoundButton-knopView, boolean isChecked) IntentFilter filter = new IntentFilter (BluetoothDevice.ACTION_FOUND) ; if (isChecked) mAdapter.clear (); getActivity (). registerReceiver (bReciever, filter); bTAdapter.startDiscovery (); else getActivity (). unregisterReceiver (bReciever); bTAdapter.cancelDiscovery (); ); 

Dat is het. We hebben onze Bluetooth-scanner voltooid.

4. Verbinding maken met een apparaat

Bluetooth-verbindingen werken zoals elke andere verbinding. Er is een server en een client die communiceren via RFCOMM-sockets. Op Android worden RFCOMM-sockets weergegeven als een BluetoothSocket voorwerp. Gelukkig voor ons, wordt de meeste technische code voor servers afgehandeld door de Android SDK en beschikbaar via de Bluetooth API.

Verbinden als een klant is eenvoudig. Uw eerste verkrijgt u de RFCOMM-socket van de gewenste BluetoothDevice door te bellen createRfcommSocketToServiceRecord (), doorgeven van een UUID, een 128-bits waarde die u maakt. De UUID is vergelijkbaar met een poortnummer.

Laten we bijvoorbeeld aannemen dat u een chat-app maakt die Bluetooth gebruikt om te chatten met andere gebruikers in de buurt. Om andere gebruikers te vinden om mee te chatten, wilt u op zoek naar andere apparaten waarop uw chathulp is geïnstalleerd. Om dit te doen, zouden we de UUID zoeken in de lijst met services van de apparaten in de buurt. Als u een UUID gebruikt om te luisteren en Bluetooth-verbindingen te accepteren, wordt die UUID automatisch toegevoegd aan de lijst met services van de telefoon of aan het protocol voor detectie van services.

Zodra de BluetoothSocket is gemaakt, jij belt aansluiten() op de BluetoothSocket. Hiermee initialiseert u een verbinding met de BluetoothDevice via de RFCOMM-socket. Zodra ons apparaat is verbonden, kunnen we de socket gebruiken om gegevens uit te wisselen met het aangesloten apparaat. Dit doen is vergelijkbaar met elke standaard serverimplementatie.

Het onderhouden van een Bluetooth-verbinding kost veel geld, dus we moeten de socket sluiten als we hem niet langer nodig hebben. Om de socket te sluiten, bellen we dichtbij() op de BluetoothSocket.

Het volgende codefragment laat zien hoe u verbinding maakt met een gegeven BluetoothDevice:

openbare klasse ConnectThread breidt Thread uit private BluetoothSocket bTSocket; public boolean connect (BluetoothDevice bTDevice, UUID mUUID) BluetoothSocket temp = null; probeer temp = bTDevice.createRfcommSocketToServiceRecord (mUUID);  catch (IOException e) Log.d ("CONNECTTHREAD", "Kon RFCOMM socket niet maken:" + e.toString ()); return false;  probeer bTSocket.connect ();  catch (IOException e) Log.d ("CONNECTTHREAD", "Could not connect:" + e.toString ()); probeer bTSocket.close ();  catch (IOException close) Log.d ("CONNECTTHREAD", "Kon verbinding niet sluiten:" + e.toString ()); return false;  return true;  public boolean cancel () try bTSocket.close ();  catch (IOException e) Log.d ("CONNECTTHREAD", "Kon verbinding niet sluiten:" + e.toString ()); return false;  return true; 

Verbinden als een server is iets moeilijker. Ten eerste, van jouw BluetoothAdapter, je moet een krijgen BluetoothServerSocket, welke zal worden gebruikt om naar een verbinding te luisteren. Dit wordt alleen gebruikt om de gedeelde RFCOMM-socket van de verbinding te verkrijgen. Zodra de verbinding tot stand is gebracht, is de serveraansluiting niet meer nodig en kan deze worden gesloten door te bellen dichtbij() ben ermee bezig.

We instantiëren een server socket door te bellen listenUsingRfcommWithServiceRecord (String naam, UUID mUUID). Deze methode neemt twee parameters, een naam van het type Draad en een unieke ID van het type UUID. De naamparameter is de naam die we de service geven wanneer deze wordt toegevoegd aan het SDP (Service Discovery Protocol) -item van de telefoon. De unieke ID moet overeenkomen met de UUID die de client probeert te verbinden gebruikt.

We bellen dan aanvaarden() op de nieuw verkregen BluetoothServerSocket om op een verbinding te wachten. Wanneer de aanvaarden() oproep retourneert iets dat niet is nul, we wijzen het toe aan onze BluetoothSocket, die we vervolgens kunnen gebruiken om gegevens uit te wisselen met het verbonden apparaat.

Het volgende codefragment laat zien hoe u een verbinding als server accepteert:

public class ServerConnectThread breidt Thread uit private BluetoothSocket bTSocket; public ServerConnectThread ()  public void acceptConnect (BluetoothAdapter bTAdapter, UUID mUUID) BluetoothServerSocket temp = null; probeer temp = bTAdapter.listenUsingRfcommWithServiceRecord ("Service_Name", mUUID);  catch (IOException e) Log.d ("SERVERCONNECT", "Kon geen BluetoothServerSocket verkrijgen:" + e.toString ());  while (true) try bTSocket = temp.accept ();  catch (IOException e) Log.d ("SERVERCONNECT", "Kon een binnenkomende verbinding niet accepteren."); breken;  if (bTSocket! = null) try temp.close ();  catch (IOException e) Log.d ("SERVERCONNECT", "Kon ServerSocket niet sluiten:" + e.toString ());  pauze;  public void closeConnect () try bTSocket.close ();  catch (IOException e) Log.d ("SERVERCONNECT", "Kon verbinding niet sluiten:" + e.toString ()); 

Lezen en schrijven naar de verbinding gebeurt met behulp van streams, InputStream en OutputStream. We kunnen een verwijzing naar deze streams krijgen door te bellen getInputStream () en getOutputStream () op de BluetoothSocket. Om te lezen van en te schrijven naar deze streams, bellen we lezen() en schrijven() respectievelijk.

In het volgende codefragment wordt getoond hoe u dit voor één geheel getal doet:

public class ManageConnectThread breidt Thread uit public ManageConnectThread ()  public void sendData (BluetoothSocket socket, int data) gooit IOException ByteArrayOutputStream output = new ByteArrayOutputStream (4); output.write (data); OutputStream outputStream = socket.getOutputStream (); outputStream.write (output.toByteArray ());  public int receiveData (BluetoothSocket-socket) gooit IOException byte [] buffer = nieuwe byte [4]; ByteArrayInputStream input = new ByteArrayInputStream (buffer); InputStream inputStream = socket.getInputStream (); inputStream.read (buffer); return input.read (); 

Je kunt beide voorbeelden vinden in het voltooide project op GitHub.

Conclusie

We hebben met succes onze eigen Bluetooth-scanner gemaakt en hebben het volgende geleerd:

  • vraag de benodigde Bluetooth-machtigingen aan
  • schakel Bluetooth in op uw telefoon
  • krijg een lijst met gepaarde apparaten
  • een lijst met Bluetooth-apparaten in de buurt scannen en weergeven
  • een Bluetooth-verbinding tot stand brengen tussen twee apparaten
  • verzenden en ontvangen van gegevens via een Bluetooth-verbinding

Voel je vrij om de code in het voltooide project op GitHub te gebruiken en deze in je eigen applicaties aan te passen.