Por que eu devo ler este artigo:O processo de comunicação utilizando a tecnologia NFC que permite a troca de informações de forma segura sem fios entre dispositivos compatíveis a curta distância. Inicialmente serão apresentados os conceitos teóricos básicos sobre a tecnologia, seguido do desenvolvimento de um estudo de caso, e por fim, a demonstração do aplicativo desenvolvido. Saber utilizar esta tecnologia é importante por ela ser muito promissora. É bem provável que nos próximos anos ela faça parte ativamente do dia a dia podendo substituir documentos pessoais e cartões de crédito, entre outros.

A Near Field Communication (Comunicação por Campo de Proximidade), mais popularmente conhecida pela sigla NFC, é uma tecnologia para troca de informações de forma segura sem fios entre dispositivos compatíveis a curta distância. É necessária apenas a aproximação física para estabelecer automaticamente a comunicação, que ao contrário da tecnologia Bluetooth por exemplo, não necessita da interação com o usuário para encontrar um serviço ou estabelecer uma conexão.

O objetivo deste protocolo não é trocar uma grande quantidade de informações, embora isto também seja possível, mas sim, trocar informações pequenas e rápidas, de forma segura, sem necessidade de configurações adicionais. Simplesmente aproximar o dispositivo e trocar os dados.

A tecnologia surgiu do padrão RFID (Radio Frequency Identification), mas por questões de segurança limitou o campo de atuação em até 10 centímetros tornando-se assim mais segura.

Este protocolo de comunicação começou a ser criado em 2002 através de uma parceria entre Sony e Philips, os quais estabeleceram um padrão definido pelo NFC Forum. Em 2004 um consórcio global foi criado composto de companhias de bancos, cartões de crédito, hardware e software. Todas estas empresas apostaram na tecnologia e estão dando suporte para ela ser utilizada a nível mundial, na maior quantidade de dispositivos possível.

Atualmente, o Japão e os Estados Unidos são os países que mais apostaram nesta tecnologia, sendo ela utilizada no dia a dia para comprar passagens de metro, assim como refrigerantes em máquinas, e em muitos outros locais. Nos Estados Unidos, por exemplo, o acesso a prédios da Universidade do Arizona é controlado por este protocolo. A fábrica de automóveis BMW apresentou um projeto de chave do veículo com NFC, sem a necessidade de inseri-la na fechadura do automóvel, mas sim aproximá-la do veículo.

