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

Jak zaktualizować aplikację do płatności na Androida, aby podać adres dostawy i dane kontaktowe płatnika za pomocą interfejsów API płatności internetowych.

Sahel
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 obniżać współczynnik konwersji.

Dlatego interfejs Payment Request API obsługuje funkcję żądania adresu dostawy i informacji kontaktowych. Dzięki temu:

  • Użytkownicy mogą wybrać właściwy adres zaledwie kilkoma kliknięciami.
  • Adres jest zawsze zwracany w formacie standardowym.
  • Podanie nieprawidłowego adresu jest mniej prawdopodobne.

Przeglądarki mogą opóźnić zbieranie adresu dostawy i danych kontaktowych przez aplikację płatniczą, aby zapewnić ujednolicone proces płatności. Jest to tzw. przekazywanie dostępu.

O ile jest to możliwe, Chrome przekazuje dane kontaktowe i adres dostawy klienta do wywołanej aplikacji płatniczej na Androida. Przekazywanie dostępu upraszcza proces płatności.

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

Trwa zmiana opcji i adresu dostawy. Zobacz, jak to ustawienie wpływa dynamicznie na opcje dostawy i łączną cenę.

Aby dodać obsługę przekazywania dostępu do aplikacji do płatności na Androida, która już istnieje, wykonaj te czynności:

  1. Deklaruj obsługiwane przekazywanie dostępu.
  2. Przeanalizuj dodatkowe intencje (PAY) dla wymaganych opcji płatności.
  3. Podaj wymagane informacje w odpowiedzi na 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. Otrzymywać od sprzedawcy zaktualizowane dane do płatności (na przykład skorygowaną łączną kwotę na podstawie kosztu wybranej opcji dostawy).

Deklarowanie obsługiwanych przedstawicieli

Przeglądarka musi znać listę dodatkowych informacji, które może udostępnić aplikacja płatnicza, aby mogła przekazać zbieranie tych informacji do aplikacji. Obsługiwane uprawnienia dostępu muszą być zadeklarowane 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 wybranych spośród tych prawidłowych wartości:

[ "payerName", "payerEmail", "payerPhone", "shippingAddress" ]

Poniższy przykład może zawierać 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>

Przeanalizuj dodatki intencji PAY pod kątem wymaganych opcji płatności

Dodatkowe wymagane informacje sprzedawca może podać w słowniku paymentOptions. Chrome przedstawi listę wymaganych opcji, które może udostępnić Twoja aplikacja, przekazując te parametry do aktywności PAY jako rozszerzenia intencji.

paymentOptions

paymentOptions to podzbiór opcji płatności określonych przez sprzedawcę, w przypadku których Twoja aplikacja zadeklarowała pomoc w przekazywaniu dostępu.

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ć te parametry:

  • requestPayerName – wartość logiczna wskazująca, czy nazwa płatnika jest wymagana.
  • requestPayerPhone – wartość logiczna wskazująca, czy wymagany jest numer telefonu płatnika.
  • requestPayerEmail – wartość logiczna wskazująca, czy wymagany jest adres e-mail płatnika.
  • requestShipping – wartość logiczna wskazująca, czy informacje o dostawie są wymagane.
  • shippingType – ciąg tekstowy przedstawiający typ dostawy. Typ dostawy to "shipping", "delivery" lub "pickup". Aplikacja może użyć tej wskazówki w swoim interfejsie, gdy prosi o podanie adresu użytkownika lub wyboru opcji dostawy.

shippingOptions

shippingOptions to tablica opcji dostawy określonych przez sprzedawcę z możliwością paczki. Ten parametr będzie występować 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 poniższymi kluczami.

  • id – identyfikator opcji dostawy.
  • label – etykieta opcji wysyłki wyświetlana użytkownikowi.
  • amount – pakiet kosztów dostawy zawierający klucze currency i value z wartościami ciągów.
  • selected – określa, czy opcję dostawy należy wybrać, gdy aplikacja płatnicza wyświetla opcje dostawy.

Wszystkie klucze oprócz selected zawierają wartości w postaci ciągów 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ść

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

Aby było to możliwe, następujące parametry muszą być określone jako dodatki do intencji:

  • payerName – pełna nazwa płatnika. Jeśli paymentOptions.requestPayerName ma wartość prawda, to pole nie może być puste.
  • payerPhone – numer telefonu płatnika. Jeśli paymentOptions.requestPayerPhone ma wartość prawda, to pole nie może być puste.
  • payerEmail – adres e-mail płatnika. Jeśli paymentOptions.requestPayerEmail ma wartość prawda, ciąg znaków nie może być pusty.
  • shippingAddress – adres dostawy podany przez użytkownika. Gdy paymentOptions.requestShipping ma wartość prawda, pakiet nie powinien być pusty. Pakiet powinien mieć następujące klucze reprezentujące różne części adresu fizycznego.
    • city
    • countryCode
    • dependentLocality
    • organization
    • phone
    • postalCode
    • recipient
    • region
    • sortingCode
    • addressLineWszystkie klucze oprócz addressLine zawierają wartości w postaci ciągów znaków. addressLine to tablica ciągów tekstowych.
  • shippingOptionId – identyfikator opcji dostawy wybranej przez użytkownika. Jeśli paymentOptions.requestShipping ma wartość prawda, to pole nie może być puste.

