Tutorial Android – Comunicação Bluetooth

On 13 de julho de 2016 by Carlos Mion

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:

Novo projeto criado.

Novo projeto criado.

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.

Criando a classe de suporte ao Bluetooth

Criando a classe de suporte ao Bluetooth

Dê o nome que desejar, para efeito do tutorial, ela se chamará ConexaoBluetooth.

Classe de suporte criada

Classe de suporte criada

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.

Criando uma nova Activity

Criando uma nova Activity

Agora o projeto estará assim:

Projeto após a criação de todas as classes que serão necessárias

Projeto após a criação de todas as classes que serão necessárias

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:

Montagem do projeto.

Montagem do projeto.

Mensagens recebidas

Mensagens recebidas

Duvidas? Entre em contato comigo no E-mail: moc.liamtohnull@32noimsolrac

Summary
Review Date
Reviewed Item
Comunicação Bluetooth e Android
Author Rating
51star1star1star1star1star

4 Responses to “Tutorial Android – Comunicação Bluetooth”

  • 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!

Trackbacks & Pings

Deixe um comentário

O seu endereço de e-mail não será publicado.