No Brasil já existe o caso de sucesso PagSeguro (UOL, que teve o projeto desenvolvido em parceria com a Nokia e possibilita transações financeiras seguras utilizando smartphones.

As possibilidades de negócio com este protocolo de comunicação são muitas, desde o controle de acesso de pessoas, acionamento de recursos, transações financeiras e muito mais. Qualquer aplicação pode trocar dados via NFC, como a aplicação de contatos, o browser, o YouTube, transferindo contatos, páginas web e vídeos para outros dispositivos.

A partir de uma aplicação Android que faça uso da comunicação NFC, é possível fazer a leitura dos dados existentes em tags NFC (Figura 1), ou ainda, fazer um device trocar dados com outro. Também podemos fazer com que uma aplicação Android seja iniciada automaticamente assim que um dado NFC seja recuperado.

Exemplo de uma tag NFC
Figura 1. Exemplo de uma tag NFC

Para exemplificarmos sua aplicação será desenvolvido ao longo deste artigo uma aplicação desenvolvida na plataforma Android que permite dois dispositivos Android trocarem informações de texto. Para o exemplo, a mensagem trafegada estará no formato NDEF, que significa NFC Data Exchange Format. Trata-se de uma forma genérica de trocar dados NFC e é um dos formatos mais simples para iniciar um primeiro aplicativo com esta tecnologia.

Funcionamento do NFC na plataforma Android

Um device Android está sempre procurando por dispositivos com NFC para fazer a leitura de seus dados, a não ser que esta comunicação esteja desativada no menu do device. Quando um dispositivo com NFC é encontrado, automaticamente o comportamento do device é iniciar uma Activity para tratá-la, sempre que possível, sem pedir nada ao usuário. Como a comunicação com o NFC acontece a curta distância, o fato do usuário ter que movimentar o device para selecionar uma aplicação para tratar a mensagem já prejudica o andamento do processo. Desta forma, o ideal é evitar que telas sejam apresentadas, como a apresentada na Figura 2.

Tela de seleção de aplicativo para tratamento de tag NFC
Figura 2. Tela de seleção de aplicativo para tratamento de tag NFC

Para garantir que a comunicação acontece sem a intervenção do usuário, a plataforma Android provê um serviço chamado de dispatcher system, o qual analisa o dispositivo NFC, recebe seus dados, e tenta automaticamente localizar uma aplicação para tratá-la. Isto pode ser feito de três maneiras:

  • Analisando a mensagem e descobrindo o MIME type ou a URI (ambas informações representam aplicativos que podem processar o dado recebido) a qual esta pode ser associada;
  • Recuperando o MIME type ou a URI, este já enviado junto com a mensagem;
  • Iniciando uma Activity específica após receber a mensagem.

Antes de iniciarmos a codificação de um aplicativo Android para tratar a comunicação com NFC, é necessário conhecer os diferentes tipos de tags NFC, como o dispatcher system analisa estas tags e como o dispatcher system trabalha quando identifica uma mensagem NDEF.

Tags NFC podem ser lidas dos mais diversos tipos de dispositivos, que as podem enviar das mais diferentes maneiras. Para facilitar a comunicação, um tipo padrão de envio de mensagens foi criado, o NDEF, que no Android é representado pela classe android.nfc.NdefMessage. Esta classe é composta por um ou mais registros, estes representados pela classe android.nfc.NdefRecord.

Embora a comunicação NFC suporte outros tipos de mensagens, disponíveis no pacote android.nfc.tech (pode inclusive criar seus protocolos de comunicação), é altamente recomendável utilizar o NDEF garantindo com isso uma facilidade de leitura e gravação. Além disso, como este é o tipo mais utilizado, a possibilidade de outros dispositivos também gerarem ou lerem esta informação é grande.

Quando um device Android lê uma mensagem gerada por uma tag no formato NDEF, o primeiro passo é identificar na mensagem o MimeType ou a URI, o qual informará ao device como esta mensagem deverá ser tratada. Muitas vezes, um dado que vem de uma tag NFC possui uma URI (por exemplo, abrir o aplicativo do YouTube), assim como uma informação (o vídeo que deve ser executado), desta forma, de forma transparente para o usuário, um aplicativo é aberto e um dado compatível com este aplicativo é apresentado.

Para fazer isso, o aplicativo Android primeiro lê a mensagem que chegou (objeto da classe NdefMessage) e, em seguida, processa o primeiro registro desta (objeto no formato NdefRecord). Este, em uma mensagem formatada da maneira correta, trará três informações:

  1. TNF (Type Name Format, ou nome do tipo do formato): Este campo indica como a mensagem NDEF deve ser processada. Pode informar que estará sendo enviada uma URI como referência, um MimeType, ou alguma outra forma. Os valores válidos são apresentados na Figura 3.
  2. Formatos válidos de TNF
    Figura 3. Formatos válidos de TNF
  3. Variable length type (Tipo de registro): Caso o primeiro campo seja definido com TNF_WELL_KNOWN, utiliza-se este campo para complementar a informação enviada. Os formatos válidos são apresentados na Figura 4.
  4. Formatos válidos para o campo Variable lenght type
    Figura 4. Formatos válidos para o campo Variable lenght type
  5. Variable length payload (Dados enviados): Esta é a mensagem que será trafegada. Como uma mensagem NDEF pode possuir muitos registros, não se deve assumir que toda a mensagem que será trafegada está logo no primeiro registro.

O dispatcher system utiliza a mensagem NDEF para identificar a mensagem recebida, bem como tentar processá-la da melhor maneira possível utilizando o caminho da aplicação que deve ser executada, o complemento deste caminho e os dados propriamente ditos.

Se a mensagem recebida é “entendível” pelo dispatcher system, este encapsula todos os dados e informa que uma Intent do tipo ACTION_NDEF_DISCOVERED deve ser executada com os dados recebidos. Em outras palavras, significa que a mensagem NDEF veio no formato que pode ser processada de forma automática pelo device Android.

Entretanto, em algumas situações, o dispatcher system não consegue “entender” o que deve ser realizado com a mensagem recebida. Nesta situação, os dados que informam sobre o que deve ser feito podem estar encapsulados dentro de um objeto da classe android.nfc.Tag, neste caso, é indicada uma Intent do tipo ACTION_TECH_DISCOVERED. Tanto o início da Intent ACTION_NDEF_DICOVERED quanto da ACTION_TECH_DISCOVERED são capturados por um IntentFilter.

Caso contrário, se não for identificada uma situação onde uma Intent do tipo ACTON_NDEF_DISCOVERED e ACTION_TECH_DISCOVERED pode ser iniciada, a última alternativa é processar a mensagem iniciando uma Intent do tipo ACTION_TAG_DISCOVERED.

A Figura 5 apresenta o funcionando da seleção de qual Intent será utilizado para tratar uma mensagem NFC.

Seleção da Intent para processar uma mensagem NFC
Figura 5. Seleção da Intent para processar uma mensagem NFC

Desta forma, ao receber uma mensagem NFC, o dispatcher system verifica o primeiro registro da mensagem. Se estiver tudo formatado, ele tentará iniciar uma Intent do tipo NFED_DISCOVERED, caso contrário, será identificado se existe um filtro para iniciar esta Intent a partir de um TECH_DISCOVERY, mas caso isso não ocorra, o TAG_DISCOVERED é verificado. Não encontrando nenhum IntentFilter para ele, nada é realizado.

Estudo de caso

Para o desenvolvimento deste estudo de caso foi utilizada a IDE de desenvolvimento Eclipse já configurada com o plugin ADT o qual permite o desenvolvimento de aplicações Android. A ferramenta Android SDK também foi instalada e configurada no ambiente de desenvolvimento. A versão do Android utilizada para o exemplo deve ser superior a API 14. Vale ressaltar que a tecnologia NFC está disponível na plataforma Android a partir da API 9, mesmo que suportando apenas ACTION_TAG_DISCOVERED. Na API 10 esta comunicação foi aprimorada e somente na API 14 o processo de comunicação foi facilitado com o uso do Android Beam.

Para iniciar o desenvolvimento, acessamos o menu FileNewAndroid Application Project. O projeto será nomeado como UsandoNFC e será armazenado no pacote br.com.estudo.usandonfc, conforme apresentado na Figura 6.

Dados referentes a criação do projeto UsandoNFC
Figura 6. Dados referentes a criação do projeto UsandoNFC

Nas demais telas foi selecionado o tipo da Activity utilizada na aplicação – Blank Activity, assim como o nome da tela – activity_principal.xml – e da classe Java – PrincipalActivity.java.

O aplicativo será formado pela tela principal (criada no passo anterior) e duas outras telas. A primeira utilizada pelo usuário do device para enviar dados via NFC, e a segunda usada para permitir que as mensagens via NFC possam ser recuperadas.

Este aplicativo deve ser executado simultaneamente em dois devices Android com suporte a NFC para que seu funcionamento possa ser observado: o primeiro apresentará a tela para enviar os dados (BeamData), e o segundo a tela que o habilita a receber dados (DispatcherTag). Finalizado o projeto, o mesmo possui a estrutura apresentada na Figura 7.

Estrutura de arquivos do projeto UsandoNFC
Figura 7. Estrutura de arquivos do projeto UsandoNFC

Após criado o projeto, assim como as Activities que processarão as três telas do aplicativo (tela principal de seleção, tela para envio de dados e tela para recebimento de dados), o passo seguinte é modificar o arquivo Android_Manifest.xml informando que a aplicação faz uso da comunicação NFC e que a instalação deste aplicativo pode ser realizada apenas nos devices que possuam esta tecnologia.

Abrindo o arquivo Android_Manifest.xml, as linhas 11 e 13 devem ser inseridas conforme Listagem 1.


 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="//schemas.android.com/apk/res/android"
     package="br.com.estudo.usandonfc"
     android:versionCode="1"
     android:versionName="1.0" >
 
     <uses-sdk
         android:minSdkVersion="17"
         android:targetSdkVersion="17" />
     
     <uses-permission android:name="android.permission.NFC"/>
 
     <uses-feature android:name="android.hardware.nfc" android:required="true" />
     
     <application
         android:allowBackup="true"
         android:icon="@drawable/ic_launcher"
         android:label="@string/app_name"
         android:theme="@style/AppTheme" >
         <activity
             android:name="br.com.estudo.usandonfc.PrincipalActivity"
             android:label="@string/app_name" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
         <activity
             android:name="br.com.estudo.usandonfc.BeamDataActivity"
             android:label="@string/title_activity_beam_data" >
         </activity>
         <activity
             android:name="br.com.estudo.usandonfc.DispatcherTagActivity"
             android:label="@string/title_activity_dispatcher_tag" >
         </activity>
     </application>
 
 </manifest>
Listagem 1. Android_Manifest.xml – Arquivo de configuração do projeto

A linha 11 do arquivo informará ao usuário do device, no momento da instalação do aplicativo, que o mesmo fará uso da comunicação NFC. Já a linha 13 limita a instalação deste aplicativo há apenas aparelhos que possuam o recurso NFC.

Se, por exemplo, a falta da comunicação NFC no device Android não comprometer o uso do aplicativo, a linha 13 do arquivo AndroidManifest.xml pode ser eliminada. Outra opção também é adicionar no método onCreate() da tela principal (PrincipalActivity.java) a condicional apresentada na Listagem 2.


  private android.nfc.NfcAdapter mNfcAdapter;
    
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_principal);
  
    mNfcAdapter = android.nfc.NfcAdapter.getDefaultAdapter(this);
  
    if (mNfcAdapter != null) {
          Toast.makeText( this, "NFC presente no device...", Toast.LENGTH_LONG ).show();
    } else {
          Toast.makeText( this, "NFC ausente no device...", Toast.LENGTH_LONG ).show();
    }
  
  }
