Opprett en Bluetooth-skanner Med Android's Bluetooth-API

Bluetooth er blitt en svært populær teknologi, spesielt på mobile enheter. Det er en teknologi for å oppdage og overføre data mellom nærliggende enheter. Nesten alle moderne mobile enheter har Bluetooth-funksjoner i disse dager. Hvis du vil lage et appgrensesnitt med en annen Bluetooth-aktivert enhet, alt fra telefoner til høyttalere, må du vite hvordan du bruker Android's Bluetooth-API.

I denne veiledningen vil vi lage en app som ligner på den innebygde Bluetooth-appen i Android-innstillingene. Det vil inneholde følgende funksjoner:

  • aktiver Bluetooth på en enhet
  • vis en liste over sammenkoblede enheter
  • oppdag og list i nærheten Bluetooth-enheter

Vi vil også gå over det grunnleggende for å koble til og sende data til en annen Bluetooth-enhet. Jeg har opprettet et prosjekt for å komme i gang, som du kan laste ned fra GitHub. Nedenfor skjermbildet illustrerer hva startprosjektet ser ut. Hvis du sitter fast eller får problemer, kan du se på det ferdige prosjektet på GitHub.

1. Aktiverer Bluetooth

Før vi kan aktivere Bluetooth på en Android-enhet, må vi be om nødvendige tillatelser. Vi gjør dette i appens manifest. De BLÅTANN tillatelse tillater appen vår å koble til, koble fra og overføre data med en annen Bluetooth-enhet. De BLUETOOTH_ADMIN Tillatelse tillater at appen vår finner nye Bluetooth-enheter og endrer enhetens Bluetooth-innstillinger.

  

Vi bruker Bluetooth-adapteren til grensesnitt med Bluetooth. Vi ordner adapteren i ListActivity klasse. Hvis adapteren er null, Dette betyr at Bluetooth ikke støttes av enheten, og appen fungerer ikke på den gjeldende enheten. Vi håndterer denne situasjonen ved å vise en varslingsdialog til brukeren og avslutte appen.

@Override protected void onCreate (Bundle savedInstanceState) ... BTAdapter = BluetoothAdapter.getDefaultAdapter (); // Telefonen støtter ikke Bluetooth, så la brukeren vite og avslutte. hvis (BTAdapter == null) ny AlertDialog.Builder (this) .setTitle ("Ikke kompatibel") .setMessage ("Telefonen støtter ikke Bluetooth") .setPositiveButton ("Exit", ny DialogInterface.OnClickListener void onClick (DialogInterface dialog, int som) System.exit (0);) .setIcon (android.R.drawable.ic_dialog_alert) .show (); 

Hvis Bluetooth er tilgjengelig på enheten, må vi aktivere det. For å aktivere Bluetooth, starter vi en hensikt gitt til oss av Android SDK, BluetoothAdapter.ACTION_REQUEST_ENABLE. Dette vil presentere en dialog til brukeren, spør dem om tillatelse til å aktivere Bluetooth på enheten. REQUEST_BLUETOOTH er et statisk heltall vi angir for å identifisere aktivitetsforespørselen.

