Pular para o conteúdo principal

Edição Reduced (Headless) - Early Access

A edição Reduced é uma variante do SDK Único sem interface embarcada (headless). Nela, toda a interação visual da jornada de pagamento é desenhada pela automação comercial e o SDK se comunica com o aplicativo por meio da interface PaykitUiCallback.

É indicada para integradores que precisam controlar 100% da UI e para ambientes legados (AGP 3.3.x, Gradle 4.10.3, Java 8, Android 7.1+) que não comportam as telas internas do SDK.

Dispositivos-alvo

A edição Reduced foi pensada para dispositivos Android (PDVs, tablets, smartphones) com captura via Pinpad USB ou Bluetooth. Ela também pode rodar em terminais SmartPOS, evitando embarcar as bibliotecas dos fabricantes — nesse cenário, a impressão fica sob responsabilidade da automação (veja Impressão).

Nota

A edição Reduced é distribuída como artefatos próprios, com sufixo -reduced, e não embarca o módulo de UI (sem Jetpack Compose). Em contrapartida, é obrigatório registrar uma implementação de PaykitUiCallback — sem ela, os fluxos interativos (como o cancelamento) não conseguem ser concluídos.

Passo 1 - Configurar as dependências

Utilize o mesmo repositório SDK_UNICO descrito em Primeiros Passos e adicione os artefatos da edição Reduced ao build.gradle.kts:

val sdkUnicoReducedVersion = "X.Y.Z-reduced"

implementation("SDKPayServices:core-reduced:$sdkUnicoReducedVersion")
implementation("SDKPayServices:reduced:$sdkUnicoReducedVersion")
implementation("SDKPayServices:config-reduced:$sdkUnicoReducedVersion")
implementation("SDKPayServices:common-reduced:$sdkUnicoReducedVersion")
ArtefatoDescrição
SDKPayServices:core-reducedNúcleo do SDK Único (edição Reduced).
SDKPayServices:reducedProvider TEF (LinxTEF/CliSiTef) sem BCs de fabricantes.
SDKPayServices:config-reducedConfiguração e parametrização.
SDKPayServices:common-reducedComponentes comuns.
Nota

A versão exata dos artefatos *-reduced é fornecida pela equipe Linx durante a integração.

Atenção

A edição Reduced não utiliza flavors de adquirente. Os quatro artefatos acima já compõem a integração headless via TEF — não é necessário (nem suportado) o bloco flavorDimensions/productFlavors descrito em Primeiros Passos.

Passo 2 - Registrar o PaykitUiCallback

Como não há telas internas, o SDK precisa de uma implementação de PaykitUiCallback (veja o esqueleto no Passo 3) registrada antes de qualquer transação. Há dois caminhos suportados — utilize um.

Caminho A - Registro estático (recomendado)

Chame PaykitUiModel.build(context, callback) antes de criar a instância do Paykit:

import com.linx.paykit.common.builder.Parameters
import com.linx.paykit.common.builder.PaykitId
import com.linx.paykit.core.PaykitFactory
import com.linx.paykit.ui.data.PaykitUiModel

val uiCallback = MeuPaykitUiCallback(this)

// 1) Registra o callback headless
PaykitUiModel.build(this, uiCallback)

// 2) Cria a instância do Paykit
val paykit = PaykitFactory().build(
Parameters(this, "Nome da Aplicação", PaykitId("SEU_PAYKIT_ID"))
)

Caminho B - Via Parameters.ui

Passe o callback no Parameters, definindo useInternalScreens = false:

import com.linx.paykit.common.ui.PaykitUiParams

val paykit = PaykitFactory().build(
Parameters(
this,
"Nome da Aplicação",
PaykitId("SEU_PAYKIT_ID"),
ui = PaykitUiParams(
callback = uiCallback,
useInternalScreens = false
)
)
)
Atenção

No Caminho B, useInternalScreens tem valor padrão true. Se você passar o callback mas mantiver o padrão, o SDK assume que usará telas internas (inexistentes na edição Reduced) e não registra o seu callback. Sempre defina useInternalScreens = false neste caminho.

Passo 3 - Implementar o PaykitUiCallback

A interface PaykitUiCallback não possui métodos com implementação padrão — todos precisam ser implementados. A descrição de cada método e dos tipos de resposta está em Referência: PaykitUiCallback. Esqueleto mínimo:

import com.linx.paykit.common.ui.*