Listagem 2. PrincipalActivity.java – Tela principal do aplicativo

No código apresentado, um objeto que representa o adaptador NFC do device é recuperado (linha 08), sendo este testado na linha 10. Se tiver valor diferente de nulo, indicando que o device possui suporte a NFC, é apresentada mensagem informativa (linha 11). Caso contrário, uma mensagem de erro é apresentada na linha 13.

O passo seguinte é a codificação da interface gráfica da tela principal activity_principal.xml, como mostra a ver Listagem 3.


  <?xml version="1.0" encoding="utf-8"?>
   
  <LinearLayout xmlns:android="//schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical" >
  
      <Button
          android:id="@+id/btDispatcher"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="Dispatcher Tag" />
  
      <Button
          android:id="@+id/btBeamData"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="Beam Data" />
  
  </LinearLayout>
Listagem 3. activity_principal.xml – Tela principal do aplicativo

A interface gráfica do aplicativo é formado por dois botões. O primeiro (linhas 08 a 12) responsável por habilitar a leitura de dados via NFC, e o segundo (linhas 14 a 18) pelo envio dos dados.

Para tratar a interface gráfica principal, a PrincipalActivity.java deve ser codificada conforme Listagem 4, que realiza inicialmente o import das classes utilizadas no programa (linhas 03 a 09). Em seguida declara a classe na linha 11 e realiza a declaração dos componentes visuais de tela (linha 13), assim como do objeto que representa o adaptador NFC na linha 16.