offentlig klasse ListActivity utvider ActionBarActivity implementerer DeviceListFragment.OnFragmentInteractionListener offentlig statisk int REQUEST_BLUETOOTH = 1; ... beskyttet tomt onCreate (Bundle savedInstanceState) ... hvis (! BTAdapter.isEnabled ()) Intent enableBT = new Intent (BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult (enableBT, REQUEST_BLUETOOTH); 

2. Oppnå en liste over sammenkoblede enheter

I dette trinnet skanner vi etter parede Bluetooth-enheter og viser dem på en liste. I forbindelse med en mobil enhet kan en Bluetooth-enhet enten være:

  • ukjent
  • sammen
  • tilkoblet

Det er viktig å vite forskjellen mellom en parret og en tilkoblet Bluetooth-enhet. Parrede enheter er klar over hverandres eksistens og deler en koblingsnøkkel, som kan brukes til å autentisere, som resulterer i en tilkobling. Enheter kobles automatisk sammen når en kryptert tilkobling er opprettet.

Tilkoblede enheter deler en RFCOMM-kanal, slik at de kan sende og motta data. En enhet kan ha mange sammenkoblede enheter, men den kan bare kobles til en enhet av gangen.

Bluetooth-enheter er representert av BluetoothDevice gjenstand. En liste over sammenkoblede enheter kan fås ved å påkalle getBondedDevices () metode, som returnerer et sett av BluetoothDevice objekter. Vi påberoper getBondedDevices () metode i DeviceListFragment's onCreate () metode.

Offentlig tomgang onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); Log.d ("DEVICELIST", "Super kalt DeviceListFragment onCreate \ n"); deviceItemList = ny ArrayList(); Sett pairedDevices = bTAdapter.getBondedDevices (); 

Vi bruker getName () og getAddress ()  metoder for å få mer informasjon om Bluetooth-enhetene. De getName () Metoden returnerer den offentlige identifikatoren til enheten mens getAddress () Metoden returnerer enhetens MAC-adresse, en identifikator som identifiserer enheten enestående.

Nå som vi har en liste over de sammenkoblede enhetene, oppretter vi en DeviceItem objekt for hver BluetoothDevice gjenstand. Vi legger til hver DeviceItem motsette seg en oppstilling som heter deviceItemList. Vi bruker denne gruppen til å vise listen over parrede Bluetooth-enheter i vår app. Koden for å vise listen over DeviceItem objekter er allerede til stede i startprosjektet.

hvis (pairedDevices.size ()> 0) for (BluetoothDevice-enhet: pairedDevices) DeviceItem newDevice = ny DeviceItem (device.getName (), device.getAddress (), "false"); deviceItemList.add (newDevice); 

3. Oppdag Bluetooth-enheter i nærheten

Det neste trinnet er å oppdage enheter enheten ikke er sammenkoblet med ennå, ukjent enheter, og legg dem til i listen over sammenkoblede enheter. Vi gjør dette når brukeren tapper skanneknappen. Koden for å håndtere dette er plassert i DeviceListFragment.

Vi må først lage en BroadcastReceiver og tilsidesatte OnReceive () metode. De OnReceive () Metoden påberopes når en Bluetooth-enhet er funnet.

De OnReceive () Metoden tar en hensikt som sitt andre argument. Vi kan sjekke hvilken form for hensikt å kringkaste med ved å påberope seg getAction (). Hvis handlingen er BluetoothDevice.ACTION_FOUND, da vet vi at vi har funnet en Bluetooth-enhet. Når dette skjer, oppretter vi en DeviceItem objekt ved hjelp av enhetens navn og MAC-adresse. Til slutt legger vi til DeviceItem protestere mot ArrayAdapter å vise den i appen vår.

offentlig klasse DeviceListFragment utvider Fragment implementerer AbsListView.OnItemClickListener ... privat endelig BroadcastReceiver bReciever = ny BroadcastReceiver () offentlig ugyldig onReceive (Kontekst kontekst, Intent intent) String action = intent.getAction (); hvis (BluetoothDevice.ACTION_FOUND.equals (handling)) BluetoothDevice device = intent.getParcelableExtra (BluetoothDevice.EXTRA_DEVICE); // Opprett en ny enhetenhet DeviceItem newDevice = ny DeviceItem (device.getName (), device.getAddress (), "false"); // Legg det til vår adapter mAdapter.add (newDevice); ; 

Når skanneknappen slås på, må vi bare registrere mottakeren vi nettopp har laget og påkalle startDiscovery () metode. Hvis skanneknappen slås av, avregistrerer vi mottakeren og påkaller cancelDiscovery (). Husk at oppdagelsen tar opp mange ressurser. Hvis søknaden din kobles til en annen Bluetooth-enhet, bør du alltid avbryte funn før du kobler til.

