Tap On Phone (Early Access)
O Tap On Phone permite que smartphones Android comerciais (COTS) aceitem pagamentos por aproximação (NFC), sem a necessidade de um terminal de pagamento dedicado. Essa modalidade utiliza a tecnologia gTapp como processador de pagamentos.
O Tap On Phone requer que o aplicativo gTapp esteja instalado no dispositivo. O SDK verificará automaticamente a presença do app e retornará um erro caso ele não esteja disponível.
- Dispositivo Android com suporte a NFC
- Aplicativo gTapp instalado e atualizado
- Token de ativação (solicitar ao time de integrações do SDK Único)
- Dispositivo deve passar nas verificações de segurança (attestation)
Configuração
Passo 1 — Adicionar a flavor gsurf
Adicione a flavor gsurf ao bloco de flavors no build.gradle.kts:
val flavors = setOf(
// ... outras flavors
"gsurf" to 26,
)
Passo 2 — Dependências
Com Flavors
val sdkPayServicesVersion = "$SDK_VERSION"
implementation("SDKPayServices:core:$sdkPayServicesVersion")
implementation("SDKPayServices:config:$sdkPayServicesVersion")
implementation("SDKPayServices:common:$sdkPayServicesVersion")
Standalone (sem Flavors)
val sdkPayServicesVersion = "$SDK_VERSION"
implementation("SDKPayServices:core-gsurf:$sdkPayServicesVersion")
implementation("SDKPayServices:gsurf:$sdkPayServicesVersion")
implementation("SDKPayServices:config:$sdkPayServicesVersion")
implementation("SDKPayServices:common:$sdkPayServicesVersion")
Passo 3 — Permissões
Além das permissões padrão do SDK Único, o Tap On Phone requer permissão de NFC:
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
Diferenças em relação aos demais provedores
O Tap On Phone possui características específicas que o diferenciam dos provedores tradicionais (SmartPOS):
| Característica | Tap On Phone | Provedores SmartPOS |
|---|---|---|
| Dispositivo | Smartphones Android comerciais (COTS) | Terminais de pagamento dedicados |
| Captura do cartão | Apenas NFC (contactless) | Chip, tarja magnética, NFC |
| Ativação | Token de ativação (solicitar ao time de integrações) | CNPJ + parâmetros do provedor |
| Processador | PaymentProcessor.GSURF | STONE, TEF, REDE, etc. |
| Impressão | Via impressora externa (Bluetooth/USB) | Impressora térmica integrada |
| Transações suportadas | Crédito, Débito, Cancelamento | Todas as modalidades |
| Segurança | Attestation do dispositivo | Certificação PCI do terminal |
As seguintes operações não estão disponíveis no Tap On Phone: voucher, pix, wallet, qrCode, fleet, preAuthorize, capturePreAuthorization, cancelPreAuthorization, executeAdminOperation.
Ativação
A ativação do Tap On Phone utiliza o campo gsurf dos ActivationParameters. O token de ativação deve ser solicitado ao time de integrações do SDK Único.
GSurfActivationParameters
| Campo | Tipo | Descrição |
|---|---|---|
token | String? | Token de ativação do terminal. Solicitar ao time de integrações do SDK Único. Obrigatório. |
Realize a operação de ativação apenas 1 (uma) vez no terminal. Após a ativação bem-sucedida, o dispositivo fica vinculado à loja.
Exemplo
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.linx.paykit.common.Callback
import com.linx.paykit.common.activation.ActivationParameters
import com.linx.paykit.common.activation.ActivationResult
import com.linx.paykit.common.activation.GSurfActivationParameters
import com.linx.paykit.common.builder.Parameters
import com.linx.paykit.common.parameter.PaykitId
import com.linx.paykit.core.Paykit
import com.linx.paykit.core.PaykitFactory
class MainActivity : AppCompatActivity() {
private lateinit var paykit: Paykit
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
paykit = PaykitFactory().build(Parameters(this, "TapOnPhone", PaykitId("PAYKIT_ID")))
val activationParams = ActivationParameters(
storeCnpj = "12345678000199",
gsurf = GSurfActivationParameters(
token = "SEU_TOKEN_DE_ATIVACAO"
)
)
paykit.activate(activationParams, object : Callback<ActivationResult> {
override fun execute(result: ActivationResult) {
if (result.success) {
Log.i("Activation", "Tap On Phone ativado: ${result.message}")
} else {
Log.e("Activation", "Erro: ${result.message}")
}
}
})
}
}
Erros de Ativação
O Tap On Phone valida a segurança do dispositivo durante a ativação. Os possíveis erros são:
| Erro | Descrição |
|---|---|
TOKEN_NOT_INFORMED | Token de ativação não foi informado. |
APP_NOT_INSTALLED | Aplicativo gTapp não está instalado no dispositivo. |
INCOMPATIBLE_DEVICE | Dispositivo não é compatível com Tap On Phone (sem suporte a NFC ou hardware insuficiente). |
ACTIVATION_FAILED | Falha na ativação — token inválido, expirado ou já utilizado em outro dispositivo. |
DEVICE_NOT_SECURE | Dispositivo não passou na verificação de segurança (root, bootloader desbloqueado, etc.). |
DEVICE_NOT_AUTHENTICATED | Dispositivo não possui autenticação obrigatória configurada (PIN, senha ou biometria). |
Verificação de Segurança (Attestation)
O Tap On Phone valida continuamente a integridade do dispositivo antes e durante as transações. Quando o dispositivo é considerado inseguro, o SDK retorna o erro DEVICE_NOT_SECURE com um reason_code no campo rawData do resultado.
Códigos de Dispositivo Não Seguro
O campo rawData do resultado contém as chaves reason_code e reason_description:
| Código | Nome | Descrição | Solução |
|---|---|---|---|
| 1 | NO_SCREEN_LOCK | Dispositivo sem bloqueio de tela configurado. | Configurar bloqueio de tela (PIN, senha ou biometria) nas configurações do dispositivo. |
| 2 | DEBUG_MODE_ENABLED | Modo de depuração USB ou desenvolvedor habilitado. | Desabilitar as "Opções do desenvolvedor" e a "Depuração USB" nas configurações do dispositivo. |
| 3 | CRITICAL_ATTESTATION_THREAT | Ameaça crítica de segurança detectada no dispositivo. | Realizar restauração de fábrica ou utilizar outro dispositivo. Consulte a tabela de ameaças abaixo para detalhes. |
| 4 | CAMERA_IN_USE_BY_OTHER_APP | Outro aplicativo está utilizando a câmera do dispositivo. | Fechar todos os aplicativos que utilizam a câmera antes de iniciar a transação. |
| 5 | POSSIBLE_SECURITY_VULNERABILITIES | Possíveis vulnerabilidades de segurança detectadas. | Atualizar o sistema operacional e o patch de segurança para a versão mais recente. Se persistir, realizar restauração de fábrica. |
| 6 | APP_LOST_FOCUS | A aplicação perdeu o foco durante a operação. | Não minimizar ou alternar entre aplicativos durante a transação. Tentar novamente mantendo o app em primeiro plano. |
Ameaças Críticas de Attestation
Quando o reason_code é 3 (CRITICAL_ATTESTATION_THREAT), significa que o sistema de attestation detectou uma ameaça no dispositivo. As ameaças são agrupadas por categoria:
Ameaças do Dispositivo
| Ameaça | Descrição | Solução | Recuperável? |
|---|---|---|---|
| Dispositivo com root | Acesso privilegiado não autorizado ao sistema operacional. | Restauração de fábrica ou utilizar outro dispositivo. | ❌ |
| Adulteração do sistema | Remoção das limitações de segurança do fabricante. | Restauração de fábrica ou utilizar outro dispositivo. | ❌ |
| Emulador | App executando em ambiente emulado (não é um dispositivo físico). | O Tap On Phone requer um dispositivo Android físico. | ❌ |
| Bootloader desbloqueado | O bootloader do dispositivo não é seguro. | Restauração de fábrica ou utilizar outro dispositivo. | ❌ |
| SELinux desabilitado | Recurso de segurança do sistema desativado. | Restauração de fábrica ou utilizar outro dispositivo. | ❌ |
| Modo depuração USB | Opção de desenvolvimento habilitada no dispositivo. | Desabilitar "Opções do desenvolvedor" nas configurações. | ✅ |
| ADB Wi-Fi habilitado | Depuração sem fio habilitada no dispositivo. | Desabilitar "Opções do desenvolvedor" nas configurações. | ✅ |
| Horário do dispositivo inválido | Relógio do dispositivo desatualizado ou incorreto. | Ajustar data e hora para automático nas configurações. | ✅ |
Ameaças de Aplicativo
| Ameaça | Descrição | Solução | Recuperável? |
|---|---|---|---|
| App malicioso detectado | Aplicativo malicioso instalado no dispositivo. | Desinstalar o app identificado. Se persistir, restauração de fábrica. | ⚠️ |
| Malware via sideload | Malware instalado por loja não oficial. | Desinstalar o app malicioso e instalar apps apenas via Google Play. | ⚠️ |
| App com depuração habilitada | Um app com modo debug pode ser explorado. | Desinstalar o app identificado. Se persistir, restauração de fábrica. | ⚠️ |
| Adulteração de app | Bibliotecas do app foram modificadas ou injetadas. | Restauração de fábrica ou utilizar outro dispositivo. | ❌ |
| App gTapp não reconhecido | Versão do gTapp não corresponde ao registrado no Google Play. | Desinstalar o gTapp e reinstalar via Google Play Store. | ✅ |
| Rollback de versão | Tentativa de reverter o app para uma versão anterior. | Restauração de fábrica ou utilizar outro dispositivo. | ❌ |
| App não licenciado | O gTapp não foi obtido pelo Google Play. | Desinstalar e reinstalar via Google Play Store. Verificar conta Google. | ✅ |
| Assinatura de app inválida | Certificado do app não corresponde ao esperado. | Atualizar o SO e o patch de segurança. Reinstalar o gTapp via Google Play. | ⚠️ |
Ameaças de Rede
| Ameaça | Descrição | Solução | Recuperável? |
|---|---|---|---|
| Man-in-the-Middle (SSL Strip) | Ataque interceptando tráfego HTTPS. | Restauração de fábrica ou utilizar outro dispositivo. | ❌ |
| Ponto de acesso falso | Rede Wi-Fi mascarando redes conhecidas. | Remover todas as redes Wi-Fi salvas e conectar apenas em redes confiáveis. | ✅ |
| Rede comprometida | Dados podem estar sendo interceptados. | Remover todas as redes Wi-Fi salvas e conectar apenas em redes confiáveis. | ✅ |
| Link de phishing visitado | Usuário acessou URL potencialmente maliciosa. | Restauração de fábrica ou utilizar outro dispositivo. | ❌ |
Ameaças de PIN (Tela de Senha)
| Ameaça | Descrição | Solução | Bloqueante? |
|---|---|---|---|
| Modo desenvolvedor ativo | Impede transações que exigem digitação de senha. | Desabilitar "Opções do desenvolvedor" nas configurações. | Não bloqueia o dispositivo |
| Acessibilidade habilitada | Serviço de acessibilidade ativo impede digitação de PIN. | Desabilitar serviços de acessibilidade nas configurações. | Não bloqueia o dispositivo |
| Captura de tela habilitada | Serviço com capacidade de screenshot detectado. | Desabilitar serviços de acessibilidade. | Não bloqueia o dispositivo |
| Gravação de tela detectada | Aplicativo gravando a tela durante transação. | Parar gravação de tela antes de usar o Tap On Phone. | Não bloqueia o dispositivo |
| Tela obscurecida | Outra janela sobrepondo a tela de PIN. | Fechar todos os apps sobrepostos (bolhas de chat, etc.). | Não bloqueia o dispositivo |
| Perda de foco no PIN | Usuário saiu da tela de PIN durante transação. | Não alternar entre apps durante digitação de senha. | Não bloqueia o dispositivo |
Ameaças de Integridade (Google Play Integrity / Key Attestation)
| Ameaça | Descrição | Solução | Recuperável? |
|---|---|---|---|
| Integridade básica | Versão não reconhecida do Android. | Restauração de fábrica ou utilizar outro dispositivo. | ❌ |
| Integridade virtual | Dispositivo executando em emulador. | Utilizar um dispositivo Android físico. | ❌ |
| Nível de segurança do keystore | Dispositivo sem keystore fortemente seguro. | Utilizar outro dispositivo compatível. | ❌ |
| Versão do SO desatualizada | Android não atende os requisitos mínimos. | Atualizar o sistema operacional. Se não houver atualização, utilizar outro dispositivo. | ⚠️ |
| Patch de segurança desatualizado | Patch de segurança não atende os requisitos. | Atualizar o patch de segurança. Se não houver atualização, utilizar outro dispositivo. | ⚠️ |
| Cadeia de certificados inválida | Certificados do keystore expirados ou malformados. | Atualizar o SO. Se persistir, restauração de fábrica ou utilizar outro dispositivo. | ⚠️ |
Quando o dispositivo falha na verificação de segurança (attestation), os dados de ativação persistidos no dispositivo são removidos automaticamente. Isso significa que, após resolver o problema de segurança, será necessário realizar uma nova ativação com o token antes de processar transações novamente.
- ✅ Recuperável — O problema pode ser resolvido com ações simples no dispositivo.
- ⚠️ Parcialmente recuperável — Pode ser resolvido, mas se as ações sugeridas não funcionarem, será necessário restauração de fábrica ou outro dispositivo.
- ❌ Não recuperável — Requer restauração de fábrica ou substituição do dispositivo.
- Em caso de dúvidas, consulte o time de integrações do SDK Único.
Transações
Crédito
O Tap On Phone suporta crédito à vista e parcelado (loja e emissor). O valor é enviado em centavos internamente pelo SDK.
val creditParams = CreditParameters(
amount = BigDecimal("150.00"),
installments = 3, // Parcelado em 3x (omitir para à vista)
externalId = "ORDER_123456"
)
paykit.credit(creditParams, object : Callback<PaymentResult> {
override fun execute(result: PaymentResult) {
if (result.status == TransactionStatus.APPROVED) {
Log.i("Payment", "Crédito aprovado: ${result.id}")
Log.i("Payment", "NSU: ${result.nsuInfo?.hostNsu}")
} else {
Log.e("Payment", "Negado: ${result.message}")
}
}
})
Débito
val debitParams = DebitParameters(
amount = BigDecimal("50.00"),
externalId = "ORDER_789012"
)
paykit.debit(debitParams, object : Callback<PaymentResult> {
override fun execute(result: PaymentResult) {
if (result.status == TransactionStatus.APPROVED) {
Log.i("Payment", "Débito aprovado: ${result.id}")
} else {
Log.e("Payment", "Negado: ${result.message}")
}
}
})
Cancelamento
O cancelamento no Tap On Phone requer paymentId, originalPaymentType (CREDIT ou DEBIT) e o valor a ser cancelado (cancelAmount ou amount).
O campo originalPaymentType é obrigatório no Tap On Phone e deve ser PaymentType.CREDIT ou PaymentType.DEBIT. Outros tipos serão rejeitados.
val cancelParams = CancelParameter(
paymentId = "TRANSACTION_ID_ORIGINAL",
amount = BigDecimal("150.00"),
originalPaymentType = PaymentType.CREDIT,
cancelAmount = BigDecimal("50.00") // Para cancelamento parcial
)
paykit.cancel(cancelParams, object : Callback<CancelResult> {
override fun execute(result: CancelResult) {
if (result.status == TransactionStatus.APPROVED) {
Log.i("Cancel", "Cancelamento aprovado: ${result.id}")
} else {
Log.e("Cancel", "Erro: ${result.message}")
}
}
})
Erros de Transação
Além dos erros padrão do SDK, o Tap On Phone pode retornar os seguintes erros específicos:
| Erro | Descrição |
|---|---|
TERMINAL_NOT_ACTIVE | Terminal não ativado — execute activate antes |
TERMINAL_EXPIRED | Autenticação do terminal expirou — reative o terminal |
ATTESTATION_FAILED | Falha no attestation do dispositivo |
ACCESSIBILITY_ENABLED | Serviços de acessibilidade ativos impedem a transação |
TRANSACTION_CANCELLED_BY_USER | Usuário cancelou a transação na tela do gTapp |
TRANSACTION_TIMEOUT | Tempo limite para aproximação do cartão excedido |
Customização Visual
O Tap On Phone permite customizar a aparência das telas de pagamento exibidas pelo gTapp. A customização é configurada via Parameter Manager através do parâmetro config_gsurf_customization.
Campos de Customização
| Campo | Tipo | Descrição |
|---|---|---|
backgroundStartColor | String | Cor inicial do gradiente de fundo (hex #RRGGBB) |
backgroundEndColor | String | Cor final do gradiente de fundo (hex #RRGGBB) |
logoUrl | String | URL HTTPS do logotipo exibido na tela de pagamento |
currencySymbolTextColor | String | Cor do símbolo da moeda (R$) |
amountTextColor | String | Cor do valor da transação |
paymentTypeTextColor | String | Cor do texto do tipo de pagamento |
cancelButtonColor | String | Cor do botão de cancelar |
cancelButtonIconColor | String | Cor do ícone do botão de cancelar |
contactlessLogoColor | String | Cor do ícone de contactless |
titleTextColor | String | Cor do título |
subtitleTextColor | String | Cor do subtítulo |
mainProgressBarColor | String | Cor da barra de progresso principal |
timerBarColor | String | Cor da barra de tempo |
initialProgressBarColor | String | Cor da barra de progresso inicial |
cardHintBottomSheetButtonColor | String | Cor do botão de dica do cartão |
cardHintBottomSheetButtonTextColor | String | Cor do texto do botão de dica do cartão |
Formato do JSON
{
"backgroundStartColor": "#59366D",
"backgroundEndColor": "#9A6FB4",
"logoUrl": "https://exemplo.com/logo.png",
"currencySymbolTextColor": "#FFFFFF",
"amountTextColor": "#FFFFFF",
"paymentTypeTextColor": "#FFFFFF",
"cancelButtonColor": "#B388CD",
"cancelButtonIconColor": "#FFFFFF",
"contactlessLogoColor": "#FFFFFF",
"titleTextColor": "#FFFFFF",
"subtitleTextColor": "#FFFFFF",
"mainProgressBarColor": "#B388CD",
"timerBarColor": "#B388CD",
"initialProgressBarColor": "#9A6FB4",
"cardHintBottomSheetButtonColor": "#59366D",
"cardHintBottomSheetButtonTextColor": "#FFFFFF"
}
Todos os campos são opcionais. Apenas os campos informados serão aplicados; os demais mantêm o visual padrão do gTapp. Caso o parâmetro config_gsurf_customization não esteja configurado ou esteja vazio, o SDK aplica o fallback com as cores do tema padrão.
Impressão
Por ser executado em smartphones comerciais (sem impressora térmica integrada), o Tap On Phone utiliza impressoras externas via Bluetooth ou USB. O SDK detecta automaticamente a impressora disponível através do PrinterManager.
val bitmap: Bitmap = // Bitmap do comprovante
paykit.print(bitmap, object : Callback<PrintResult> {
override fun execute(result: PrintResult) {
if (result.success) {
Log.i("Print", "Comprovante impresso")
} else {
Log.e("Print", "Erro: ${result.message} - Status: ${result.status}")
}
}
})
Consulta da Última Transação
O Tap On Phone permite consultar os dados da última transação realizada:
paykit.getLastTransaction(object : Callback<TransactionQueryResult> {
override fun execute(result: TransactionQueryResult) {
Log.i("Query", "Última transação: ${result.id} - ${result.status}")
}
})
Este conteúdo foi útil para você?