No método onCreate() são realizadas as operações padrão de Activity (linhas 20 e 21) e são recuperados os objetos visuais da tela (linhas 23 e 24), declarando na sequência o tratamento de eventos dos botões btDispatcher e btBeamData (linhas 26 a 42).

Na linha 44 o objeto que representa o adaptador NFC é instanciado, sendo este testado na linha 46. Mesmo sendo adicionada a restrição na linha 13 do arquivo AndroidManifest.xml (Listagem 1), o teste da linha 46 foi adicionado ao programa. Se o device não oferecer suporte ao NFC, os botões ficarão desabilitados (linhas 50 e 51).


 package br.com.estudo.usandonfc;
 
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
 import android.widget.Button;
 import android.widget.Toast;
 import android.nfc.NfcAdapter;
   
 public class PrincipalActivity extends Activity {
 
   private Button btDispatcher;
   private Button btBeamData;
   
   private NfcAdapter mNfcAdapter;
   
   @Override
   protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_principal);
 
         btDispatcher = (Button) findViewById( R.id.btDispatcher );
         btBeamData = (Button) findViewById( R.id.btBeamData );
         
         btDispatcher.setOnClickListener( new View.OnClickListener() {
                
                @Override
                public void onClick(View arg0) {
                       btDispatcherOnClick();
                       
                }
         } );
         
         btBeamData.setOnClickListener( new View.OnClickListener() {
                
                @Override
                public void onClick(View v) {
                       btBeamDataOnClick();
                       
                }
         } );
         
         mNfcAdapter = NfcAdapter.getDefaultAdapter(this);

         if (mNfcAdapter != null) {
                Toast.makeText( this, "NFC presente no device...", Toast.LENGTH_LONG 48.).show();
         } else {
                btDispatcher.setEnabled( false );0
                btBeamData.setEnabled( false );
                Toast.makeText( this, "NFC ausente no device...", Toast.LENGTH_LONG ).show();
         }
         
   }

   protected void btDispatcherOnClick() {
         Intent intent = new Intent( this, DispatcherTagActivity.class );
         startActivity( intent );
   }

   protected void btBeamDataOnClick() {
         Intent intent = new Intent( this, BeamDataActivity.class );
         startActivity( intent );.
   }      

 }
