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

Podawanie adresu dostawy i danych kontaktowych w formularzu internetowym może być uciążliwe dla klientów. Może powodować błędy i niższy 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 wiele korzyści:

  • Aby wybrać właściwy adres, wystarczy 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 przekazuje adres dostawy i informacje kontaktowe klienta do wywoływanej aplikacji płatniczej na Androida. Przekazywanie dostępu ułatwia proces 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 w działaniu. 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. Powiadom 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).

Deklarowanie obsługiwanych przekazywania dostępu

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/supported_delegations" />
</activity>

<resource> musi być listą ciągów znaków wybranych spośród tych prawidłowych 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="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 może zapewnić Twoja aplikacja, przekazując poniższe parametry do aktywności PAY jako extras.

paymentOptions

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

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

Może zawierać takie parametry:

  • requestPayerName – wartość logiczna wskazująca, czy imię i nazwisko płatnika jest wymagane.
  • requestPayerPhone – wartość logiczna wskazująca, czy wymagany jest telefon płatnika.
  • 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 podpowiedzi w interfejsie użytkownika, gdy prosi o adres użytkownika lub wybór opcji dostawy.

shippingOptions

shippingOptions to tablica z opcjami dostawy określonymi przez sprzedawcę. Ten parametr będzie istniał tylko wtedy, gdy paymentOptions.requestShipping == true.

val shippingOptions: List<ShippingOption>? =
    extras.getParcelableArray("shippingOptions")?.mapNotNull {
        p -> from(p as Bundle)
    }

Każda opcja dostawy to Bundle z tymi kluczami.

  • id – identyfikator opcji dostawy.
  • label – etykieta opcji wysyłki widoczna dla użytkownika.
  • amount – pakiet kosztów dostawy zawierający klucze currency i value z wartościami typu ciąg 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ą.

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)

Podawanie wymaganych informacji w odpowiedzi na płatność

W odpowiedzi na aktywność w usłudze PAY Twoja aplikacja powinna podać wymagane informacje dodatkowe.

W tym celu należy podać te parametry jako dodatkowe parametry intencji:

  • 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 mieć poniższe klucze reprezentujące różne części w adresie fizycznym.
    • city
    • countryCode
    • dependentLocality
    • organization
    • phone
    • postalCode
    • recipient
    • region
    • sortingCode
    • addressLineWszystkie 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 działania w odpowiedzi na płatność otrzymaną z wywołanej aplikacji płatniczej ma wartość RESULT_OK, Chrome sprawdza, czy dodatki zawierają 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ższa próbka kodu to przykład prawidłowej odpowiedzi:

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

Opcjonalnie: obsługa przepływu dynamicznego

Czasami całkowity koszt transakcji wzrasta, np. gdy użytkownik wybierze opcję dostawy ekspresowej albo gdy użytkownik wybierze międzynarodowy adres dostawy lub lista dostępnych opcji wysyłki albo ich ceny. Gdy Twoja aplikacja udostępnia adres dostawy lub opcję wybrane przez użytkownika, powinna być w stanie powiadomić sprzedawcę o zmianach adresu dostawy lub opcji oraz wyświetlić użytkownikowi zaktualizowane szczegóły płatności (udostępnione przez sprzedawcę).

AIDL

Aby powiadomić sprzedawcę o nowych zmianach, użyj usługi PaymentDetailsUpdateService zadeklarowanej w pliku AndroidManifest.xml w Chrome. Aby korzystać z tej usługi, utwórz 2 pliki AIDL z takimi treściami:

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

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

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

Wartość callingPackageName używana do określania intencji uruchomienia usługi może być jedną z tych wartości w zależności od przeglądarki, która zainicjowała żądanie płatności.

Kanały Chrome Nazwa pakietu
Stabilny "com.android.chrome"
Beta "com.chrome.beta"
Deweloperzy "com.chrome.dev"
Canary "com.chrome.canary"
Chromium "org.chromium.chrome"
Okno szybkiego wyszukiwania Google (osadzający komponent WebLayer) "com.google.android.googlequicksearchbox"

changePaymentMethod

Powiadamia sprzedawcę o zmianach w formie płatności wybranej przez użytkownika. Pakiet paymentHandlerMethodData zawiera klucze methodName i opcjonalnie details, oba z wartościami tekstowymi. Jeśli weryfikacja się nie powiedzie, 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.

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

changeShippingOption

powiadamia sprzedawcę o zmianach w wybranej przez użytkownika opcji dostawy. shippingOptionId powinien 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 nie ma niepustego pakietu shippingAddress z prawidłowym parametrem countryCode, i w przypadku niepowodzenia weryfikacji wyśle updatePaymentDetails z poniższym komunikatem o błędzie za pomocą callback.updateWith.

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

Jak otrzymać zaktualizowane dane do płatności od sprzedawcy

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 to pakiet odpowiadający słownikowi PaymentRequestDetailsUpdateWebIDL (po usunięciu pola modifiers) i zawiera te klucze opcjonalne:

  • total – pakiet zawierający klucze currency i value, oba klucze mają wartości ciągu znaków
  • shippingOptions – tablica opcji dostawy do pakowania.
  • 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 tekstowego. Każdy klucz reprezentuje błąd weryfikacji związany z odpowiadającej mu części adresu dostawy.

Brak klucza oznacza, że jego wartość nie uległa zmianie.