Vi fjerner også ArrayAdapter gjenstand, mAdapter, når oppdagelsen begynner. Når vi begynner å skanne, vil vi ikke inkludere gamle enheter som kanskje ikke lenger er innenfor rekkevidde av enheten.

offentlig visning onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) View view = inflater.inflate (R.layout.fragment_deviceitem_list, container, false); ToggleButton scan = (ToggleButton) view.findViewById (R.id.scan); ... scan.setOnCheckedChangeListener (ny CompoundButton.OnCheckedChangeListener () offentlig ugyldig påCheckedChanged (CompoundButton buttonView, boolean isChecked) IntentFilter filter = ny IntentFilter (BluetoothDevice.ACTION_FOUND) Hvis (isChecked) mAdapter.clear (); getActivity (). registerReceiver (bReciever, filter); bTAdapter.startDiscovery (); else getActivity (). unregisterReceiver (bReciever); bTAdapter.cancelDiscovery (); ); 

Det er det. Vi har fullført vår Bluetooth-skanner.

4. Koble til en enhet

Bluetooth-tilkoblinger fungerer som alle andre tilkoblinger. Det er en server og en klient som kommuniserer via RFCOMM-kontakter. På Android er RFCOMM-stikkontakter representert som en BluetoothSocket gjenstand. Heldigvis for oss håndteres mesteparten av den tekniske koden for servere av Android SDK og tilgjengelig via Bluetooth API.

Koble til som klient er enkelt. Din første får RFCOMM-kontakten fra ønsket BluetoothDevice ved å ringe createRfcommSocketToServiceRecord (), passerer i en UUID, en 128-biters verdi som du oppretter. UUID ligner på et portnummer.

For eksempel, anta at du lager en chat-app som bruker Bluetooth for å chatte med andre nærliggende brukere. For å finne andre brukere å chatte med, vil du se etter andre enheter med chat-appen din installert. For å gjøre dette, ville vi se etter UUID i listen over tjenester av de nærliggende enhetene. Ved å bruke en UUID til å lytte og godta Bluetooth-tilkoblinger, legger du automatisk til at UUID til telefonens liste over tjenester, eller tjenesteoppdagingsprotokoll.

Først når BluetoothSocket er opprettet, du ringer koble()BluetoothSocket. Dette vil initialisere en forbindelse med BluetoothDevice gjennom RFCOMM-kontakten. Når enheten er koblet til, kan vi bruke stikkontakten til å utveksle data med den tilkoblede enheten. Å gjøre dette ligner på hvilken som helst standard serverimplementering.

Vedlikehold av en Bluetooth-tilkobling er kostbar, så vi må lukke stikkontakten når vi ikke lenger trenger det. For å lukke stikkontakten, ringer vi Lukk()BluetoothSocket.

Følgende kodestykke viser hvordan du kobler til en gitt BluetoothDevice:

offentlig klasse ConnectThread utvider tråden private BluetoothSocket bTSocket; offentlig boolsk tilkobling (BluetoothDevice bTDevice, UUID MOUSE) BluetoothSocket temp = null; prøv temp = bTDevice.createRfcommSocketToServiceRecord (mUUID);  catch (IOException e) Log.d ("CONNECTTHREAD", "Kunne ikke opprette RFCOMM-socket:" + e.toString ()); returner falsk;  prøv bTSocket.connect ();  fangst (IOException e) Log.d ("CONNECTTHREAD", "Kunne ikke koble til:" + e.toString ()); prøv bTSocket.close ();  fangst (IOException nær) Log.d ("CONNECTTHREAD", "Kunne ikke lukke tilkobling:" + e.toString ()); returner falsk;  returnere sann;  offentlig boolean avbryt () prøv bTSocket.close ();  fangst (IOException e) Log.d ("CONNECTTHREAD", "Kunne ikke lukke tilkobling:" + e.toString ()); returner falsk;  returnere sann; 

Koble til som en server er litt vanskeligere. Først fra din BluetoothAdapter, du må få en BluetoothServerSocket, som vil bli brukt til å lytte etter en tilkobling. Dette brukes bare til å oppnå forbindelsens delte RFCOMM-kontakt. Når forbindelsen er etablert, trenger ikke serverkontakten lenger, og kan lukkes ved å ringe Lukk() på den.

Vi sender en serverkontakt ved å ringe listenUsingRfcommWithServiceRecord (Strenge navn, UUID mUUID). Denne metoden tar to parametere, et navn på typen string og en unik identifikator av typen UUID. Navnetparameteren er navnet vi gir tjenesten når det legges til telefonens SDP (Service Discovery Protocol) -oppføring. Den unike identifikatoren bør samsvare med UUID-klienten som prøver å koble til, bruker.

Vi ringer da aksepterer() på den nylig oppnådde BluetoothServerSocket å vente på en tilkobling. Når aksepterer() anrop returnerer noe som ikke er det null, Vi tildeler den til vår BluetoothSocket, som vi kan bruke til å utveksle data med den tilkoblede enheten.

Følgende kodestykke viser hvordan du godtar en tilkobling som en server:

offentlig klasse ServerConnectThread utvider tråden private BluetoothSocket bTSocket; offentlig ServerConnectThread ()  offentlig tomgang akseptererkobling (BluetoothAdapter bTAdapter, UUID-mUUID) BluetoothServerSocket temp = null; prøv temp = bTAdapter.listenUsingRfcommWithServiceRecord ("Service_Name", mUUID);  fangst (IOException e) Log.d ("SERVERCONNECT", "Kunne ikke få en BluetoothServerSocket:" + e.toString ());  mens (sann) prøv bTSocket = temp.accept ();  catch (IOException e) Log.d ("SERVERCONNECT", "Kunne ikke akseptere en innkommende forbindelse."); gå i stykker;  hvis (bTSocket! = null) prøv temp.close ();  fangst (IOException e) Log.d ("SERVERCONNECT", "Kunne ikke lukke ServerSocket:" + e.toString ());  gå i stykker;  offentlig tomt closeConnect () prøv bTSocket.close ();  fangst (IOException e) Log.d ("SERVERCONNECT", "Kunne ikke lukke tilkobling:" + e.toString ()); 

Lesing og skriving til forbindelsen gjøres ved hjelp av bekker, Input og OutputStream. Vi kan få en referanse til disse strømmene ved å ringe getInputStream () og getOutputStream () på BluetoothSocket. For å lese fra og skrive til disse strømmene, ringer vi lese() og skrive() henholdsvis.

Følgende kodestykke viser hvordan du gjør dette for et heltall:

offentlig klasse ManageConnectThread utvider thread public ManageConnectThread ()  offentlig ugyldig sendData (BluetoothSocket socket, int data) kaster IOException ByteArrayOutputStream output = ny ByteArrayOutputStream (4); output.write (data); OutputStream outputStream = socket.getOutputStream (); outputStream.write (output.toByteArray ());  offentlige int receiveData (BluetoothSocket socket) kaster IOException byte [] buffer = new byte [4]; ByteArrayInputStream input = ny ByteArrayInputStream (buffer); InputStream inputStream = socket.getInputStream (); inputStream.read (buffer); returnere input.read (); 

Du finner begge eksemplene i det ferdige prosjektet på GitHub.

Konklusjon

Vi har lykkes med å lage vår egen Bluetooth-skanner og lært følgende:

  • Be om nødvendige Bluetooth-tillatelser
  • aktiver Bluetooth på telefonen din
  • få en liste over sammenkoblede enheter
  • skann og vis en liste over nærliggende Bluetooth-enheter
  • opprett en Bluetooth-tilkobling mellom to enheter
  • send og motta data via en Bluetooth-tilkobling

Ta gjerne koden i det ferdige prosjektet på GitHub og modifiser det i dine egne applikasjoner.