Listagem 4. PrincipalActivity.java – Código Java referente à tela principal do aplicativo

Já o tratamento do botão btDispatcher é realizado no método da linha 57. Este instancia um Intent informando que a tela que será apresentada é a DispatcherTagActivity (linha 58) que será chamada logo na sequência (linha 59). O mesmo procedimento é feito com o botão btBeamData (linhas 62 a 65).

O próximo passo será tratar a tela responsável pelo envio da informação para o outro dispositivo NFC. Para isto, precisamos codificar a tela activity_beam_data.xml, conforme a Listagem 5.


  <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="//schemas.android.com/apk/res/android"
     xmlns:tools="//schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
     tools:context="br.com.estudo.usandonfc.BeamDataActivity" >
 
     <TextView android:id="@+id/tvMensagem"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:gravity="center_vertical"
   />
     
 </RelativeLayout>
Listagem 5. activity_beam_data.xml – Interface referente à tela de envio de mensagem

A interface apresentada é bem simples. Ela é basicamente formatada por um gerenciador de layout RelativeLayout (linha 02), no qual um componente visual TextView (linha 12) é apresentado ao centro para informar a situação da comunicação.

Já a lógica de negócio desta tela é definida na Listagem 6. O código da classe BeanDataActivity.java inicia importando as classes utilizadas pela classe (linhas 04 a 13), assim como declarando os objetos utilizados (linhas 17 a 19). O método onCreate<() da linha 22 faz o procedimento tradicional de inicialização da Activity (linhas 23 a 26), recuperando na sequência a instância do adaptador NFC (linha 28), testando-o na linha 30, para então apresentar no componente tvMensagem um texto informativo (linhas 31 ou 33).

