Nesta seção você irá aprender mais sobre os detalhes de cada funcionalidade do SDK Android para mPOS. Veja como fazer o download e configurar as bibliotecas básicas que seguem o protocolo ABECS. Além disso, veja o fluxo de criação de uma transação. Vamos lá!

Download do SDK

O SDK Android pode ser encontrado em duas distribuições, dependendo do sistema de build sendo usado:

Configurando o ambiente

Permissões Android

Adicione as seguintes linhas ao AndroidManifest.xml do seu projeto, no interior da tag <manifest>:

	<uses-permission android:name="android.permission.BLUETOOTH" />
	<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
	<uses-permission android:name="android.permission.INTERNET" />

Essas linhas garantirão as permissões necessárias para que o aplicativo e o SDK possam realizar operações com Bluetooth e com conexões à Internet.

Instruções para build com Ant:

  1. Após fazer o download em Ant, você deve encontrar os seguintes arquivos:

    • mpos-android-native.jar
    • mpos-android.jar
  2. Adicione os JARs incluídos na distribuição ao seu projeto.

Instruções para build com Gradle:

  1. Dentro do diretório de sua application Android (geralmente '/app'), você deve encontrar os seguintes arquivos:

    - AndroidManifest.xml
    - build.gradle
    

    E após fazer o download em Gradle, os seguintes arquivos estarão disponíveis:

    - mpos-android-native.jar
    - mpos-android.aar
    
  2. Adicione as seguintes linhas ao build.gradle:

	repositories {
		flatDir {
			dirs 'libs'
		}
	}

	dependencies {
		compile fileTree(dir: 'libs', include: ['*.jar'])
		compile (name:'mpos-android', ext:'aar') {
			transitive = true
		}
	}

Essas linhas incluirão os componentes nativos e os componentes Java do SDK para Android no seu projeto.

  1. Adicione os arquivos:
    • mpos-android-native.jar
    • mpos-android.aar

ao diretório libs abaixo do diretório de sua application Android.

Fluxo pré-transação

O código abaixo demonstra um fluxo completo que pode ser usado por sua aplicação,
para capturar os dados de cartão, gerar o card_hash e usá-lo para criar uma transação com
a API Pagar.Me a partir de um servidor externo. Vamos lá:

package com.example.pagarme.mpospocs;

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.os.Bundle;

import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import me.pagar.mposandroid.MposPaymentResult;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;

import me.pagar.mposandroid.Mpos;
import me.pagar.mposandroid.MposListener;
import me.pagar.mposandroid.EmvApplication;
import me.pagar.mposandroid.PaymentMethod;


public class MainActivity extends AppCompatActivity {

    private ListView listView;
    private ArrayList<String> mDeviceList = new ArrayList<String>();
    private ArrayList<BluetoothDevice> abecsList = new ArrayList<BluetoothDevice>();
    private BluetoothAdapter mBluetoothAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView) findViewById(R.id.listView);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long arg3) {
                view.setSelected(true);
                BluetoothDevice device = abecsList.get(position);
                Log.d("Abecs", "SELECTED DEVICE " + device.getName());

                try {
                    final Mpos mpos = new Mpos(abecsList.get(position), "SUA ENCRYPTION KEY", getApplicationContext());

                    mpos.addListener(new MposListener() {
                        public void bluetoothConnected() {
                            Log.d("Abecs", "Bluetooth connected.");
                            mpos.initialize();
                        }

                        public void bluetoothDisconnected() {
                            Log.d("Abecs", "Bluetooth disconnected.");
                        }

                        public void bluetoothErrored(int error) {
                            Log.d("Abecs", "Received bluetooth error");
                        }

                        public void receiveInitialization() {
                            Log.d("Abecs", "receive initialization!");
                            try {
                                mpos.downloadEMVTablesToDevice(true);
                            } catch (Exception e) {
                                Log.d("Abecs", "Got error in initialization and table update " + e.getMessage());
                            }
                        }

                        public void receiveNotification(String notification) {
                            Log.d("Abecs", "Got Notification " + notification);
                        }

                        public void receiveTableUpdated(boolean loaded) {
                            Log.d("Abecs", "received table updated loaded = " + loaded);
                            EmvApplication visaCredit = new EmvApplication(PaymentMethod.CreditCard, "visa");
                            ArrayList<EmvApplication> l = new ArrayList<EmvApplication>();
                            l.add(visaCredit);
                            EmvApplication masterCredit = new EmvApplication(PaymentMethod.CreditCard, "master");

                            l.add(masterCredit);

                            mpos.payAmount(5000, l, PaymentMethod.CreditCard);
                        }

                        public void receiveFinishTransaction() {
                            Log.d("Abecs", "Finished transaction");
                            mpos.close("TRANSACAO APROVADA");
                        }

                        public void receiveClose() {
                            Log.d("Abecs", "Receive close");
                            mpos.closeConnection();
                        }

                        public void receiveCardHash(String cardHash, MposPaymentResult result) {
                            Log.d("Abecs", "Card Hash is " + cardHash);
                            Log.d("Abecs", "Card Brand is " + result.cardBrand);
                            Log.d("Abecs", "FD = " + result.cardFirstDigits + " LD = " + result.cardLastDigits);
                            Log.d("Abecs", "ONL = " + result.isOnline);

                          /* Nesse momento você deve enviar o card_hash para 
                             seu servidor, criar a transação, e devolver um 
                             response para o app com os seguintes campos:
                             
                             * acquirer_response_code
                             * card_emv_response
                             * card_pin_mode
                             
                             Que serão usados no mpos.finishTransaction()
                          */
                          
                          mpos.finishTransaction(true, Integer.parseInt((String) t.get("acquirer_response_code")), (String) t.get("card_emv_response"));

                        }

                        public void receiveError(int error) {
                            Log.d("ABECS", "Received error " + error);
                        }

                        public void receiveOperationCancelled() {
                            Log.d("ABECS", "Cancel");
                        }
                    });

                    Log.d("Abecs", "Telling to initialize");
                    mpos.openConnection(false);
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

    }
}

