Pular para o conteúdo principal

Inicialização do Terminal

Com o merchantId em mãos, inicialize o terminal. A inicialização baixa a carga do gateway, grava as tabelas EMV de cada adquirente no pinpad e prepara o contexto de transação.

Chame a cada execução do app: o estado de inicializado vive só em memória e não é restaurado quando o processo reinicia. Sem inicialização, as operações financeiras respondem onAppError(SdkErrorCode.TERMINAL_NOT_INITIALIZED, ...).

import com.tupifintech.apossdk.sdk.api.model.TerminalInitializationRequest

val initResponse = posPinpad.terminalInitialization(
request = TerminalInitializationRequest(merchantId = merchantId)
)

if (initResponse.success) {
// Dados do estabelecimento (header, recibo, senha de acesso)
val merchant = initResponse.merchant
} else {
// Falha na ativação, no download da carga ou na preparação do contexto.
// Não libere vendas; ofereça nova tentativa.
}

O callback onTablesLoaded(ok) informa o resultado da gravação das tabelas no pinpad, uma vez por adquirente da carga. Ele também é chamado quando o SDK recarrega as tabelas sozinho (após transações ou quando o pinpad informa tabelas expiradas). Recomendação:

  • Considere a inicialização concluída só se initResponse.success for true e nenhum onTablesLoaded(false) tiver chegado durante a chamada.
  • Quando success == false, chega também onAppError(SdkErrorCode.TERMINAL_INITIALIZATION_FAILED, ...).
  • Falha de chave do adquirente padrão chega como onAppError(SdkErrorCode.PP_ERRKEY, ...). Nova tentativa não resolve: acione o suporte.

Para verificar o estado depois:

val ready = posPinpad.isTerminalInitialized() // só indica que terminalInitialization foi chamado
val tables = posPinpad.getTablesInfo() // versões das tabelas EMV por adquirente; null se nunca carregou

isTerminalInitialized() é true mesmo quando a inicialização falhou. Para saber se deu certo, use o retorno de terminalInitialization.

Coordenadas do Teclado PIN​

Importante: as coordenadas do teclado PIN não são configuradas antecipadamente. O SDK as solicita de forma reativa, na primeira captura de senha do processo, pelo callback onStartGetPinCoordinates. O app deve medir as posições dos botões na tela e devolvê-las pela função recebida.

override fun onStartGetPinCoordinates(setPinCoordinates: (List<String>) -> Unit) {
// Exiba a tela de PIN, meça os botões e chame setPinCoordinates(coords)
showPinScreen(onCoordinatesReady = { coords -> setPinCoordinates(coords) })
}

Formato e ordem da lista​

São 13 itens, cada um uma string "left,top,right,bottom" em pixels da janela (positionInWindow() no Compose ou getLocationInWindow() em Views). A ordem esperada é:

ÍndiceTecla
0–8Números 1 a 9
9Número 0
10CANCELAR
11OK / Confirma
12Backspace
  • O SDK aguarda as coordenadas por 5 segundos. Sem resposta, o pinpad segue sem as teclas mapeadas e a digitação da senha falha.
  • O portador tem 60 segundos para digitar a senha.
  • As coordenadas ficam em cache durante o processo: o callback não é chamado de novo nas transações seguintes. Mantenha o teclado sempre na mesma posição.
  • Se MerchantInfo.accessibilityKeyboard for true, exiba o teclado de senha de acessibilidade (4 colunas, compatível com a película tátil da Positivo).
  • A máscara da senha digitada chega por onPinEntry(pinMask, message, amount).

No Compose, as coordenadas podem ser obtidas com onGloballyPositioned + positionInWindow(). Veja o exemplo completo em Exemplos.

Informações do Dispositivo​

val info = posPinpad.getDeviceInfo() // lança IllegalStateException se o pinpad ainda não conectou
Log.d("YBY", "Modelo: ${info.hardwareModel}")
Log.d("YBY", "Serial: ${info.serialNo}")
Log.d("YBY", "Firmware: ${info.firmwareVersion}")

val tid = posPinpad.getTerminalTid() // TID do adquirente, o mesmo impresso no comprovante
val sim = posPinpad.getSimInfo() // suspend: ICCID, operadora e transporte ativo; null se o serviço não responder

A conexão com o pinpad acontece em segundo plano após create. Logo depois de criar a instância, trate a IllegalStateException de getDeviceInfo() e tente de novo mais tarde.

Health Check​

val health = posPinpad.checkInternetConnection()
if (!health.isConnected) {
showError(health.errorMessage ?: "Sem conexão")
}

HealthCheckResult traz também hasNetworkConnection, isApiReachable e latencyMs.

Boas Práticas​

Tratamento de erros​

Implemente os callbacks de erro (onAppError, onNetworkConnectionError, onUnauthorizedError, onSessionExpired, etc.). Os de erro HTTP não chegam na main thread. Veja Callbacks.

override fun onAppError(error: SdkErrorCode, message: String) {
Log.e("YBY", "Erro ${error.name} (${error.code}): $message")
showErrorDialog(message)
}

override fun onNetworkConnectionError() {
runOnUiThread { showErrorDialog("Sem conexão com a internet") }
}

Dados sensíveis​

Nunca registre em log dados de pagamento (PAN, PIN, track) nem a accessPassword do merchant.