Na linha 35 é iniciado o processo para envio de mensagens NFC, além disso, esta linha define um novo objeto NdefMessage (que é um binário utilizado para encapsular os dados a serem transferidos).Neste objeto podem ser inseridos um ou mais registros. Para o exemplo, utilizamos dois registros criados pelo método criarRegistroTexto() codificado a partir da linha 42.

Como se trata de um formato multiplataforma, alguns cuidados devem ser tomados, por exemplo, informar o local da mensagem, assim como o formato do texto. Em nossa aplicação utilizamos o idioma inglês e a codificação do texto em UTF-8.


   
  package br.com.estudo.usandonfc;
  
  import java.nio.charset.Charset;
  import java.util.Locale;
  
  import android.app.Activity;
  import android.nfc.NdefMessage;
  import android.nfc.NdefRecord;
  import android.nfc.NfcAdapter;
  import android.os.Bundle;
  import android.widget.TextView;
  import android.widget.Toast;
  
  public class BeamDataActivity extends Activity {
  
   private TextView tvMensagem;
   private NfcAdapter mNfcAdapter;
   private NdefMessage mNdefMessage;
   
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_beam_data);
  
       tvMensagem = (TextView)findViewById(R.id.tvMensagem);
    
       mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
  
       if (mNfcAdapter != null) {
           tvMensagem.setText("Toque em Beam Data no outro dispositivo");
       } else {
           tvMensagem.setText("NFC ausente no device...");
       }
  
       mNdefMessage = new NdefMessage(
         new NdefRecord[] {
           criarRegistroTexto("Um texto qualquer enviado para o outro device!",
           Locale.ENGLISH, true),
           criarRegistroTexto("Segundo texto qualquer enviado ao outro device!",
           Locale.ENGLISH, true) }); 
   }
  
   public static NdefRecord criarRegistroTexto(String text, Locale locale, 
     boolean encodeInUtf8) {
       byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
  
       Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") :
       Charset.forName("UTF-16");
       byte[] textBytes = text.getBytes(utfEncoding);
  
       int utfBit = encodeInUtf8 ? 0 : (1 << 7);
       char status = (char)(utfBit + langBytes.length);
  
       byte[] data = new byte[1 + langBytes.length + textBytes.length]; 
       data[0] = (byte)status;
       System.arraycopy(langBytes, 0, data, 1, langBytes.length);
       System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
  
       return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, 
   new byte[0], data);
   }
  
   @Override
   public void onResume() {
     super.onResume();
  
       if (mNfcAdapter != null)
     mNfcAdapter.enableForegroundNdefPush(this, mNdefMessage);
   }
  
   @Override
   public void onPause() {
     super.onPause();
  
     if (mNfcAdapter != null)
          mNfcAdapter.disableForegroundNdefPush(this);
   }  
  
  }
Listagem 6. BeamDataActivity.java – Classe Java para envio de dados NFC

Já o método criarRegistroTexto() é responsável por recuperar a mensagem que se deseja transmitir (text) e armazená-la em um array de bytes para a transmissão, considerando neste armazenamento a Locale e o formato da mensagem (UTF-8), como vemos da linha 43 até a 54. Após isso, o array de bytes data possui os dados para serem transmitidos. Para isso, basta criar um NdefRecord (linha 56), informar que a mensagem está em um formato conhecido (TNF_WELL_KNOWN) e que o conteúdo da mensagem segue com o objeto (RTD_TET). O conteúdo da mensagem é o último parâmetro (array de bytes data).

Por fim, os métodos onResume() e onPause() são responsáveis por garantir a comunicação NFC mesmo que ocorra algum comportamento alheio no dispositivo (como a chegada de uma ligação).