Zweryfikuj odpowiedź dotyczącą płatności

Jeśli wynik aktywności odpowiedzi na płatność otrzymaną z wywołanej aplikacji płatniczej jest ustawiony na RESULT_OK, Chrome sprawdzi w dodatkach wymagane dodatkowe informacje. Jeśli weryfikacja się nie powiedzie, Chrome zwróci od request.show() komunikat o odrzuceniu z jednym z tych komunikatów o błędzie:

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

Oto przykładowy kod 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 rośnie, np. gdy użytkownik wybiera opcję ekspresowej dostawy lub gdy lista dostępnych opcji dostawy bądź ich ceny zmieniają się, gdy użytkownik wybiera międzynarodowy adres dostawy. Gdy aplikacja udostępnia wybrany przez użytkownika adres dostawy lub opcję, powinna być w stanie powiadamiać sprzedawcę o wszelkich zmianach adresu dostawy lub opcji i wyświetlać użytkownikowi zaktualizowane dane do płatności (podane 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 dwa pliki AI o tej zawartości:

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

Powiadom sprzedawcę 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
        }
    }
}

Pole callingPackageName używane w intencji uruchomienia usługi może mieć jedną z tych wartości w zależności od przeglądarki, która zainicjowała żądanie płatności.

Kanał Chrome Nazwa pakietu
Stabilny "com.android.chrome"
Beta "com.chrome.beta"
Dla programistów "com.chrome.dev"
Wyspy Kanaryjskie "com.chrome.canary"
Chromium "org.chromium.chrome"
Okno szybkiego wyszukiwania Google (umieszczony element WebLayer) "com.google.android.googlequicksearchbox"

changePaymentMethod

Powiadamia sprzedawcę o zmianach w wybranej przez użytkownika formie płatności. Pakiet paymentHandlerMethodData zawiera methodName i opcjonalne klucze details z wartościami będącymi ciągiem znaków. Chrome sprawdzi, czy pakiet nie jest pusty z niepustym elementem methodName, i jeśli weryfikacja się nie powiedzie, Chrome wyśle polecenie updatePaymentDetails z jednym z tych komunikatów o błędach.callback.updateWith

'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ę. Chrome sprawdzi, czy brakuje niepustego elementu shippingOptionId, i jeśli weryfikacja się nie powiedzie, wyśle updatePaymentDetails ten komunikat o błędzie za pomocą callback.updateWith.

'Shipping option identifier required.'

changeShippingAddress

Powiadamia sprzedawcę o zmianach w adresie dostawy podanym przez użytkownika. Chrome sprawdzi niepusty pakiet shippingAddress z prawidłową wartością countryCode i w razie niepowodzenia weryfikacji wyśle za pomocą callback.updateWith komunikat updatePaymentDetails z poniższym komunikatem o błędzie.

'Payment app returned invalid shipping address in response.'

Komunikat o błędzie dotyczącym nieprawidłowego stanu

Jeśli po otrzymaniu któregokolwiek z żądań zmiany Chrome napotka nieprawidłowy stan, wywoła metodę callback.updateWith z usuniętym pakietem updatePaymentDetails. Pakiet będzie zawierać tylko klucz error z "Invalid state". Przykłady nieprawidłowego stanu:

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

Otrzymuj od sprzedawcy zaktualizowane dane do płatności

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 jest odpowiednikiem pakietu ze słownika PaymentRequestDetailsUpdate WebIDL (po usunięciu pola modifiers) i zawiera te opcjonalne klucze:

  • total – pakiet zawierający klucze currency i value; oba klucze mają wartości w postaci ciągów
  • shippingOptions – tablica opcji dostawy z możliwością dostawy.
  • error – ciąg znaków zawierający ogólny komunikat o błędzie (np.changeShippingOption nie podaje prawidłowego identyfikatora opcji dostawy).
  • stringifiedPaymentMethodErrors – ciąg znaków JSON zawierający błędy weryfikacji formy płatności.
  • addressErrors – pakiet z opcjonalnymi kluczami identycznymi z adresem dostawy i wartościami ciągów znaków. Każdy klucz reprezentuje błąd weryfikacji związany z odpowiadającą mu częścią adresu dostawy.

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