Come aggiornare l'app di pagamento Android per fornire l'indirizzo di spedizione e i dati di contatto del pagatore con le API Web Payments.
Inserire l'indirizzo di spedizione e i dati di contatto tramite un modulo web può essere un'esperienza complicata per i clienti. Può causare errori e ridurre il tasso di conversione.
Ecco perché l'API Payment Request supporta una funzionalità per richiedere l'indirizzo di spedizione e i dati di contatto. Ciò offre diversi vantaggi:
- Gli utenti possono scegliere l'indirizzo giusto con pochi tocchi.
- L'indirizzo viene sempre restituito nel formato standardizzato.
- È meno probabile che invii un indirizzo errato.
I browser possono rimandare la raccolta dell'indirizzo di spedizione e dei dati di contatto a un'app di pagamento per offrire un'esperienza di pagamento unificata. Questa funzionalità è chiamata delega.
Quando possibile, Chrome delega la raccolta dell'indirizzo di spedizione e dei dati di contatto di un cliente all'app per pagamenti Android richiamata. La delega riduce gli attriti durante il pagamento.
Il sito web del commerciante può aggiornare in modo dinamico le opzioni di spedizione e il prezzo totale a seconda dell'indirizzo di spedizione scelto dal cliente e dell'opzione di spedizione.
Per aggiungere il supporto della delega a un'app per pagamenti Android già esistente, implementa i seguenti passaggi:
- Dichiara le deleghe supportate.
- Analizza gli extra di
PAY
per intent per le opzioni di pagamento richieste. - Fornisci i dati richiesti nella risposta al pagamento.
- [Facoltativo] Supporto del flusso dinamico:
- Comunica al commerciante le modifiche relative al metodo di pagamento, all'indirizzo di spedizione o all'opzione di spedizione selezionati dall'utente.
- Ricevere dal commerciante i dettagli di pagamento aggiornati (ad es. l'importo totale rettificato in base al costo dell'opzione di spedizione selezionata).
Dichiara le deleghe supportate
Il browser deve conoscere l'elenco di informazioni aggiuntive che l'app di pagamento può fornire per poter delegare la raccolta di queste informazioni alla tua app. Dichiara le deleghe supportate come <meta-data>
nel file AndroidManifest.xml della tua app.
<activity
android:name=".PaymentActivity"
…
<meta-data
android:name="org.chromium.payment_supported_delegations"
android:resource="@array/supported_delegations" />
</activity>
<resource>
deve essere un elenco di stringhe scelto dai seguenti valori validi:
[ "payerName", "payerEmail", "payerPhone", "shippingAddress" ]
Nell'esempio seguente è possibile fornire solo un indirizzo di spedizione e l'indirizzo email del pagatore.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="supported_delegations">
<item>payerEmail</item>
<item>shippingAddress</item>
</string-array>
</resources>
Analizza gli extra di PAY
per intent per le opzioni di pagamento richieste
Il commerciante può specificare le informazioni aggiuntive richieste utilizzando il dizionario
paymentOptions
. Chrome fornirà l'elenco delle opzioni richieste che la tua app può fornire passando i seguenti parametri all'attività PAY
come extra per intent.
paymentOptions
paymentOptions
è il sottoinsieme di opzioni di pagamento specificate dal commerciante per cui la tua app ha dichiarato il supporto della delega.
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")
Può includere i seguenti parametri:
requestPayerName
: il valore booleano che indica se il nome del pagatore è obbligatorio o meno.requestPayerPhone
: il valore booleano che indica se è richiesto o meno il telefono di chi paga.requestPayerEmail
: il valore booleano che indica se l'indirizzo email del pagatore è obbligatorio o meno.requestShipping
: il valore booleano che indica se sono necessarie o meno le informazioni di spedizione.shippingType
: la stringa che mostra il tipo di spedizione. Il tipo di spedizione può essere"shipping"
,"delivery"
o"pickup"
. L'app può usare questo suggerimento nella sua UI per richiedere l'indirizzo dell'utente o la scelta delle opzioni di spedizione.
shippingOptions
shippingOptions
è la serie di opzioni di spedizione specificate dal commerciante. Questo parametro esisterà solo quando paymentOptions.requestShipping ==
true
.
val shippingOptions: List<ShippingOption>? =
extras.getParcelableArray("shippingOptions")?.mapNotNull {
p -> from(p as Bundle)
}
Ogni opzione di spedizione è un Bundle
con le seguenti chiavi.
id
: l'identificatore dell'opzione di spedizione.label
: l'etichetta dell'opzione di spedizione mostrata all'utente.amount
: il pacchetto per il costo di spedizione contenentecurrency
evalue
chiavi con valori stringa.currency
mostra la valuta del costo di spedizione, sotto forma di codice alfabetico di tre lettere corretto ISO4217value
mostra il valore del costo di spedizione, sotto forma di valore monetario decimale valido
selected
: indica se selezionare o meno l'opzione di spedizione quando l'app di pagamento mostra le opzioni di spedizione.
Tutte le chiavi tranne selected
hanno valori stringa. selected
ha un valore 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)
Fornire le informazioni richieste nella risposta al pagamento
La tua app deve includere le informazioni aggiuntive richieste nella risposta
all'attività di PAY
.
A tale scopo, è necessario specificare i seguenti parametri come extra per intent:
payerName
: nome completo del pagatore. Deve essere una stringa non vuota quandopaymentOptions.requestPayerName
è true.payerPhone
: il numero di telefono di chi effettua il pagamento. Deve essere una stringa non vuota quandopaymentOptions.requestPayerPhone
è true.payerEmail
: l'indirizzo email del pagatore. Deve essere una stringa non vuota quandopaymentOptions.requestPayerEmail
è true.shippingAddress
: l'indirizzo di spedizione fornito dall'utente. Deve essere un bundle non vuoto quandopaymentOptions.requestShipping
è true. Il bundle deve avere le seguenti chiavi che rappresentano parti diverse in un indirizzo fisico.city
countryCode
dependentLocality
organization
phone
postalCode
recipient
region
sortingCode
addressLine
Tutte le chiavi diverse daaddressLine
hanno valori stringa.addressLine
è un array di stringhe.
shippingOptionId
: l'identificatore dell'opzione di spedizione selezionata dall'utente. Deve essere una stringa non vuota quandopaymentOptions.requestShipping
è true.
Convalida la risposta al pagamento
Se il risultato dell'attività di una risposta al pagamento ricevuta dall'app di pagamento richiamata è impostato su RESULT_OK
, Chrome verificherà la presenza di informazioni aggiuntive richieste nelle sue funzionalità extra. Se la convalida non va a buon fine, Chrome restituisce una
promessa rifiutata da request.show()
con uno dei seguenti messaggi di errore
rivolti agli sviluppatori:
'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".'
Il seguente esempio di codice è un esempio di risposta valida:
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")
}
}
(Facoltativo) Supporto del flusso dinamico
A volte il costo totale di una transazione aumenta, ad esempio quando l'utente sceglie l'opzione di spedizione espressa o quando l'elenco delle opzioni di spedizione disponibili o i relativi prezzi cambiano quando l'utente sceglie un indirizzo di spedizione internazionale. Quando la tua app fornisce l'indirizzo o l'opzione di spedizione selezionati dall'utente, dovrebbe essere in grado di comunicare al commerciante eventuali modifiche dell'indirizzo di spedizione o dell'opzione e mostrare all'utente i dettagli di pagamento aggiornati (forniti dal commerciante).
AIDL
Per informare il commerciante delle nuove modifiche, utilizza il servizio PaymentDetailsUpdateService
dichiarato nel file AndroidManifest.xml di Chrome. Per utilizzare questo servizio, crea due file AIDL con il contenuto seguente:
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);
}
Comunicare al commerciante modifiche al metodo di pagamento, all'indirizzo di spedizione o all'opzione di spedizione selezionati dall'utente
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
}
}
}
Il valore callingPackageName
utilizzato per l'intent iniziale del servizio può avere uno dei seguenti valori, a seconda del browser che ha avviato la richiesta di pagamento.
Canale di Chrome | Nome pacchetto |
---|---|
Stabile |
"com.android.chrome"
|
Beta |
"com.chrome.beta"
|
Sviluppatore |
"com.chrome.dev"
|
Canary |
"com.chrome.canary"
|
Chromium |
"org.chromium.chrome"
|
Casella di ricerca rapida Google (un incorporatore Weblayer) |
"com.google.android.googlequicksearchbox"
|
changePaymentMethod
Informa il commerciante in merito alle modifiche apportate al metodo di pagamento selezionato dall'utente. Il bundle paymentHandlerMethodData
contiene chiavi methodName
e details
facoltative, entrambe con valori stringa. Chrome cercherà un bundle non vuoto con methodName
non vuoto e invierà un updatePaymentDetails
con uno dei seguenti messaggi di errore tramite callback.updateWith
se la convalida non va a buon fine.
'Method data required.'
'Method name required.'
changeShippingOption
Informa il commerciante in merito alle modifiche apportate all'opzione di spedizione selezionata dall'utente.
shippingOptionId
deve essere l'identificatore di una delle opzioni di spedizione specificate dal commerciante. Se la convalida non va a buon fine, Chrome verifica la presenza di un valore shippingOptionId
non vuoto e invia
un updatePaymentDetails
con il seguente messaggio di errore tramite
callback.updateWith
.
'Shipping option identifier required.'
changeShippingAddress
Informa il commerciante in merito alle modifiche all'indirizzo di spedizione fornito dall'utente. Chrome
verifica la presenza di un bundle shippingAddress
non vuoto con un countryCode
valido
e invia un updatePaymentDetails
con il seguente messaggio di errore tramite
callback.updateWith
se la convalida non va a buon fine.
'Payment app returned invalid shipping address in response.'
Messaggio di errore relativo allo stato non valido
Se Chrome rileva uno stato non valido alla ricezione di una qualsiasi delle richieste di modifica,
chiama callback.updateWith
con un bundle updatePaymentDetails
oscurato. Il bundle conterrà solo la chiave error
con "Invalid state"
.
Esempi di stato non valido:
- Quando Chrome è ancora in attesa di una risposta del commerciante a una modifica precedente (ad esempio un evento di modifica in corso).
- L'identificatore dell'opzione di spedizione fornita dall'app di pagamento non appartiene ad alcuna opzione di spedizione specificata dal commerciante.
Ricevere i dati di pagamento aggiornati dal commerciante
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
è il bundle equivalente al dizionario
PaymentRequestDetailsUpdate
WebIDL (dopo aver oscurato il campo
modifiers
) e contiene le seguenti chiavi facoltative:
total
: un bundle contenente chiavicurrency
evalue
; entrambe le chiavi hanno valori di stringashippingOptions
: l'array assegnabile di opzioni di spedizioneerror
: una stringa contenente un messaggio di errore generico (ad es. quandochangeShippingOption
non fornisce un identificatore di opzione di spedizione valido)stringifiedPaymentMethodErrors
: una stringa JSON che rappresenta gli errori di convalida per il metodo di pagamentoaddressErrors
: un bundle con chiavi facoltative identiche a indirizzo di spedizione e valori stringa. Ogni chiave rappresenta un errore di convalida relativo alla parte corrispondente dell'indirizzo di spedizione.
Una chiave assente indica che il suo valore non è cambiato.