Para finalizar o aplicativo temos a Activity responsável por permitir que a aplicação receba uma mensagem NFC. Ela possui uma interface gráfica simples e é implementada conforme a Listagem 7.


 <RelativeLayout xmlns:android="//schemas.android.com/apk/res/android"
     xmlns:tools="//schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
     tools:context=".DispatcherTagActivity" >
 
     <TextView android:id="@+id/tvMensagem"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center_vertical"
  />
     
 </RelativeLayout>
Listagem 7. activity_dispatcher_tag.xml – Interface gráfica da tela para recebimento de dados

A interface gráfica possui o mesmo conteúdo da interface apresentada na Listagem 5, com o mesmo campo informativo na tela (tvMensagem – linha 11).

As Listagens 8 e 9 apresentam o código Java responsável por tratar o recebimento de dados via NFC. O código apresentado tem a mesma estrutura básica da Activity da Listagem 6, diferenciando apenas no código presente ao final do método onCreate(). Na linha 43 é criado um PendingItent para garantir que uma ação seja iniciada com o recebimento da mensagem NFC. Também definimos um IntentFilter (linha 46) informando que esta ação só será iniciada ao recebimento de mensagens do tipo NDEF_DISCOVERED (este tipo foi definido na linha 56 da Listagem 6).

Assim, ao chegar uma mensagem, o método onNewIntent() é chamado (linha 60). Este é responsável por verificar o tipo de ação (linha 61), assim como a tag da mensagem (linha 62). Ambas as informações são concatenadas em um objeto String (linha 64).

Após isso, as mensagens do tipo NDEF_MESSAGES são recuperadas (linha 66), verificadas (linha 69) e percorridas (linha 71). Serão recuperados cada registro da mensagem (linha 72), assim como percorridas as partes destes registros (linha 73). Lembrando que uma mensagem pode ser formada por um ou mais registros, e um registro pode ser formado por uma ou mais informações.

Desta forma, as mensagens conhecidas (TNF_WELL_KNOWN) e com conteúdo (RTD_TEXT) serão recuperadas (linha 78), codificadas (linhas 79) e concatenas na mensagem que será apresentada para o usuário (linha 83) sendo, por fim, disponibilizada no componente TextView (linha 96).


  package br.com.estudo.usandonfc;
  
  import java.util.Arrays;
  
  import android.app.Activity;
  import android.app.PendingIntent;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.nfc.NdefMessage;
  import android.nfc.NdefRecord;
  import android.nfc.NfcAdapter;
  import android.nfc.Tag;
  import android.nfc.tech.NfcF;
  import android.os.Bundle;
  import android.os.Parcelable;
  import android.util.Log;
  import android.widget.TextView;
  
  public class DispatcherTagActivity extends Activity {
  
   private TextView tvMensagem;
  
   private NfcAdapter mNfcAdapter;
   private PendingIntent mPendingIntent;
   private IntentFilter[] mIntentFilters;
   private String[][] mNFCTechLists;
  
   @Override
   public void onCreate(Bundle savedState) {
     super.onCreate(savedState);
  
     setContentView(R.layout.activity_dispatcher_tag);
     tvMensagem = (TextView) findViewById(R.id.tvMensagem);
  
     mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
  
     if (mNfcAdapter != null) {
         tvMensagem.setText("Toque em Beam Data no outro dispositivo");
     } else {
         tvMensagem.setText("NFC ausente no device...");
     }
  
     mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
             getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
  
     IntentFilter ndefIntent = new IntentFilter(
             NfcAdapter.ACTION_NDEF_DISCOVERED);
  
     try {
         ndefIntent.addDataType("*/*");
         mIntentFilters = new IntentFilter[] { ndefIntent };
     } catch (Exception e) {
         Log.e("TagDispatch", e.toString());
     }
  
     mNFCTechLists = new String[][] { new String[] { NfcF.class.getName() } };
   }
 } 
