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

Download do SDK

Para integrar seu PinPad com uma aplicação que utiliza da biblioteca mPOS iOS Pagar.me você precisa primeiro fazer o download em: Bibliotecas

Ao finalizar o download, você deve descompactar a pasta mpos-ios, e localizar os diretórios lib e include, já que ambos serão necessários para os próximos passos.

Configurando o ambiente

Em seu Xcode, siga os seguintes passos:

  1. Adicione as libraries libabecs.a, libmpos.a, libmposios.a e libtms.a — que estão incluídas na distribuição do SDK (pasta lib) — nas configurações do projeto Xcode em Build Phases > Link Binary With Libraries;
  2. Adicione o diretório include da distribuição do SDK a Build Settings > Search Paths > Header Search Paths;
  3. Adicione o diretório lib da distribuição do SDK a Build Settings > Search Paths > Library Search Paths;
  4. Mude a opção Build Settings > Build Options > Enable Bitcode de Yes para No;
  5. Caso seu projeto use Objective-C ou Swift (e não Objective-C++), adicione -lstdc++ a Build Settings > Linking > Other Linker Flags.

Caso você use Swift

  1. Adicione um header file ao seu projeto para fazer o bridging, e insira:
#import <mpos-ios.h>
  1. No campo Build Settings > Swift Compiler - Code Generation > Objective-C Bridging Header, insira este header;
  2. Ao adicionar o Header, a classe PMMposController estará disponível para você.

Criando uma transação

O exemplo abaixo segue todo o fluxo para capturar as informações do cartão e gerar um card_hash para que posteriormente você consiga criar uma transação. Em seguida já explicamos os principais pontos do código, segue:

//
//  ViewController.m
//  mposToDocs
//
//  Created by Aardvark on 1/25/17.
//  Copyright © 2017 Aardvark. All rights reserved.
//

#import "ViewController.h"
#import <ExternalAccessory/ExternalAccessory.h>
#import "mpos-ios.h"

@interface ViewController ()

@end

@implementation ViewController

- (void) makeATransaction{
    // Obtém um objeto EAAccessory, que representa um aparelho Bluetooth pareado.
    EAAccessory *accessory = [[[EAAccessoryManager sharedAccessoryManager]
                               connectedAccessories]
                              firstObject];
    
    PMMposController *controller = [[PMMposController alloc] initWithAccessory:accessory encryptionKey:@"SUA ENCRYPTION_KEY"];
    [controller openConnection];
    
    [controller openSessionWithCallback:^(NSError *error) {
        if (error != nil) {
            /* Lidar com Erro */
            NSLog(@"What's wrong kido: %@", error);
            return;
        }
        /* Agora vamos configurar duas aplicações, ou seja, especificar 
         duas combinações de Bandeira + Tipo de cartão que desejamos limitar o aceite, 
         sendo Visa e Master crédito. Mas para aceitar todas, passe nil no parâmetro.
         */
        NSArray *applications = @[
                                  [PMEmvApplication applicationWithCardBrand:@"visa"
                                                               paymentMethod:MPM_CREDIT],
                                  [PMEmvApplication applicationWithCardBrand:@"master"
                                                               paymentMethod:MPM_CREDIT]
                                  ];
        
        
        /* selecionar Crédito como método de pagamento de tarja */
        [controller payAmount:15000 withApplications:applications
                                    magstripePaymentMethod:MPM_CREDIT
                 withCallback:^(NSString *cardHash,
                                NSDictionary *dict,
                                NSError *error) {
            NSLog(@"Sweet you've just got a cardHash, look: %@", cardHash);
            
            /*Excelente, neste momento já pode criar uma transação usando o cardHash gerado. */
            /* recomendamos que faça a chamada para API 
                  de um servidor externo, e não diretamente do device */         
            NSLog(@"Crie a transação neste ponto");
                     
            /* E após criar essa transação, a API Pagar.Me vai retornar alguns parâmetros que
             você precisa para encerrar o processo junto ao PinPad*/
                     
            [controller finishTransactionWithSuccessfulConnection:YES
                                                     responseCode:200
                                                          emvData:@"emvDataResponse"
                                                     withCallback:^(NSError *error){
                if(error != nil){
                    NSLog(@"Something went wrong while finishing the transaction, look: %@", error);
                }
                /*Com tudo certo, você deve agora encerrar a session e a connection com o Pinpad*/
                [controller closeSessionWithMessage:@"You are terminated!" callback:^(NSError *error) {
                    /* Hora de encerrar a connection também */
                    [controller closeConnection];
                }];
            }];
        }];
    }];
}