class MeuPaykitUiCallback(
private val activity: Activity
) : PaykitUiCallback {

private fun ui(block: () -> Unit) = activity.runOnUiThread(block)

// Informativos: apenas exibir
override fun onShowMessage(message: String) = ui { /* exibir status */ }
override fun onShowAlert(message: String) = ui { /* exibir alerta */ }
override fun onShowError(message: String) = ui { /* exibir erro */ }
override fun onShowProcessing(message: String) = ui { /* exibir progresso */ }
override fun onShowInsertCard(message: String) = ui { /* "insira/aproxime o cartão" */ }
override fun onShowRemoveCard(message: String) = ui { /* "retire o cartão" */ }
override fun onShowPassword() = ui { /* "digite a senha" */ }
override fun onShowQrCode(message: String, qrCode: String, timeout: Int) =
ui { /* exibir QR Code */ }

// Interativos: OBRIGATÓRIO chamar operationResult uma vez
override fun onShowConfirmation(
message: String,
operationResult: (ConfirmationOperationResult) -> Unit
) = ui {
// exibir Sim/Não e responder:
// operationResult(ConfirmationOperationResult.Yes) ou .No
}

override fun onShowInput(
parameters: InputParameters,
operationResult: (InputOperationResult) -> Unit
) = ui {
// coletar o dado e responder:
// operationResult(InputOperationResult.Success(texto)) ou .Canceled
}

override fun onShowMenu(
label: String,
items: Array<String>,
timeout: Int?,
operationResult: (MenuOperationResult) -> Unit
) = ui {
// exibir opções e responder:
// operationResult(MenuOperationResult.Success(indice)) ou .Canceled
}

@Deprecated("Sobrecarga antiga sem timeout")
override fun onShowMenu(
label: String,
items: Array<String>,
operationResult: (MenuOperationResult) -> Unit
) = onShowMenu(label, items, null, operationResult)

// Estado de cancelamento
@Volatile private var canceled = false
override val isCanceled: Boolean get() = canceled
override fun setCanceledStatus(canceled: Boolean) { this.canceled = canceled }
override fun showCanceledStatus(): Boolean = canceled
}

Passo 4 - Executar operações

Com o callback registrado e o Paykit criado, as operações funcionam normalmente — o resultado chega no Callback<T> e as interações de tela chegam no PaykitUiCallback.

// Venda no crédito
paykit.credit(creditParameters) { result ->
Log.i("PaymentResult", "Status: ${result.status}")
}

Para o cancelamento interativo (operador confirma e digita o número do cartão pela UI da automação), utilize cancelInteractive:

paykit.cancelInteractive { result ->
Log.i("CancelResult", "Status: ${result.status}")
}
Nota

O cancelamento por parâmetro (cancel com CancelParameter) continua disponível na edição Reduced — veja Cancelamento. A diferença é que, na edição Reduced, todas as telas da jornada são entregues ao app via PaykitUiCallback.

Fluxo de um cancelamento interativo

Sequência típica de chamadas recebidas no PaykitUiCallback durante um cancelInteractive (pode variar conforme rede/configuração):

  1. onShowConfirmation("OPERACAO CANCELADA?") — exiba Sim/Não e responda ConfirmationOperationResult.Yes para prosseguir.
  2. onShowInput(...) com label = "NUMERO DO CARTAO" (dataType = CARD_NUMBER) — colete o número e responda InputOperationResult.Success("<numero>").
  3. onShowProcessing(...) / onShowMessage(...) — exiba progresso/status.
  4. Eventuais onShowMenu / onShowInput adicionais.
  5. Resultado final entregue no Callback<CancelResult> de cancelInteractive.

Impressão

Na edição Reduced, a automação comercial é responsável pela impressão. Como os artefatos -reduced não embarcam as bibliotecas dos fabricantes, a impressora nativa do terminal em geral não fica acessível ao SDK — chamadas de impressão degradam com segurança para "impressora indisponível", sem interromper o fluxo.

O ponto de atenção é a rotina do TEF, que por padrão tenta imprimir comprovantes automaticamente. Nas transações, desabilite a impressão automática e trate o comprovante pela sua rotina:

  • Envie autoPrintReceipt = false (e printMerchantReceipt = false, quando aplicável) nos parâmetros das transações.
  • Imprima o comprovante pela infraestrutura da própria automação, a partir do retorno transacional.

Solução de problemas

A jornada interativa não avança (ex.: "ao tocar para cancelar, nada acontece")

Quando um método interativo não é respondido (ou o callback não está registrado), o fluxo TEF fica repetindo a mesma solicitação. Verifique:

  • O PaykitUiCallback foi registrado (Caminho A ou B) antes da operação?
  • No Caminho B, useInternalScreens está como false?
  • Em todos os métodos interativos (onShowConfirmation, onShowInput, onShowMenu), o operationResult é chamado exatamente uma vez — inclusive nos caminhos de cancelamento (No / Canceled)?

No log (logcat), o sintoma é a repetição contínua de mensagens do tipo Exibindo mensagem de confirmação / Exibindo input sem nenhuma resposta.

Este conteúdo foi útil para você?