Tutorial Android – Comunicação Bluetooth
Neste post iremos mostrar como usar o Bluetooth no Android — Configuração e — no Android. O desenvolvimento usará o Android Studio 2.1 e a versão 5.0 do Android(API 21) – com suporte ao Android 6.0(API 23) – .
Configuração do Ambiente para usar o Bluetooth
Após baixar o Android Studio e configurado o ambiente, comece um novo projeto.
Criação do projeto:
Ao criar um novo projeto, escolha a opção “Empty Activity”, aguarde a preparação do projeto feita de forma automática pelo Android Studio e você se deparará com a seguinte tela:
Criando a classe de suporte
Essa é a classe que da suporte à toda a comunicação Bluetooth, sem ela, nada seria possível no nosso tutorial. Clique no pacote java do seu projeto e vá em: new > Java Class.
Dê o nome que desejar, para efeito do tutorial, ela se chamará ConexaoBluetooth.
Declaração das variáveis utilizadas
private static ConexaoBluetooth conexao; //objeto que referencia a classe private final BluetoothAdapter BTAdapter = BluetoothAdapter.getDefaultAdapter(); //acessa o dispositivo bluetooth de um celular genérico private BluetoothDevice BTDevice; //todo acesso ao módulo bluetooth utilizado no tutorial será feito a partir deste objeto. private final BluetoothSocket BTSocket; // garante a instância da rede bluetooth entre o celular e o módulo private BufferedReader mBufferedReader = null; //lê as comunicações private final UUID activeUUID= UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // ID padrão da porta serial private boolean isConnected = true; // variável de controle da conexão private final int REQUEST_ENABLE_BT = 1; // Constante padrão para requisição de permissão de acesso ao bluetooth em tempo de execução.
Agora, alguns métodos que serão utilizados pelas activities do projeto.
//Construtor da classe private ConexaoBluetooth(BluetoothDevice device){ BTDevice = device; BluetoothSocket temp = null; try { temp = BTDevice.createRfcommSocketToServiceRecord(activeUUID); } catch (IOException io) { Log.i("LOG", "Erro IO"); } BTSocket = temp; if(BTAdapter.isDiscovering()) BTAdapter.cancelDiscovery(); try { InputStream aStream = null; InputStreamReader aReader = null; BTSocket.connect(); aStream = BTSocket.getInputStream(); aReader = new InputStreamReader( aStream ); mBufferedReader = new BufferedReader( aReader ); }catch (IOException e) { isConnected = false; return; } } //Garante a conexão com o módulo bluetooth public static ConexaoBluetooth getInstance(BluetoothDevice d, boolean subrescrever) { if (conexao == null) conexao = new ConexaoBluetooth(d); else if(subrescrever) { conexao = new ConexaoBluetooth(d); Log.i( "ConexaoBluetooth","Sobrescreveu a conexão"); } return conexao; } //Verifica o estado da conexão public boolean isConnected () { return BTAdapter.isEnabled(); } //Referencia a conexão public BluetoothSocket getConection() { return BTSocket; } //Termina a conexão public boolean finish() { try { BTSocket.close(); return true; } catch (IOException e) { return false; } }
O código da classe ConexaoBluetooth ficou assim:
package br.ufop.imobilis.tutorialbluetooth; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.util.Log; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.UUID; public class ConexaoBluetooth { private static ConexaoBluetooth conexao; private final BluetoothAdapter BTAdapter = BluetoothAdapter.getDefaultAdapter(); private BluetoothDevice BTDevice; private final BluetoothSocket BTSocket; private BufferedReader mBufferedReader = null; private final UUID activeUUID= UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //ID padrão da porta serial. private boolean isConnected = true; private final int REQUEST_ENABLE_BT = 1; public BufferedReader getmBufferedReader() { return mBufferedReader; } private ConexaoBluetooth(BluetoothDevice device) { BTDevice = device; BluetoothSocket temp = null; try { temp = BTDevice.createRfcommSocketToServiceRecord(activeUUID); } catch (IOException io) { Log.i("LOG", "Erro IO"); } BTSocket = temp; if(BTAdapter.isDiscovering()) BTAdapter.cancelDiscovery(); try { InputStream aStream = null; InputStreamReader aReader = null; BTSocket.connect(); aStream = BTSocket.getInputStream(); aReader = new InputStreamReader( aStream ); mBufferedReader = new BufferedReader( aReader ); }catch (IOException e) { isConnected = false; return; } } public static ConexaoBluetooth getInstance(BluetoothDevice d, boolean subrescrever) { if (conexao == null) conexao = new ConexaoBluetooth(d); else if(subrescrever) { conexao = new ConexaoBluetooth(d); Log.i( "ConexaoBluetooth","Sobrescreveu a conexão"); } return conexao; } public boolean isConnected () { return BTAdapter.isEnabled(); } public BluetoothSocket getConection() { return BTSocket; } public boolean finish() { try { BTSocket.close(); return true; } catch (IOException e) { return false; } } }
Configurando o AndroidManifest
Agora que a classe está pronta, o Android Studio acusará alguns erros, pois ele reconhecerá que para utilizar o adaptador Bluetooth do Android, será necessário permissões do usuário. Pois a interação com o Bluetooth é considerada uma permissão crítica(Clique aqui para saber mais sobre permissões perigosas).
Então, agora vá ao AndroidManifest.xml e edite-o para que a permissão seja requisitada ao usuário.
<uses-permission android:name="android.permission.BLUETOOTH" /> < uses-permission android:name="android.permission.BLUETOOTH_ADMIN" / >
Caso você deseje que seu projeto ofereça suporte ao Android 6.0, adicione também as permissões de localização.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
O código completo do AndroidManifest.xml ficou assim:
< ?xml version="1.0" encoding="utf-8"? > < manifest xmlns:android="http://schemas.android.com/apk/res/android" package="br.ufop.imobilis.tutorialbluetooth" > < uses-permission android:name="android.permission.BLUETOOTH" / > < uses-permission android:name="android.permission.BLUETOOTH_ADMIN" / > < uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" / > < uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" / > < application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> </manifest>
Agora, uma nova Activity será criada, ela é necessária para evitar problemas de sincronia no projeto. Sendo assim, ela só será chamada após a conexão ter sido estabelecida na MainActivity.
Criando a Activity de comunicação
Para criar uma nova Activity, segue-se um processo semelhante ao de criação de uma classe, clique no mesmo pacote java onde estão a MainActivity e a ConexãoBluetooth e vá em: New > Activity > Empty Activity.
Agora o projeto estará assim:
Declaração de variáveis
As variáveis necessárias para a comunicação de fato com o módulo Bluetooth serão estas.
private BluetoothSocket mmSocket; private OutputStream mmOutputStream; private InputStream mmInputStream; private Thread workerThread; private byte[] readBuffer; private int readBufferPosition; private volatile boolean stopWorker; //estabelecendo a conexão entre a activity e a classe de suporte private ConexaoBluetooth connection = ConexaoBluetooth.getInstance(null, false);
A Função de comunicação
Esta é a função que trata a comunicação feita com o módulo.
void beginListenForData() { final BufferedReader reader = connection.getmBufferedReader(); stopWorker = false; readBufferPosition = 0; readBuffer = new byte[1024]; workerThread = new Thread(new Runnable() { public void run() { while (!Thread.currentThread().isInterrupted() && !stopWorker) { try { String info = reader.readLine(); // recebe os dados da comunicação Toast.makeText(ReceivingData.this, "Mensagem recebida: " + info, Toast.LENGTH_SHORT).show(); mmOutputStream.write("OK".getBytes()); // envia dados. } catch (IOException ex) { stopWorker = true; } } } }); workerThread.start(); }
Essa função é uma Thread, que roda em paralelo com o resto do app em loop, sempre tratando a comunicação com o módulo Bluetooth.
Vale lembrar, que para mandar o que deseja, basta apenas colocar o que quiser no lugar do “OK”.
Agora recupere a conexão feita na MainActivity através de sua referência e chame a função beginListenForData().
try { mmOutputStream = mmSocket.getOutputStream(); mmInputStream = mmSocket.getInputStream(); mmOutputStream.write("AT".getBytes()); beginListenForData(); mmOutputStream.write("OK".getBytes()); Toast.makeText(ReceivingData.this, "Recebendo dados do Bluetooth", Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); }
O código da ReceivingData ficou assim:
package br.ufop.imobilis.tutorialbluetooth; import android.bluetooth.BluetoothSocket; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Toast; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class ReceivingData extends AppCompatActivity { private BluetoothSocket mmSocket; private OutputStream mmOutputStream; private InputStream mmInputStream; private Thread workerThread; private byte[] readBuffer; private int readBufferPosition; private volatile boolean stopWorker; private ConexaoBluetooth connection = ConexaoBluetooth.getInstance(null, false); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_receiving_data); mmSocket = connection.getConection(); try { mmOutputStream = mmSocket.getOutputStream(); mmInputStream = mmSocket.getInputStream(); mmOutputStream.write("AT".getBytes()); beginListenForData(); mmOutputStream.write("OK".getBytes()); Toast.makeText(ReceivingData.this, "Recebendo dados do Bluetooth", Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); } } void beginListenForData() { final BufferedReader reader = connection.getmBufferedReader(); stopWorker = false; readBufferPosition = 0; readBuffer = new byte[1024]; workerThread = new Thread(new Runnable() { public void run() { while (!Thread.currentThread().isInterrupted() && !stopWorker) { try { String info = reader.readLine(); // recebe os dados da comunicação Toast.makeText(ReceivingData.this, "Mensagem recebida: " + info, Toast.LENGTH_SHORT).show(); mmOutputStream.write("OK".getBytes()); // envia dados. } catch (IOException ex) { stopWorker = true; } } } }); workerThread.start(); } }
Conectando-se ao Bluetooth
Agora que todas as outras classes estão prontas, falta a MainActivity, que irá comunicar as 3 classes e estabelecer a conexão.
Variáveis utilizadas
As variáveis que serão utilizadas para a conexão com o módulo bluetooth serão:
private BluetoothAdapter BA; private final String nomeDispositivo = "beMyEyes"; //Mude beMyEyes para o nome do seu módulo Bluetooth. private final int REQUEST_ENABLE_BT = 1; // Código padrão para o requerimento em tempo de execução. private ConexaoBluetooth conexao; private IntentFilter it = null; private final String[] PermissionsLocation = {Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION}; //Array de permissões relacionadas ao Bluetooth no Android 6.0 ou maior private final int ResquestLocationId = 0; // Código padrão para o requerimento em tempo de execução.
Estabelecer a conexão
Comece declarando o filtro e o receptor da conexão, com o seguinte código:
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // Quando a ação "discover" achar um dispositivo if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); try{ if(device.getName().trim().equals(nomeDispositivo)) { conexao = ConexaoBluetooth.getInstance(device, true); if(conexao.isConnected()) { Toast.makeText(MainActivity.this, "Conectado ao " + device.getName(), Toast.LENGTH_SHORT).show(); changeActivity(); // chama a ReceivingData } } }catch (Exception e) { e.printStackTrace(); } } } }; //função para facilitar o entendimento da troca de activities. private void changeActivity(){ Intent i = new Intent(this,ReceivingData.class); startActivity(i); }
Também declare as funções de apoio à conexão:
public void BtEnable(){ //liga o bluetooth if (!BA.isEnabled()) { Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(turnOn, REQUEST_ENABLE_BT); Toast.makeText(MainActivity.this, "Bluetooth Ligado", Toast.LENGTH_SHORT).show(); } else { lookFor(); } // Essa if em especial, verifica se a versão Android é 6.0 ou maior, pois caso seja, uma permissão para localização, além das relacionadas ao Bluetooth, sao necessárias. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){ requestPermissions(PermissionsLocation,ResquestLocationId); } } } protected void lookFor() { // Procura por dispositivos if(BA.startDiscovery()){} else ; }
Agora basta no onCreate(), fazer as chamadas relacionadas à conexão.
while(true) { // Instancia o filtro declarado logo após o onCreate(). it = new IntentFilter(); it.addAction(BluetoothDevice.ACTION_FOUND); it.addCategory(Intent.CATEGORY_DEFAULT); registerReceiver(mReceiver, it); // Registra um Receiver para o App. break; } BA = BluetoothAdapter.getDefaultAdapter(); BtEnable();
Feito isso, está pronta a Aplicação.
O código final da classe MainActivity ficou assim:
package br.ufop.imobilis.tutorialbluetooth; import android.Manifest; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.Build; import android.speech.tts.TextToSpeech; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Toast; import java.util.Objects; public class MainActivity extends AppCompatActivity { private BluetoothAdapter BA; private final String nomeDispositivo = "beMyEyes"; //Mude beMyEyes para o nome do seu módulo Bluetooth. private final int REQUEST_ENABLE_BT = 1; // Código padrão para o requerimento em tempo de execuxão. private ConexaoBluetooth conexao; private IntentFilter it = null; private final String[] PermissionsLocation = {Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION}; //Array de permissões relacionadas ao Bluetooth no Android 6.0 ou maior private final int ResquestLocationId = 0; // Código padrão para o requerimento em tempo de execução. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); while(true) { it = new IntentFilter(); // Instancia o filtro declarado logo após o onCreate(). it.addAction(BluetoothDevice.ACTION_FOUND); it.addCategory(Intent.CATEGORY_DEFAULT); registerReceiver(mReceiver, it); // Registra um Receiver para o App. break; } BA = BluetoothAdapter.getDefaultAdapter(); BtEnable(); } IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // Quando a ação "discover" achar um dispositivo if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); try{ if(device.getName().trim().equals(nomeDispositivo)) { conexao = ConexaoBluetooth.getInstance(device, true); if(conexao.isConnected()) { Toast.makeText(MainActivity.this, "Conectado ao " + device.getName(), Toast.LENGTH_SHORT).show(); changeActivity(); // chama a ReceivingData } } }catch (Exception e) { e.printStackTrace(); } } } }; private void changeActivity() { Intent i = new Intent(this,ReceivingData.class); startActivity(i); } public void BtEnable(){ //liga o bluetooth if (!BA.isEnabled()) { Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(turnOn, REQUEST_ENABLE_BT); Toast.makeText(MainActivity.this, "Bluetooth Ligado", Toast.LENGTH_SHORT).show(); } else { lookFor(); } // Essa if em especial, verifica se a versão Android é 6.0 ou maior, pois caso seja, uma permissão para localização, além das relacionadas ao Bluetooth, sao necessárias. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){ requestPermissions(PermissionsLocation,ResquestLocationId); } } } protected void lookFor() { // Procura por dispositivos if(BA.startDiscovery()){} else ; } }
Fotos do projeto:
Duvidas? Entre em contato comigo no E-mail: moc.liamtohnull@32noimsolrac





Parabéns Mion, você é o cara!
Mion, parabens pela iniciativa, mas estou tendo problemas em 3 partes do código.
1° – setContentView(R.layout.activity_receiving_data2) => activity_receiving_data2 não está encontrando, ta certo esse nome? Não seria somente activity_receiving_data;
2° – while (!Thread.currentThread().isInterrupted() && !stopWorker) { => A palavra && fica com vermelho embaixo, pq?
Esses 2 problemas estão na classe ReceivingData nas linhas 28 e 54 respectivamente
3° – Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { => Fica o vermelho debaixo do >, pq?
Poderia me ajudar?
Boa noite Matheus,
1- Sim, desculpe pelo erro, esse numero 2 depois do “data” não deveria estar aí, deve ter sido um erro de digitação que vou corrigir agora mesmo.
2 e 3- Cara, qual erro que o AndroidStudio sugere nesses 2? Abri o código aqui e a minha IDE não está acusando esses erros
obrigado pelo comentário, vou corrigir os erros assim que possível!