@end
import ExternalAccessory

// Obtém um objeto EAAccessory, que representa um aparelho Bluetooth pareado.
let accessory = EAAccessoryManager.sharedAccessoryManager().connectedAccessories.first

let controller = PMMposController(accessory: accessory, encryptionKey: "SUA_ENCRYPTION_KEY")
controller.openConnection()
controller.openSessionWithCallback({ (error: NSError!) -> Void in
    if error != nil {
        /* Lidar com Erro */
        return
    }

    /* aceitar somente Visa Crédito */
    var applications = [ PMEmvApplication(cardBrand: "visa", paymentMethod: MPM_CREDIT) ];

    /* selecionar Crédito como método de pagamento de tarja */
    controller.payAmount(100, withApplications: applications, withCallback: { (cardHash: String!, error: NSError!) -> Void in
        if error != nil {
            /* Lidar com Erro */
            return
        }
        NSLog("card_hash gerado = %@", cardHash);

        /* Gerar transação com a API Pagar.me... */       
        controller.finishTransactionWithSuccess(..., withCallback: { error: NSError! -> Void in
            if error != nil {
                /* Lidar com Erro */
                return
            }

            controller.closeSessionWithMessage(message: "Message", callback: { error: NSError! -> Void in
                controller.closeConnection()
            })
        })
    })
});

Atualizando tabelas EMV

Para as diferentes aplicações de Cartão de crédito (diferentes bandeiras e diferença entre crédito e débito) existe um conjunto de especificações de como o PinPad deve se comportar, assim como certificados que permitem ao PinPad lidar com elas. Este conjunto é denominado tabelas EMV e pode ser obtido junto ao 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 as bibliotecas, como no exemplo abaixo, fazem a instalação no PinPad:

#import <ExternalAccessory/ExternalAccessory.h>
#import "mpos-ios.h"

// Obtém um objeto EAAccessory, que representa um aparelho Bluetooth pareado.
EAAccessory *accessory = [[[EAAccessoryManager sharedAccessoryManager] connectedAccessories] firstObject];

PMMposController *controller = [[PMMposController alloc] initWithAccessory:accessory encryptionKey:@"{ENCRYPTION_KEY}"];
BOOL force = NO; // Define o comportamento da atualização de tabelas
[controller openConnection];
[controller openSessionWithCallback:^(NSError *error){
    if (error != nil) { /* Lidar com Erro */ return; }
    [controller downloadEMVTablesToDeviceWithCallback:^(BOOL loaded, NSError *error){
        if (error != nil) { /* Lidar com Erro */ return; }
        NSLog(@"Tabelas Carregadas: %d", loaded);
        [controller closeSessionWithMessage:@"Message" callback:^(NSError *error){
            [controller closeConnection];
        }];
    } forceUpdate:force];
}];
import ExternalAccessory

// Obtém um objeto EAAccessory, que representa um aparelho Bluetooth pareado.
let accessory = EAAccessoryManager.sharedAccessoryManager().connectedAccessories.first

let controller = PMMposController(accessory: accessory, encryptionKey: "ENCRYPTION_KEY")
let force = false // Define o comportamento da atualização de tabelas

controller.openConnection()
controller.openSessionWithCallback({ (error: NSError!) -> Void in
    if error != nil {
        /* Lidar com Erro */
        return
    }
    controller.downloadEMVTablesToDeviceWithCallback({ (loaded: Bool, error: NSError!) -> Void in
        if error != nil {
            /* Lidar com Erro */
            return;
        }

        NSLog("Tabelas Carregadas: %d", loaded);
        controller.closeSessionWithMessage(message: "Message", callback: { error: NSError! -> Void in
            controller.closeConnection()
        })

    }, forceUpdate: force)
});