Atualizando as tabelas EMV

Para as diferentes aplicações de cartão de crédito (diferentes bandeiras, crédito/débito) existem um conjunto de especificações de como o PinPad deve se comportar, assim como certificados que permitem lidar com elas. Este conjunto é denominado tabelas EMV e pode ser obtido junto à Pagar.me via SDK.

Para baixar as tabelas EMV, as seguintes operações são realizadas:

  1. Download das tabelas EMV pela API Pagar.me;
  2. Transferência das tabelas baixadas para o PinPad.

A API Pagar.me fornece as tabelas EMV e então as bibliotecas, como no exemplo abaixo, fazem a instalação no PinPad:

public void receiveInitialization() {
                            Log.d("Abecs", "receive initialization!");
                            try {
                                mpos.downloadEMVTablesToDevice(true);
                            } catch (Exception e) {
                                Log.d("Abecs", "Got error in initialization and table update " + e.getMessage());
                            }
                        }

O valor booleano force dos exemplos especifica o comportamento de atualização de tabelas no PinPad. Caso esteja setado como true, faz o download e instala as tabelas baixadas no PinPad. Caso esteja como false, somente instala as tabelas no PinPad se a versão no PinPad for diferente da versão das tabelas na API Pagar.me, evitando instalações de forma redundante.

O parâmetro loaded nos eventos lançados por ocasião do término de atualização de tabelas indica, se true, que foram instaladas tabelas no PinPad; se false, que essa instalação não foi necessária.

Processando os dados de cartão

Para processar e obter um card_hash — que deverá ser enviado à API Pagar.me para que a transação seja criada — o seguinte código pode ser utilizado:

public void receiveTableUpdated(boolean loaded) {
                            Log.d("Abecs", "received table updated loaded = " + loaded);
                            EmvApplication visaCredit = new EmvApplication(PaymentMethod.CreditCard, "visa");
                            ArrayList<EmvApplication> l = new ArrayList<EmvApplication>();
                            l.add(visaCredit);
                            EmvApplication masterCredit = new EmvApplication(PaymentMethod.CreditCard, "master");

                            l.add(masterCredit);

                            mpos.payAmount(5000, l, PaymentMethod.CreditCard);
                        }

Este SDK usa uma função de processamento chamada payAmount com três parâmetros: amount, applications e magstripePaymentMethod.

O primeiro é um inteiro representando a quantia a ser cobrada em centavos (no caso dos exemplos, 100 = R$1,00). As opções possíveis são as seguintes:

ParâmetroSignificado
amountQuantia a ser cobrada em centavos (ex. 100 = R$1,00)
applicationsUm conjunto de EMVApplication que sua aplicação deseja selecionar. Uma EMVApplication consiste da combinação bandeira e método de pagamento (ex. Visa Crédito, Master Débito, Amex Crédito). Em caso de valor nulo, a escolha de possíveis aplicações é feita pelo pinpad.
magstripePaymentMethodA tarja magnética não permite seleção de método de pagamento no pinpad, e requer sempre que a aplicação o defina. Possíveis valores: PaymentMethod.CreditCard ou PaymentMethod.DebitCard

🚧

Vale ressaltar

Caso o conjunto de aplicações especificado não seja suportado pelo cartão inserido (ex. applications contém Visa Crédito e o cartão é Master Crédito), o pinpad retorna o erro 70.

Finalizando uma transação

Após a obtenção de um card_hash por meio do processamento no SDK, e seu envio à API Pagar.me para criação de uma transação, é necessário finalizar o procedimento como um todo. Para tal, o seguinte código deve ser usado:

boolean connected = true; /* Define se foi possível se conectar à API Pagar.me para processar a transação */ 

mpos.finishTransaction(connected, Integer.parseInt((String) t.get("acquirer_response_code")), (String) t.get("card_emv_response"));

Logo, considere a seguinte assinatura para o método finishTransaction:

finishTransaction(boolean connected, int responseCode, String emvData)

Começando com o parâmetro connected, ele define se a conexão com a API Pagar.me foi bem-sucedida, e os demais podem ser encontrados no response da API Pagar.Me para seu servidor:

{
  "card_pin_mode": "online",
  "acquirer_response_code": "0000",
  "card_emv_response": "124046c481.ca8c"
}

Sendo:

ParâmetroCorrespondência no objeto transaction
responseCodeacquirer_response_code, diz respeito ao código de retorno do adquirente Pagar.Me para sua aplicação.
emvDatacard_emv_response: String responsável por finalizar a comunicação entre pinpad e cartão, e usada somente quando a autenticação foi pin online, veja a seguir.

card_pin_mode

Você deve usar este parâmetro para validar se é necessário executar o finishTransaction. Sempre que o retorno estiver como online, é necessário finalizar a transação, caso contrário apenas execute o fechamento da conexão com o PinPad.

🚧

Vale ressaltar

Caso não tenha sido possível fazer uma conexão com a API Pagar.me, para inicializar uma transação (e o parâmetro connected seja false), responseCode deve ser 0 e emvData deve ser null.


Próximo

Excelente! Você aprendeu como integrar sua aplicação com nosso SDK para mPOS, mas caso encontre algum erro ao longo do caminho, a seguinte tabela pode te ajudar na resolução, segue: