Dostarczanie informacji o dostawie i danych kontaktowych z aplikacji płatniczej na Androida

Jak zaktualizować aplikację do płatności na Androida, aby udostępnić adres dostawy i informacje kontaktowe płatnika za pomocą interfejsów Web Payments API.

Sahel Sharify
Sahel Sharify

Data publikacji: 17 lipca 2020 r., ostatnia aktualizacja: 27 maja 2025 r.

Wpisywanie adresu dostawy i informacji kontaktowych w formularzu internetowym może być uciążliwe dla klientów. Może to powodować błędy i obniżać współczynnik konwersji.

Dlatego interfejs API żądania płatności obsługuje funkcję umożliwiającą prośbę o adres dostawy i informacje kontaktowe. Daje to kilka korzyści:

  • Użytkownicy mogą wybrać odpowiedni adres, wykonując kilka kliknięć.
  • Adres jest zawsze zwracany w standardowym formacie.
  • Wpisanie nieprawidłowego adresu jest mniej prawdopodobne.

Aby zapewnić spójne płatności, przeglądarki mogą odroczyć zbieranie adresu dostawy i informacji kontaktowych do aplikacji płatniczej. Ta funkcja nazywa się delegacja.

W miarę możliwości Chrome deleguje zbieranie adresu dostawy i informacji kontaktowych klienta do wywołanej aplikacji do płatności na Androida. Delegowanie to zmniejsza trudności podczas płatności.

Strona sprzedawcy może dynamicznie aktualizować opcje dostawy i łączną cenę w zależności od wybranego przez klienta adresu dostawy i opcji dostawy.

Zmiana opcji dostawy i adresu dostawy. Zobacz, jak wpływa ona dynamicznie na opcje dostawy i cenę całkowitą.

Aby dodać obsługę delegowania do istniejącej aplikacji do płatności na Androida:

  1. Deklaruj obsługiwane delegacje.
  2. Przeanalizuj PAY dodatkowe informacje o intencji, aby sprawdzić wymagane opcje płatności.
  3. Podaj wymagane informacje w odpowiedzi na prośbę o płatność.
  4. [Opcjonalnie] Obsługa dynamicznego przepływu:
    1. Poinformuj sprzedawcę o zmianach w wybranej przez użytkownika formie płatności, adresie dostawy lub opcji dostawy.
    2. Otrzymaj od sprzedawcy zaktualizowane informacje o płatności (np. skorygowaną łączną kwotę na podstawie kosztu wybranej opcji dostawy).

Zadeklaruj obsługiwane delegowania

Przeglądarka musi znać listę dodatkowych informacji, które może udostępnić Twoja aplikacja do płatności, aby mogła zlecić jej zbieranie. Zadeklaruj obsługiwane delegowanie jako <meta-data> w pliku AndroidManifest.xml aplikacji.

<activity
  android:name=".PaymentActivity"
    <meta-data
    android:name="org.chromium.payment_supported_delegations"
    android:resource="@array/chromium_payment_supported_delegations" />
</activity>

Wartość android:resource musi wskazywać na element <string-array> zawierający wszystkie lub podzbiór tych wartości:

  • payerName
  • payerEmail
  • payerPhone
  • shippingAddress

W tym przykładzie można podać tylko adres dostawy i adres e-mail płatnika.

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string-array name="chromium_payment_supported_delegations">
    <item>payerEmail</item>
    <item>shippingAddress</item>
  </string-array>
</resources>

Parsowanie PAY dodatkowych informacji o zamierzeniu w przypadku wymaganych opcji płatności

Sprzedawca może podać dodatkowe wymagane informacje za pomocą słownika paymentOptions. Chrome przekaże listę wymaganych opcji, które aplikacja może podać, przekazując paymentOptions dodatkowe informacje o intencji do aktywności PAY.

paymentOptions

paymentOptions to podzbiór opcji płatności określonych przez sprzedawcę, dla których Twoja aplikacja zadeklarowała obsługę delegowania.

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");
}

Może on zawierać te parametry:

  • requestPayerName – wartość logiczna wskazująca, czy imię i nazwisko płatnika jest wymagane.
  • requestPayerPhone – wartość logiczna określająca, czy telefon płatnika jest wymagany.
  • requestPayerEmail – wartość logiczna wskazująca, czy adres e-mail płatnika jest wymagany.
  • requestShipping – wartość logiczna wskazująca, czy informacje o dostawie są wymagane.
  • shippingType – ciąg tekstowy określający typ dostawy. Typ dostawy może być określony jako "shipping", "delivery" lub "pickup". Aplikacja może używać tego skrótu w interfejsie użytkownika, gdy prosi o adres lub opcje dostawy.

shippingOptions

shippingOptions to tablica z opcjami dostawy określonymi przez sprzedawcę. Ten parametr będzie istniał tylko wtedy, gdy 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;
  }
}

Każda opcja dostawy to Bundle z tymi kluczami.

  • id – identyfikator opcji dostawy.
  • label – etykieta opcji dostawy wyświetlana użytkownikowi.
  • amount – pakiet kosztów dostawy zawierający klucze currency i value z wartościami ciągu znaków.
  • selected – określa, czy opcja dostawy ma być wybrana, gdy aplikacja do płatności wyświetla opcje dostawy.

Wszystkie klucze inne niż selected mają wartości ciągu znaków. selected ma wartość logiczną.

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);

Podawanie wymaganych informacji w odpowiedzi na zgłoszenie dotyczące płatności

Aplikacja powinna zawierać wymagane dodatkowe informacje w odpowiedzi na aktywność PAY.

Aby to zrobić, jako dodatkowe parametry intencji należy podać te parametry:

  • payerName – imię i nazwisko płatnika. Jeśli parametr paymentOptions.requestPayerName ma wartość prawda, ciąg znaków powinien być niepusty.
  • payerPhone – numer telefonu płatnika. Jeśli parametr paymentOptions.requestPayerPhone ma wartość prawda, ciąg znaków powinien być niepusty.
  • payerEmail – adres e-mail płatnika. Ten ciąg znaków nie może być pusty, gdy paymentOptions.requestPayerEmail ma wartość true.
  • shippingAddress – podany przez użytkownika adres dostawy. Jeśli parametr paymentOptions.requestShipping ma wartość prawda, pakiet powinien być niepusty. Pakiet powinien zawierać te klucze, które reprezentują różne części adresu fizycznego.
    • countryCode
    • postalCode
    • sortingCode
    • region
    • city
    • dependentLocality
    • addressLine
    • organization
    • recipient
    • phoneWszystkie klucze inne niż addressLine mają wartości ciągu znaków. Argument addressLine jest tablicą ciągów znaków.
  • shippingOptionId – identyfikator wybranej przez użytkownika opcji dostawy. Jeśli parametr paymentOptions.requestShipping ma wartość prawda, ten ciąg znaków nie może być pusty.

Weryfikowanie odpowiedzi na płatność

Jeśli wynik aktywności odpowiedzi na płatność otrzymanej z wywołanej aplikacji do płatności ma wartość RESULT_OK, Chrome sprawdzi, czy w sekcji dodatków znajdują się wymagane dodatkowe informacje. Jeśli weryfikacja się nie powiedzie, Chrome zwróci odrzucone obiecanie z request.show() z jednym z tych komunikatów o błędzie dla deweloperów:

'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".'

Poniższy przykładowy kod przedstawia prawidłową odpowiedź:

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;
}

Opcjonalnie: obsługa przepływu dynamicznego

Czasami całkowity koszt transakcji wzrasta, na przykład gdy użytkownik wybierze opcję dostawy ekspresowej lub gdy lista dostępnych opcji dostawy lub ich ceny zmieni się po wybraniu przez użytkownika międzynarodowego adresu dostawy. Gdy Twoja aplikacja udostępnia wybrany przez użytkownika adres dostawy lub opcję dostawy, powinna być w stanie powiadomić sprzedawcę o zmianach adresu dostawy lub opcji dostawy i pokazać użytkownikowi zaktualizowane szczegóły płatności (udostępnione przez sprzedawcę).

Aby powiadomić sprzedawcę o nowych zmianach, wprowadź interfejs IPaymentDetailsUpdateServiceCallback i opublikuj go w swoim pliku AndroidManifest.xml za pomocą filtra intencji UPDATE_PAYMENT_DETAILS.

Bezpośrednio po wywołaniu intencji PAY Chrome połączy się z usługą UPDATE_PAYMENT_DETAILS (jeśli istnieje) w tym samym pakiecie co intencja PAY i wywoła usługę setPaymentDetailsUpdateService(service), aby przekazać Twojej aplikacji do płatności punkt końcowy IPaymentDetailsUpdateService, który powiadomi o zmianach w formie płatności, opcji dostawy lub adresie dostawy użytkownika.

Podczas odbierania komunikacji między procesami (IPC) używaj wartości packageManager.getPackagesForUid(Binder.getCallingUid()), aby sprawdzić, czy aplikacja, która wywołała intencję PAY, ma tę samą nazwę pakietu co aplikacja, która wywołała metody IPaymentDetailsUpdateServiceCallback.

AIDL

Utwórz 2 pliki AIDL z tą treścią:

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);
}

Usługa

Zaimplementuj usługę 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

Udostępnij usługę IPaymentDetailsUpdateServiceCallback w AndroidManifest.xml.

<service
    android:name=".SampleUpdatePaymentDetailsCallbackService"
    android:exported="true">
    <intent-filter>
        <action android:name="org.chromium.intent.action.UPDATE_PAYMENT_DETAILS" />
    </intent-filter>
</service>

powiadamianie sprzedawcy o zmianach w wybranej przez użytkownika formie płatności, adresie dostawy lub opcji dostawy;

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

Informuje sprzedawcę o zmianach w wybranej przez użytkownika formie płatności. Pakiet paymentHandlerMethodData zawiera klucze methodName i opcjonalnie details, oba z wartościami tekstowymi. Chrome sprawdzi, czy nie ma pustego pakietu z niepustym methodName i wyśle updatePaymentDetails z jednym z tych komunikatów o błędzie przez callback.updateWith, jeśli weryfikacja się nie powiedzie.

'Method data required.'
'Method name required.'

changeShippingOption

powiadamia sprzedawcę o zmianach w wybranej przez użytkownika opcji dostawy. Wartość shippingOptionId powinna być identyfikatorem jednej z opcji dostawy określonych przez sprzedawcę. Jeśli weryfikacja się nie powiedzie, Chrome sprawdzi, czy shippingOptionId nie jest pusty, i wyśle updatePaymentDetails z tym komunikatem o błędzie przez callback.updateWith.

'Shipping option identifier required.'

changeShippingAddress

powiadamia sprzedawcę o zmianach adresu dostawy podanego przez użytkownika; Chrome sprawdzi, czy istnieje niepusty pakiet shippingAddress z prawidłowym elementem countryCode, i wyśle updatePaymentDetails z tym komunikatem o błędzie przez callback.updateWith, jeśli weryfikacja się nie powiedzie.

'Payment app returned invalid shipping address in response.'

Komunikat o błędzie „Nieprawidłowy stan”

Jeśli po otrzymaniu żądania zmiany Chrome napotka nieprawidłowy stan, wywoła funkcję callback.updateWith z zawartym w niej zbiorem updatePaymentDetails. Pakiet będzie zawierać tylko klucz error z wartością "Invalid state". Przykłady nieprawidłowego stanu:

  • Gdy Chrome nadal oczekuje na odpowiedź sprzedawcy na poprzednią zmianę (np. trwające zdarzenie zmiany).
  • Identyfikator opcji dostawy dostarczony przez aplikację do płatności nie należy do żadnej z opcji dostawy określonych przez sprzedawcę.

Odbieranie zaktualizowanych danych płatności od sprzedawcy

Kotlin

override fun updateWith(updatedPaymentDetails: Bundle) {}

override fun paymentDetailsNotUpdated() {}

Java

@Override
public void updateWith(Bundle updatedPaymentDetails) {}

@Override
public void paymentDetailsNotUpdated() {}

updatedPaymentDetails to pakiet odpowiadający słownikowi PaymentRequestDetailsUpdate WebIDL i zawiera te klucze opcjonalne:

  • total – pakiet zawierający klucze currencyvalue, oba z wartościami ciągu znaków.
  • shippingOptions – tablica opcji dostawy, które można zapakować
  • error – ciąg znaków zawierający ogólny komunikat o błędzie (np.gdy changeShippingOption nie podaje prawidłowego identyfikatora opcji dostawy).
  • stringifiedPaymentMethodErrors – ciąg JSON reprezentujący błędy walidacji formy płatności.
  • addressErrors – pakiet z opcjonalnymi kluczami identycznymi z adresem dostawy i wartościami ciągu znaków. Każdy klucz reprezentuje błąd walidacji związany z odpowiednią częścią adresu dostawy.
  • modifiers – tablica pakietów, z których każdy ma pole totalmethodData, które są też pakietami.

Brak klucza oznacza, że jego wartość się nie zmieniła.