O valor booleano force dos exemplos especifica o comportamento de atualização de tabelas no PinPad. Caso ele seja 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 uma transação de cartão de crédito/débito por intermédio do PinPad e obter o card hash — que deve ser enviado à API Pagar.me para que a transação seja completada — o seguinte código pode ser utilizado:

#import <ExternalAccessory/ExternalAccessory.h>
#import "mpos-ios.h"

// Obtém um objeto EAAccessory, que representa um aparelho Bluetooth pareado.
EAAccessory *accessory = [[[EAAccessoryManager sharedAccessoryManager] connectedAccessories] firstObject];

PMMposController *controller = [[PMMposController alloc] initWithAccessory:accessory encryptionKey:@"{ENCRYPTION_KEY}"];
[controller openConnection];
[controller openSessionWithCallback:^(NSError *error){
    if (error != nil) { /* Lidar com Erro */ return; }

    /* aceitar somente Visa Crédito */
    NSArray *applications = @[ [PMEmvApplication applicationWithCardBrand:@"visa" paymentMethod:MPM_CREDIT] ];

    /* selecionar Crédito como método de pagamento de tarja */
    [controller payAmount:100 withApplications:applications magstripePaymentMethod:MPM_CREDIT withCallback:^(NSString *cardHash, NSError *error){
        if (error != nil) { /* Lidar com Erro */ return; }
        NSLog(@"card_hash gerado = %@", cardHash);

        /* Gerar transação com a API Pagar.me... */
        [controller finishTransactionWithSuccess:... withCallback:^(NSError *error){
            if (error != nil) { /* Lidar com Erro */ return; }
            [controller closeSessionWithMessage:@"Message" callback:^(NSError *error){
                [controller closeConnection];
            }];
        }];
    }];
}];
import ExternalAccessory

// Obtém um objeto EAAccessory, que representa um aparelho Bluetooth pareado.
let accessory = EAAccessoryManager.sharedAccessoryManager().connectedAccessories.first

let controller = PMMposController(accessory: accessory, encryptionKey: "{ENCRYPTION_KEY}")
controller.openConnection()
controller.openSessionWithCallback({ (error: NSError!) -> Void in
    if error != nil {
        /* Lidar com Erro */
        return
    }

    /* aceitar somente Visa Crédito */
    var applications = [ PMEmvApplication(cardBrand: "visa", paymentMethod: MPM_CREDIT) ];

    /* selecionar Crédito como método de pagamento de tarja */
    controller.payAmount(100, withApplications: applications, withCallback: { (cardHash: String!, error: NSError!) -> Void in
        if error != nil {
            /* Lidar com Erro */
            return
        }
        NSLog("card_hash gerado = %@", cardHash);

        /* Gerar transação com a API Pagar.me... */       
        controller.finishTransactionWithSuccess(..., withCallback: { error: NSError! -> Void in
            if error != nil {
                /* Lidar com Erro */
                return
            }

            controller.closeSessionWithMessage(message: "Message", callback: { error: NSError! -> Void in
                controller.closeConnection()
            })
        })
    })
});

O SDK usa a função payAmount para capturar os dados, que aceita os seguites 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, que podem ser juntadas com o operador bitwise-OR (|):

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.

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:

#import "mpos-ios.h"

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

[controller finishTransactionWithSuccess:connected withResponseCode:[responseCode integerValue] emvData:emvData withCallback:^(NSError *error){}];
let connected = true; /* Define se foi possível se conectar à API Pagar.me para processar a transação */

controller.finishTransactionWithSuccess(connected, withResponseCode: Int(responseCode), emvData: emvData, withCallback: { error: NSError! }) -> Void in });

Os parâmetros responseCode e emvData devem ser retirados do objeto transaction retornado pela API Pagar.me:

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

Com a seguinte correspondência:

ParâmetroSignificado
responseCodeInteger dentro da propriedade acquirer_response_code do objeto transaction
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: