Come aggiornare l'app di pagamento per Android per fornire l'indirizzo di spedizione e i dati di contatto del pagatore con le API Web Payments.
Pubblicato: 17 luglio 2020, ultimo aggiornamento: 27 maggio 2025
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.
Per questo motivo, l'API Payment Request supporta una funzionalità per richiedere l'indirizzo di spedizione e i dati di contatto. Questo approccio offre diversi vantaggi:
- Gli utenti possono scegliere l'indirizzo giusto con pochi tocchi.
- L'indirizzo viene sempre restituito nel formato standardizzato.
- È meno probabile che venga inviato 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.
Ove possibile, Chrome delega la raccolta dell'indirizzo di spedizione e dei dati di contatto di un cliente all'app di pagamento Android invocata. La delega riduce le difficoltà durante il pagamento.
Il sito web del commerciante può aggiornare dinamicamente le opzioni di spedizione e il prezzo totale in base alla scelta del cliente dell'indirizzo di spedizione e dell'opzione di spedizione.
Per aggiungere il supporto della delega a un'app di pagamento per Android esistente: implementa i seguenti passaggi:
- Dichiara le deleghe supportate.
- Esegui l'analisi degli extra dell'intent
PAY
per le opzioni di pagamento obbligatorie. - Fornisci le informazioni richieste nella risposta al pagamento.
- [Facoltativo] Supporta il flusso dinamico:
- Avvisa il commerciante delle modifiche al metodo di pagamento, all'indirizzo di spedizione o all'opzione di spedizione selezionati dall'utente.
- Ricevere i dettagli di pagamento aggiornati dal commerciante (ad esempio, l'importo totale adeguato in base al costo dell'opzione di spedizione selezionata).
Dichiara le deleghe supportate
Il browser deve conoscere l'elenco delle informazioni aggiuntive che la tua app di pagamento può fornire per poter delegare la raccolta di queste informazioni alla tua app. Dichiara le deleghe supportate come <meta-data>
in AndroidManifest.xml della tua app.
<activity
android:name=".PaymentActivity"
…
<meta-data
android:name="org.chromium.payment_supported_delegations"
android:resource="@array/chromium_payment_supported_delegations" />
</activity>
android:resource
deve puntare a un <string-array>
contenente tutti o un sottoinsieme dei seguenti valori:
payerName
payerEmail
payerPhone
shippingAddress
L'esempio seguente può fornire solo un indirizzo di spedizione e l'indirizzo email del pagatore.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="chromium_payment_supported_delegations">
<item>payerEmail</item>
<item>shippingAddress</item>
</string-array>
</resources>
Analizza gli extra dell'intento PAY
per le opzioni di pagamento richieste
Il commerciante può specificare ulteriori informazioni richieste utilizzando il
dizionario paymentOptions
. Chrome fornirà l'elenco delle opzioni richieste che la tua app può fornire passando paymentOptions
Extra intent
all'attività PAY
.
paymentOptions
paymentOptions
è il sottoinsieme di opzioni di pagamento specificate dal commerciante per le quali la tua app ha dichiarato il supporto della delega.
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");
}
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 il telefono del pagatore è obbligatorio o meno.requestPayerEmail
: il valore booleano che indica se l'indirizzo email di chi paga è obbligatorio o meno.requestShipping
: il valore booleano che indica se le informazioni di spedizione sono obbligatorie o meno.shippingType
: la stringa che mostra il tipo di spedizione. Il tipo di spedizione può essere"shipping"
,"delivery"
o"pickup"
. L'app può utilizzare questo suggerimento nella sua UI quando chiede all'utente l'indirizzo o la scelta delle opzioni di spedizione.
shippingOptions
shippingOptions
è l'array di opzioni di spedizione specificate dal commerciante che può essere suddiviso in pacchetti. Questo parametro esisterà solo 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;
}
}
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 bundle del costo di spedizione contenente le chiavicurrency
evalue
con valori di stringa.currency
mostra la valuta del costo di spedizione come codice alfabetico di 3 lettere ben formato ISO4217value
mostra il valore del costo di spedizione come valore monetario decimale valido
selected
: indica se l'opzione di spedizione deve essere selezionata o meno quando l'app di pagamento mostra le opzioni di spedizione.
Tutte le chiavi diverse da selected
hanno valori di stringa. selected
ha un valore 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);
Fornire le informazioni richieste in una risposta al pagamento
L'app deve includere le informazioni aggiuntive richieste nella risposta all'attività PAY
.
A tale scopo, i seguenti parametri devono essere specificati come extra di Intent:
payerName
: il nome completo del pagatore. Deve essere una stringa non vuota quandopaymentOptions.requestPayerName
è true.payerPhone
: il numero di telefono del pagatore. 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 di un indirizzo fisico.countryCode
postalCode
sortingCode
region
city
dependentLocality
addressLine
organization
recipient
phone
Tutte le chiavi diverse daaddressLine
hanno valori di 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 di pagamento ricevuta dall'app di pagamento invocata è impostato su RESULT_OK
, Chrome controllerà se sono presenti informazioni aggiuntive obbligatorie nei suoi extra. Se la convalida non va a buon fine, Chrome restituirà 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 codice di esempio è un esempio di risposta valida:
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;
}
(Facoltativo) Supporta il 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 cambia 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 notificare al commerciante eventuali modifiche all'indirizzo o all'opzione di spedizione e mostrare all'utente i dati di pagamento aggiornati (forniti dal commerciante).
Per notificare al commerciante le nuove modifiche, implementa l'interfaccia IPaymentDetailsUpdateServiceCallback
e dichiarala nel tuo AndroidManifest.xml
con il filtro intent UPDATE_PAYMENT_DETAILS
.
Immediatamente dopo aver invocato l'intent PAY
, Chrome si connette al servizio UPDATE_PAYMENT_DETAILS
(se esistente) nello stesso pacchetto dell'intent PAY
e chiama setPaymentDetailsUpdateService(service)
per fornire all'app di pagamento l'endpoint IPaymentDetailsUpdateService
per notificare le modifiche al metodo di pagamento, all'opzione di spedizione o all'indirizzo di spedizione dell'utente.
Utilizza packageManager.getPackagesForUid(Binder.getCallingUid())
quando ricevi la comunicazione interprocessuale (IPC) per convalidare che l'app che ha invocato l'intent PAY
abbia lo stesso nome di pacchetto dell'app che ha invocato i metodi IPaymentDetailsUpdateServiceCallback
.
AIDL
Crea due file AIDL con i seguenti contenuti:
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);
}
Servizio
Implementa il servizio 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
Esponi il servizio per IPaymentDetailsUpdateServiceCallback
in
AndroidManifest.xml
.
<service
android:name=".SampleUpdatePaymentDetailsCallbackService"
android:exported="true">
<intent-filter>
<action android:name="org.chromium.intent.action.UPDATE_PAYMENT_DETAILS" />
</intent-filter>
</service>
Comunicare al commerciante le modifiche al metodo di pagamento, all'indirizzo di spedizione o all'opzione di spedizione selezionati dall'utente
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
Invia una notifica al commerciante in caso di modifiche al metodo di pagamento selezionato dall'utente. Il
bundle paymentHandlerMethodData
contiene le chiavi methodName
e details
facoltative, entrambe con valori di stringa. Se la convalida non va a buon fine, Chrome cercherà un bundle non vuoto con un methodName
non vuoto e invierà un updatePaymentDetails
con uno dei seguenti messaggi di errore tramite callback.updateWith
.
'Method data required.'
'Method name required.'
changeShippingOption
Invia una notifica al commerciante in caso di modifiche 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 controllerà la presenza di un shippingOptionId
non vuoto e invierà un updatePaymentDetails
con il seguente messaggio di errore tramite callback.updateWith
.
'Shipping option identifier required.'
changeShippingAddress
Invia una notifica al commerciante in caso di modifiche all'indirizzo di spedizione fornito dall'utente. Chrome verificherà la presenza di un bundle shippingAddress
non vuoto con un countryCode
valido e invierà 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 Stato non valido
Se Chrome rileva uno stato non valido alla ricezione di una delle richieste di modifica, chiamerà callback.updateWith
con un bundle updatePaymentDetails
oscurato. Il bundle conterrà solo la chiave error
con "Invalid state"
.
Ecco alcuni esempi di stato non valido:
- Quando Chrome è ancora in attesa della risposta del commerciante a una modifica precedente (ad esempio un evento di modifica in corso).
- L'identificatore dell'opzione di spedizione fornito dall'app di pagamento non appartiene a nessuna delle opzioni di spedizione specificate dal commerciante.
Ricevere i dettagli di pagamento aggiornati dal commerciante
Kotlin
override fun updateWith(updatedPaymentDetails: Bundle) {}
override fun paymentDetailsNotUpdated() {}
Java
@Override
public void updateWith(Bundle updatedPaymentDetails) {}
@Override
public void paymentDetailsNotUpdated() {}
updatedPaymentDetails
è il bundle equivalente al
PaymentRequestDetailsUpdate
WebIDL e contiene le seguenti
chiavi facoltative:
total
: un bundle contenente le chiavicurrency
evalue
, entrambe con valori di stringashippingOptions
: l'array di opzioni di spedizione parcelableerror
: 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 shipping address e valori stringa. Ogni chiave rappresenta un errore di convalida relativo alla parte corrispondente dell'indirizzo di spedizione.modifiers
: un array di Bundle separabili, ciascuno con un campototal
e un campomethodData
, che sono anch'essi Bundle.
Una chiave assente indica che il relativo valore non è cambiato.