Como atualizar seu app de pagamento Android para fornecer o endereço de entrega e os dados de contato do pagador com as APIs Web Payments.
Publicado em 17 de julho de 2020, última atualização: 27 de maio de 2025
Inserir o endereço de entrega e os dados de contato em um formulário da Web pode ser uma experiência complicada para os clientes. Isso pode causar erros e reduzir a taxa de conversão.
É por isso que a API Payment Request oferece suporte a um recurso para solicitar o endereço de entrega e informações de contato. Isso oferece vários benefícios:
- Os usuários podem escolher o endereço certo com apenas alguns toques.
- O endereço é sempre retornado no formato padronizado.
- É menos provável que você envie um endereço incorreto.
Os navegadores podem adiar a coleta de endereço de entrega e informações de contato para um app de pagamento para oferecer uma experiência de pagamento unificada. Essa funcionalidade é chamada de delegação.
Sempre que possível, o Chrome delega a coleta do endereço de entrega e das informações de contato de um cliente para o app de pagamento Android invocado. Essa delegação reduz a fricção durante a finalização da compra.
O site do comerciante pode atualizar de forma dinâmica as opções de frete e o preço total, dependendo da escolha do cliente de endereço de entrega e opção de frete.
Para adicionar suporte à delegação a um app de pagamento Android já existente, implemente estas etapas:
- Declarar delegações compatíveis.
- Analise os extras de intent
PAY
para conferir as opções de pagamento necessárias. - Fornecer as informações necessárias na resposta ao pagamento.
- [Opcional] Suporte a fluxo dinâmico:
Declarar delegações compatíveis
O navegador precisa saber a lista de informações adicionais que o app de pagamento
pode fornecer para delegar a coleta dessas informações ao
app. Declare as delegações compatíveis como <meta-data>
no
AndroidManifest.xml do app.
<activity
android:name=".PaymentActivity"
…
<meta-data
android:name="org.chromium.payment_supported_delegations"
android:resource="@array/chromium_payment_supported_delegations" />
</activity>
android:resource
precisa apontar para um <string-array>
que contenha todos ou um subconjunto dos seguintes valores:
payerName
payerEmail
payerPhone
shippingAddress
O exemplo a seguir só pode fornecer um endereço de entrega e o endereço de e-mail do pagador.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="chromium_payment_supported_delegations">
<item>payerEmail</item>
<item>shippingAddress</item>
</string-array>
</resources>
Analisar extras de intent PAY
para opções de pagamento obrigatórias
O comerciante pode especificar outras informações obrigatórias usando o
dicionário
paymentOptions
. O Chrome vai fornecer a lista de opções necessárias que o app pode
transmitir transmitindo os paymentOptions
extras de intent
para a atividade PAY
.
paymentOptions
paymentOptions
é o subconjunto de opções de pagamento especificadas pelo comerciante para as quais
o app declarou suporte à delegação.
Kotlin
val paymentOptions: Bundle? = extras.getBundle("paymentOptions")
val requestPayerName: Boolean? = paymentOptions?.getBoolean("requestPayerName")
val requestPayerPhone: Boolean? = paymentOptions?.getBoolean("requestPayerPhone")
val requestPayerEmail: Boolean? = paymentOptions?.getBoolean("requestPayerEmail")
val requestShipping: Boolean? = paymentOptions?.getBoolean("requestShipping")
val shippingType: String? = paymentOptions?.getString("shippingType")
Java
Bundle paymentOptions = extras.getBundle("paymentOptions");
if (paymentOptions != null) {
Boolean requestPayerName = paymentOptions.getBoolean("requestPayerName");
Boolean requestPayerPhone = paymentOptions.getBoolean("requestPayerPhone");
Boolean requestPayerEmail = paymentOptions.getBoolean("requestPayerEmail");
Boolean requestShipping = paymentOptions.getBoolean("requestShipping");
String shippingType = paymentOptions.getString("shippingType");
}
Ele pode incluir os seguintes parâmetros:
requestPayerName
: o booleano que indica se o nome do pagador é obrigatório.requestPayerPhone
: o booleano que indica se o telefone do pagador é necessário ou não.requestPayerEmail
: o booleano que indica se o e-mail do pagador é necessário.requestShipping
: o booleano que indica se as informações de frete são necessárias.shippingType
: a string que mostra o tipo de frete. O tipo de frete pode ser"shipping"
,"delivery"
ou"pickup"
. O app pode usar essa dica na interface ao solicitar o endereço do usuário ou a escolha de opções de frete.
shippingOptions
shippingOptions
é a matriz parcelável de opções de frete especificadas pelo comerciante. Esse parâmetro só vai existir quando paymentOptions.requestShipping ==
true
.
Kotlin
val shippingOptions: List<ShippingOption>? =
extras.getParcelableArray("shippingOptions")?.mapNotNull {
p -> from(p as Bundle)
}
Java
Parcelable[] shippingOptions = extras.getParcelableArray("shippingOptions");
for (Parcelable it : shippingOptions) {
if (it != null && it instanceof Bundle) {
Bundle shippingOption = (Bundle) it;
}
}
Cada opção de frete é um Bundle
com as seguintes chaves.
id
: o identificador da opção de frete.label
: o rótulo da opção de frete mostrado ao usuário.amount
: o pacote de custo de frete que contém as chavescurrency
evalue
com valores de string.currency
mostra a moeda do custo do frete, como um código alfabético de três letras bem formado ISO4217.value
mostra o valor do custo de frete como um valor monetário decimal válido.
selected
: indica se a opção de frete precisa ser selecionada quando o app de pagamento mostra as opções de frete.
Todas as chaves, exceto selected
, têm valores de string. selected
tem um valor
booleano.
Kotlin
val id: String = bundle.getString("id")
val label: String = bundle.getString("label")
val amount: Bundle = bundle.getBundle("amount")
val selected: Boolean = bundle.getBoolean("selected", false)
Java
String id = bundle.getString("id");
String label = bundle.getString("label");
Bundle amount = bundle.getBundle("amount");
Boolean selected = bundle.getBoolean("selected", false);
Fornecer as informações necessárias em uma resposta de pagamento
Seu app precisa incluir as informações adicionais necessárias na resposta à
atividade PAY
.
Para fazer isso, os seguintes parâmetros precisam ser especificados como extras de intent:
payerName
: o nome completo do pagador. Precisa ser uma string não vazia quandopaymentOptions.requestPayerName
for verdadeiro.payerPhone
: o número de telefone do pagador. Precisa ser uma string não vazia quandopaymentOptions.requestPayerPhone
for verdadeiro.payerEmail
: o endereço de e-mail do pagador. Precisa ser uma string não vazia quandopaymentOptions.requestPayerEmail
for verdadeiro.shippingAddress
: o endereço de entrega fornecido pelo usuário. Ele precisa ser um pacote não vazio quandopaymentOptions.requestShipping
for verdadeiro. O pacote precisa ter as seguintes chaves, que representam partes diferentes em um endereço físico.countryCode
postalCode
sortingCode
region
city
dependentLocality
addressLine
organization
recipient
phone
Todas as chaves, excetoaddressLine
, têm valores de string. OaddressLine
é uma matriz de strings.
shippingOptionId
: o identificador da opção de frete selecionada pelo usuário. Precisa ser uma string não vazia quandopaymentOptions.requestShipping
for verdadeiro.
Validar a resposta de pagamento
Se o resultado da atividade de uma resposta de pagamento recebida do app de pagamento invocado
estiver definido como RESULT_OK
, o Chrome vai verificar se há informações
adicionais necessárias nos extras. Se a validação falhar, o Chrome vai retornar uma promessa
rejeitada de request.show()
com uma das seguintes mensagens de erro
para desenvolvedores:
'Payment app returned invalid response. Missing field "payerEmail".'
'Payment app returned invalid response. Missing field "payerName".'
'Payment app returned invalid response. Missing field "payerPhone".'
'Payment app returned invalid shipping address in response.'
'... is not a valid CLDR country code, should be 2 upper case letters [A-Z].'
'Payment app returned invalid response. Missing field "shipping option".'
O exemplo de código a seguir é um exemplo de resposta válida:
Kotlin
fun Intent.populateRequestedPaymentOptions() {
if (requestPayerName) {
putExtra("payerName", "John Smith")
}
if (requestPayerPhone) {
putExtra("payerPhone", "5555555555")
}
if (requestPayerEmail) {
putExtra("payerEmail", "john.smith@gmail.com")
}
if (requestShipping) {
val address: Bundle = Bundle()
address.putString("countryCode", "CA")
val addressLines: Array<String> =
arrayOf<String>("111 Richmond st. West")
address.putStringArray("addressLines", addressLines)
address.putString("region", "Ontario")
address.putString("city", "Toronto")
address.putString("postalCode", "M5H2G4")
address.putString("recipient", "John Smith")
address.putString("phone", "5555555555")
putExtra("shippingAddress", address)
putExtra("shippingOptionId", "standard")
}
}
Java
private Intent populateRequestedPaymentOptions() {
Intent result = new Intent();
if (requestPayerName) {
result.putExtra("payerName", "John Smith");
}
if (requestPayerPhone) {
presult.utExtra("payerPhone", "5555555555");
}
if (requestPayerEmail) {
result.putExtra("payerEmail", "john.smith@gmail.com");
}
if (requestShipping) {
Bundle address = new Bundle();
address.putExtra("countryCode", "CA");
address.putExtra("postalCode", "M5H2G4");
address.putExtra("region", "Ontario");
address.putExtra("city", "Toronto");
String[] addressLines = new String[] {"111 Richmond st. West"};
address.putExtra("addressLines", addressLines);
address.putExtra("recipient", "John Smith");
address.putExtra("phone", "5555555555");
result.putExtra("shippingAddress", address);
result.putExtra("shippingOptionId", "standard");
}
return result;
}
Opcional: oferecer suporte a fluxo dinâmico
Às vezes, o custo total de uma transação aumenta, como quando o usuário escolhe a opção de frete expresso ou quando a lista de opções de frete disponíveis ou os preços delas mudam quando o usuário escolhe um endereço de entrega internacional. Quando o app fornece o endereço de entrega ou a opção selecionada pelo usuário, ele precisa notificar o comerciante sobre qualquer mudança de endereço de entrega ou opção e mostrar ao usuário os detalhes de pagamento atualizados (fornecidos pelo comerciante).
Para notificar o comerciante sobre novas mudanças, implemente a
interface IPaymentDetailsUpdateServiceCallback
e declare-a no
AndroidManifest.xml
com o filtro de intent UPDATE_PAYMENT_DETAILS
.
Imediatamente após invocar a intent PAY
, o Chrome vai se conectar ao
serviço UPDATE_PAYMENT_DETAILS
(se ele existir) no mesmo pacote da
intent PAY
e chamar setPaymentDetailsUpdateService(service)
para fornecer
ao app de pagamento o endpoint IPaymentDetailsUpdateService
para notificar
sobre mudanças na forma de pagamento, na opção de envio ou no endereço de entrega do usuário.
Use packageManager.getPackagesForUid(Binder.getCallingUid())
ao receber
comunicação interprocesso (IPC, na sigla em inglês) para validar se o app que invocou a
intent PAY
tem o mesmo nome de pacote que o app que invocou os
métodos IPaymentDetailsUpdateServiceCallback
.
AIDL
Crie dois arquivos AIDL com o seguinte conteúdo:
org/chromium/components/payments/IPaymentDetailsUpdateServiceCallback.aidl
package org.chromium.components.payments;
import android.os.Bundle;
import org.chromium.components.payments.IPaymentDetailsUpdateService;
interface IPaymentDetailsUpdateServiceCallback {
oneway void updateWith(in Bundle updatedPaymentDetails);
oneway void paymentDetailsNotUpdated();
oneway void setPaymentDetailsUpdateService(IPaymentDetailsUpdateService service);
}
org/chromium/components/payments/IPaymentDetailsUpdateService.aidl
package org.chromium.components.payments;
import android.os.Bundle;
import org.chromium.components.payments.IPaymentDetailsUpdateServiceCallback;
interface IPaymentDetailsUpdateService {
oneway void changePaymentMethod(in Bundle paymentHandlerMethodData,
IPaymentDetailsUpdateServiceCallback callback);
oneway void changeShippingOption(in String shippingOptionId,
IPaymentDetailsUpdateServiceCallback callback);
oneway void changeShippingAddress(in Bundle shippingAddress,
IPaymentDetailsUpdateServiceCallback callback);
}
Serviço
Implemente o serviço IPaymentDetailsUpdateServiceCallback
.
Kotlin
class SampleUpdatePaymentDetailsCallbackService : Service() {
private val binder = object : IPaymentDetailsUpdateServiceCallback.Stub() {
override fun updateWith(updatedPaymentDetails: Bundle) {}
override fun paymentDetailsNotUpdated() {}
override fun setPaymentDetailsUpdateService(service: IPaymentDetailsUpdateService) {}
}
override fun onBind(intent: Intent?): IBinder? {
return binder
}
}
Java
import org.chromium.components.paymsnts.IPaymentDetailsUpdateServiceCallback;
public class SampleUpdatePaymentDetailsCallbackService extends Service {
private final IPaymentDetailsUpdateServiceCallback.Stub mBinder =
new IPaymentDetailsUpdateServiceCallback.Stub() {
@Override
public void updateWith(Bundle updatedPaymentDetails) {}
@Override
public void paymentDetailsNotUpdated() {}
@Override
public void setPaymentDetailsUpdateService(IPaymentDetailsUpdateService service) {}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
AndroidManifest.xml
Exponha o serviço para IPaymentDetailsUpdateServiceCallback
no
AndroidManifest.xml
.
<service
android:name=".SampleUpdatePaymentDetailsCallbackService"
android:exported="true">
<intent-filter>
<action android:name="org.chromium.intent.action.UPDATE_PAYMENT_DETAILS" />
</intent-filter>
</service>
Notificar o comerciante sobre mudanças na forma de pagamento, no endereço de entrega ou na opção de envio selecionada pelo usuário
Kotlin
try {
if (isOptionChange) {
service?.changeShippingOption(selectedOptionId, callback)
} else (isAddressChange) {
service?.changeShippingAddress(selectedAddress, callback)
} else {
service?.changePaymentMethod(methodData, callback)
}
} catch (e: RemoteException) {
// Handle the remote exception
}
Java
if (service == null) {
return;
}
try {
if (isOptionChange) {
service.changeShippingOption(selectedOptionId, callback);
} else (isAddressChange) {
service.changeShippingAddress(selectedAddress, callback);
} else {
service.changePaymentMethod(methodData, callback);
}
} catch (RemoteException e) {
// Handle the remote exception
}
changePaymentMethod
Notifica o comerciante sobre mudanças na forma de pagamento selecionada pelo usuário. O
pacote paymentHandlerMethodData
contém chaves methodName
e details
opcionais com valores de string. O Chrome vai verificar se há um pacote não vazio com um
methodName
não vazio e enviar um updatePaymentDetails
com uma das
seguintes mensagens de erro por callback.updateWith
se a validação falhar.
'Method data required.'
'Method name required.'
changeShippingOption
Notifica o comerciante sobre mudanças na opção de frete selecionada pelo usuário.
shippingOptionId
precisa ser o identificador de uma das opções de frete especificadas pelo comerciante. O Chrome vai verificar se há um shippingOptionId
não vazio e enviar
um updatePaymentDetails
com a seguinte mensagem de erro via
callback.updateWith
se a validação falhar.
'Shipping option identifier required.'
changeShippingAddress
Notifica o comerciante sobre mudanças no endereço de entrega fornecido pelo usuário. O Chrome
vai verificar se há um pacote shippingAddress
não vazio com um countryCode
válido
e enviar um updatePaymentDetails
com a seguinte mensagem de erro via
callback.updateWith
se a validação falhar.
'Payment app returned invalid shipping address in response.'
Mensagem de erro de estado inválido
Se o Chrome encontrar um estado inválido ao receber qualquer uma das solicitações de mudança,
ele chamará callback.updateWith
com um pacote updatePaymentDetails
revisado. O pacote vai conter apenas a chave error
com "Invalid state"
.
Exemplos de um estado inválido:
- Quando o Chrome ainda está aguardando a resposta do comerciante a uma mudança anterior, como um evento de mudança em andamento.
- O identificador da opção de frete fornecido pelo app de pagamento não pertence a nenhuma das opções de frete especificadas pelo comerciante.
Receber detalhes de pagamento atualizados do comerciante
Kotlin
override fun updateWith(updatedPaymentDetails: Bundle) {}
override fun paymentDetailsNotUpdated() {}
Java
@Override
public void updateWith(Bundle updatedPaymentDetails) {}
@Override
public void paymentDetailsNotUpdated() {}
updatedPaymentDetails
é o pacote equivalente ao dicionário
PaymentRequestDetailsUpdate
WebIDL e contém as seguintes
chaves opcionais:
total
: um pacote que contém as chavescurrency
evalue
. Ambas as chaves têm valores de string.shippingOptions
: a matriz parcelável de opções de envioerror
: uma string que contém uma mensagem de erro genérica (por exemplo, quandochangeShippingOption
não fornece um identificador de opção de frete válido)stringifiedPaymentMethodErrors
: uma string JSON que representa erros de validação para o método de pagamento.addressErrors
: um pacote com chaves opcionais idênticas aos valores de string e endereço de envio. Cada chave representa um erro de validação relacionado à parte correspondente do endereço de entrega.modifiers
: uma matriz parcelável de pacotes, cada uma com um campototal
e ummethodData
, que também são pacotes.
Uma chave ausente significa que o valor dela não mudou.