Listagem 8. DispatcherTagActivity.java – Código Java da tela para recebimento de dados – Parte 1

  @Override
  public void onNewIntent(Intent intent) {
    String action = intent.getAction();
    Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
 
    String s = action + "\n\n" + tag.toString();
 
    Parcelable[] data = intent
            .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
 
    if (data != null) {
      try {
        for (int i = 0; i < data.length; i++) {
          NdefRecord[] recs = ((NdefMessage) data[i]).getRecords();
          for (int j = 0; j < recs.length; j++) {
            if (recs[j].getTnf() == NdefRecord.TNF_WELL_KNOWN
              && Arrays.equals(recs[j].getType(),
                 NdefRecord.RTD_TEXT)) {
 
                  byte[] payload = recs[j].getPayload();
                  String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8"
                         : "UTF-16";
                  int langCodeLen = payload[0] & 0077;
 
                  s += ("\n\nMensagemNFC  - "
                    + j
                    + "-:\n\""
                    + new String(payload, langCodeLen + 1,
                      payload.length - langCodeLen - 1,
                      extEncoding) + "\"");
                }
          }
       }
     } catch (Exception e) {
            Log.e("TagDispatch", e.toString());
    }
   }
    tvMensagem.setText(s);
  }
 
  @Override
    public void onResume() {
        super.onResume();
  
        if (mNfcAdapter != null)
            mNfcAdapter.enableForegroundDispatch(this, mPendingIntent,
                    mIntentFilters, mNFCTechLists);
    }
  
    @Override
    public void onPause() {
        super.onPause();
  
        if (mNfcAdapter != null)
            mNfcAdapter.disableForegroundDispatch(this);
    }
  }
Listagem 9. DispatcherTagActivity.java – Código Java da tela para recebimento de dados – Parte 2

Testando o aplicativo

Ao iniciar o aplicativo em ambos os dispositivos, pressione a opção Despachar Tag’s no dispositivo que irá receber a mensagem e em Beam Data no dispositivo que enviará os dados. Dessa forma, o dispositivo da esquerda estará lendo a tag NFC e o dispositivo da direita estará enviando, conforme representa a Figura 8.

Dispositivo da esquerda responsável por receber os dados. Dispositivo da direita por enviar dados
Figura 8. Dispositivo da esquerda responsável por receber os dados. Dispositivo da direita por enviar dados

Em seguida, os dois dispositivos devem ser conectados através da aproximação de ambos. A distância necessária entre os dispositivos pode variar, dependendo da sensibilidade do adaptador NFC. Para o exemplo, os dois dispositivos ficaram encostados, como pode ser observado na Figura 9.

Aproximando os dispositivos para a troca de informações
Figura 9. Aproximando os dispositivos para a troca de informações

Ao estabelecer a conexão, a tela dos dispositivos a mesma apresentada na Figura 10.

Dispositivos conectados
Figura 10. Dispositivos conectados

Posteriormente, a troca de informação é feita pressionando a tela do dispositivo da direita (ou o que está em Beam Data) e será enviado o texto já definido no aplicativo para o dispositivo da esquerda (ou o que estiver em Despachar Tag’s). O resultado final da comunicação é apresentado na Figura 11.

Troca de informações entre os dispositivos
Figura 11. Troca de informações entre os dispositivos

Infelizmente não é possível testar a comunicação no emulador do Android (AVD). Por este motivo, para os testes do estudo de caso é necessário ter dois celulares Android com a tecnologia NFC.

Como pode ser observado, a utilização da tecnologia NFC em Android não é algo complexo. A tecnologia é promissora e estima-se que nos próximos anos faça parte ativamente do dia a dia das pessoas, pois pode substituir documentos pessoais, cartões de crédito, códigos de barras, auxiliar o marketing digital e propagar informações. Sua adoção proporciona conexões fáceis, transações rápidas e compartilhamento simples de dados.

Confira também