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.
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 é compatível com um recurso para solicitar dados de contato e endereço de entrega. 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 envie um endereço incorreto.
Os navegadores podem adiar a coleta do endereço de entrega e dos dados de contato para um app de pagamento para fornecer 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 dos dados de contato de um cliente ao app de pagamento para Android invocado. A delegação reduz o atrito na finalização da compra.
O site do comerciante pode atualizar dinamicamente as opções de envio e o preço total, dependendo da escolha do endereço de entrega e da opção de envio do cliente.
Para adicionar suporte à delegação a um app de pagamento para Android já existente, implemente as seguintes etapas:
- Declare as delegações compatíveis.
- Analise os extras da intent
PAY
para as opções de pagamento necessárias. - Forneça as informações necessárias na resposta ao pagamento.
- [Opcional] Suporte ao fluxo dinâmico:
Declarar delegações compatíveis
O navegador precisa conhecer a lista de outras informações 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/supported_delegations" />
</activity>
<resource>
precisa ser uma lista de strings escolhidas entre os seguintes valores válidos:
[ "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="supported_delegations">
<item>payerEmail</item>
<item>shippingAddress</item>
</string-array>
</resources>
Analisar os extras da intent PAY
para as opções de pagamento necessárias
O comerciante pode especificar outras informações necessárias usando o
dicionário
paymentOptions
. O Chrome vai fornecer a lista de opções necessárias que seu app pode
fornecer transmitindo os seguintes parâmetros para a atividade PAY
como extras
de intent.
paymentOptions
paymentOptions
é o subconjunto de opções de pagamento especificadas pelo comerciante para as quais seu app declarou suporte à delegação.
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")
Ele pode incluir os seguintes parâmetros:
requestPayerName
: o booleano que indica se o nome do pagador é obrigatório ou não.requestPayerPhone
: o booleano que indica se o smartphone do pagador é obrigatório.requestPayerEmail
: o booleano que indica se o e-mail do pagador é obrigatório ou não.requestShipping
: o booleano que indica se as informações de frete são obrigatórias ou não.shippingType
: a string que mostra o tipo de frete. O tipo de frete pode ser"shipping"
,"delivery"
ou"pickup"
. Seu app pode usar essa dica na interface ao solicitar o endereço do usuário ou a escolha das opções de envio.
shippingOptions
shippingOptions
é a matriz fracionável de opções de envio especificadas pelo comerciante. Esse parâmetro só existe quando paymentOptions.requestShipping ==
true
.
val shippingOptions: List<ShippingOption>? =
extras.getParcelableArray("shippingOptions")?.mapNotNull {
p -> from(p as Bundle)
}
Cada opção de envio é um Bundle
com as chaves a seguir.
id
: identificador da opção de envio.label
: o rótulo da opção de envio 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 de frete, como um código do alfabeto de três letras ISO4217 bem formado;value
mostra o valor do custo de frete, como um valor monetário decimal válido
selected
: se a opção de envio precisa ou não ser selecionada quando o app de pagamento exibe as opções de envio.
Todas as chaves, exceto selected
, têm valores de string. selected
tem um valor
booleano.
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)
Fornecer as informações necessárias na resposta ao pagamento
Seu app precisa incluir as informações extras 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
: número de telefone do pagador. Precisa ser uma string não vazia quandopaymentOptions.requestPayerPhone
for verdadeiro.payerEmail
: 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
é verdadeiro. O pacote precisa ter as seguintes chaves que representam partes diferentes em um endereço físico.city
countryCode
dependentLocality
organization
phone
postalCode
recipient
region
sortingCode
addressLine
Todas as chaves, excetoaddressLine
, têm valores de string. OaddressLine
é uma matriz de strings.
shippingOptionId
: o identificador da opção de envio selecionada pelo usuário. Ela precisa ser uma string que não esteja vazia quandopaymentOptions.requestShipping
for verdadeiro.
Validar 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 verificará as 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 voltadas para o desenvolvedor:
'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 mostra uma resposta válida:
fun Intent.populateRequestedPaymentOptions() {
if (requestPayerName) {
putExtra("payerName", "John Smith")
}
if (requestPayerPhone) {
putExtra("payerPhone", "4169158200")
}
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", "4169158200")
putExtra("shippingAddress", address)
putExtra("shippingOptionId", "standard")
}
}
Opcional: suporte ao 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 mudam quando o usuário escolhe um endereço de entrega internacional. Quando o app fornece o endereço ou a opção de entrega selecionado pelo usuário, ele pode notificar o comerciante sobre alterações de endereço ou opção de entrega e mostrar ao usuário os detalhes de pagamento atualizados fornecidos por ele.
AIDL
Para notificar o comerciante sobre novas mudanças, use o serviço PaymentDetailsUpdateService
declarado no AndroidManifest.xml do Chrome. Para usar esse serviço, crie dois
arquivos AIDL com o seguinte conteúdo:
app/src/main/aidl/org/chromium/components/payments/IPaymentDetailsUpdateService
package org.chromium.components.payments;
import android.os.Bundle;
interface IPaymentDetailsUpdateServiceCallback {
oneway void updateWith(in Bundle updatedPaymentDetails);
oneway void paymentDetailsNotUpdated();
}
app/src/main/aidl/org/chromium/components/payments/IPaymentDetailsUpdateServiceCallback
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);
}
Notificar o comerciante sobre mudanças na forma de pagamento, endereço de entrega ou opção de envio selecionada pelo usuário
private fun bind() {
// The action is introduced in Chrome version 92, which supports the service in Chrome
// and other browsers (e.g., WebLayer).
val newIntent = Intent("org.chromium.intent.action.UPDATE_PAYMENT_DETAILS")
.setPackage(callingBrowserPackage)
if (packageManager.resolveService(newIntent, PackageManager.GET_RESOLVED_FILTER) == null) {
// Fallback to Chrome-only approach.
newIntent.setClassName(
callingBrowserPackage,
"org.chromium.components.payments.PaymentDetailsUpdateService")
newIntent.action = IPaymentDetailsUpdateService::class.java.name
}
isBound = bindService(newIntent, connection, Context.BIND_AUTO_CREATE)
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val service = IPaymentDetailsUpdateService.Stub.asInterface(service)
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
}
}
}
O callingPackageName
usado para a intent de inicialização do serviço pode ter um dos
valores abaixo, dependendo do navegador que iniciou a solicitação de
pagamento.
Canal do Chrome | Nome do pacote |
---|---|
Estável |
"com.android.chrome"
|
Beta |
"com.chrome.beta"
|
Dev |
"com.chrome.dev"
|
Canary |
"com.chrome.canary"
|
Chromium |
"org.chromium.chrome"
|
Caixa de pesquisa rápida do Google (um incorporador da WebLayer) |
"com.google.android.googlequicksearchbox"
|
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, ambas com valores de string. O Chrome vai verificar se há um pacote não vazio com um
methodName
não vazio e enviar uma updatePaymentDetails
com uma das
mensagens de erro abaixo usando callback.updateWith
se a validação falhar.
'Method data required.'
'Method name required.'
changeShippingOption
Notifica o comerciante sobre mudanças na opção de envio selecionada pelo usuário.
shippingOptionId
precisa ser o identificador de uma das opções de envio especificadas pelo comerciante. Se a validação falhar, o Chrome vai verificar se há um shippingOptionId
não vazio e enviar
um updatePaymentDetails
com a seguinte mensagem de erro usando
callback.updateWith
.
'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 mensagem de erro abaixo pelo
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
encoberto. O pacote 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 alteração anterior (como um evento de alteração em andamento).
- O identificador da opção de envio fornecido pelo aplicativo de pagamento não pertence a nenhuma das opções de envio especificadas pelo comerciante.
Receber detalhes de pagamento atualizados do comerciante
private fun unbind() {
if (isBound) {
unbindService(connection)
isBound = false
}
}
private val callback: IPaymentDetailsUpdateServiceCallback =
object : IPaymentDetailsUpdateServiceCallback.Stub() {
override fun paymentDetailsNotUpdated() {
// Payment request details have not changed.
unbind()
}
override fun updateWith(updatedPaymentDetails: Bundle) {
newPaymentDetails = updatedPaymentDetails
unbind()
}
}
updatePaymentDetails
é o pacote equivalente ao dicionário PaymentRequestDetailsUpdate
WebIDL (após a edição do campo modifiers
) e contém as seguintes chaves opcionais:
total
: um pacote que contém as chavescurrency
evalue
, ambas com valores de string.shippingOptions
: a matriz fracioná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 envio válido).stringifiedPaymentMethodErrors
: uma string JSON que representa erros de validação da forma de pagamento.addressErrors
: um pacote com chaves opcionais idênticas ao endereço de entrega e aos valores de string. Cada chave representa um erro de validação relacionado à parte correspondente do endereço de entrega.
Uma chave ausente significa que o valor não foi alterado.