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

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

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 Payment Request API ma funkcję żądania adresu dostawy i danych kontaktowych. Zapewnia to wiele korzyści:

  • Aby wybrać właściwy adres, wystarczy kilka kliknięć.
  • Adres jest zawsze zwracany w standardowym formacie.
  • Przesłanie nieprawidłowego adresu jest mniej prawdopodobne.

Przeglądarki mogą odroczyć zbieranie adresu dostawy i danych kontaktowych do aplikacji płatniczej, aby zapewnić jednolitą obsługę płatności. Funkcja ta jest nazywana przekazywaniem dostępu.

W miarę możliwości Chrome przekazuje adres dostawy i dane kontaktowe klienta do wywoływanej aplikacji płatniczej na Androida. Przekazywanie dostępu ułatwia proces płatności.

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

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

Aby dodać obsługę przekazywania dostępu do istniejącej aplikacji płatniczej na Androida, wykonaj te czynności:

  1. Deklarowanie obsługiwanych przekazywania dostępu.
  2. Przeanalizuj dodatki do intencji PAY pod kątem wymaganych opcji płatności.
  3. Podaj wymagane informacje w odpowiedzi na płatność.
  4. [Opcjonalnie] Dynamiczny przepływ pomocy:
    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 (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 podać Twoja aplikacja płatnicza, aby delegować zbieranie tych informacji do Twojej aplikacji. Zadeklaruj obsługiwane przekazania jako <meta-data> w pliku AndroidManifest.xml Twojej 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" ]

W przykładzie poniżej 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>

Przeanalizuj dodatki do intencji PAY, aby uzyskać informacje o wymaganych opcjach 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ę, w przypadku których Twoja aplikacja zadeklarowała obsługę przekazywania 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ć 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 wymagane są informacje o dostawie.
  • shippingType – ciąg tekstowy wskazujący typ dostawy. Typ dostawy może być "shipping", "delivery" lub "pickup". Aplikacja może użyć tej wskazówki w interfejsie, gdy pytasz użytkownika o adres lub o opcje dostawy.

shippingOptions

shippingOptions to tablica parowalna z opcjami dostawy określonymi przez sprzedawcę. Ten parametr będzie istnieć 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 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 należy wybrać opcję dostawy, gdy aplikacja płatnicza wyświetla opcje dostawy.

Wszystkie klucze poza selected zawierają ciągi znaków. selected zawiera 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 podawać wymagane informacje dodatkowe.

W tym celu jako dodatki intencji należy określić te parametry:

  • payerName – pełna nazwa płatnika. Gdy paymentOptions.requestPayerName ma wartość prawda, ten ciąg nie może być pusty.
  • payerPhone – numer telefonu płatnika. Gdy paymentOptions.requestPayerPhone ma wartość prawda, ten ciąg nie może być pusty.
  • payerEmail – adres e-mail płatnika. Gdy paymentOptions.requestPayerEmail ma wartość prawda, ciąg znaków nie może być pusty.
  • shippingAddress – adres dostawy podany przez użytkownika. Jeśli paymentOptions.requestShipping ma wartość prawda, pakiet nie powinien być pusty. 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 oprócz addressLine zawierają wartości typu ciąg znaków. addressLine jest tablicą ciągów znaków.
  • shippingOptionId – identyfikator opcji dostawy wybranej przez użytkownika. Gdy paymentOptions.requestShipping ma wartość prawda, ciąg znaków nie może być pusty.

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

Jeśli wynik działania w odpowiedzi na płatność otrzymaną z wywołanej aplikacji płatniczej ma wartość RESULT_OK, Chrome sprawdza, czy w jej dodatkach znajdują się wymagane dodatkowe informacje. Jeśli weryfikacja się nie powiedzie, Chrome zwróci odrzuconą obietnicę z request.show() z jednym z tych komunikatów o błędach, które napotykają programiści:

'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 dynamicznego przepływu

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 aplikacja udostępnia wybrany przez użytkownika adres lub opcję dostawy, powinna być w stanie powiadomić sprzedawcę o wszelkich zmianach adresu lub opcji dostawy i wyświetlić 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 AIDL z taką 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 dla 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"
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 opcjonalne klucze details z ciągami znaków. Chrome wyszuka niepusty pakiet z niepustym elementem methodName i jeśli weryfikacja się nie powiedzie, wyśle updatePaymentDetails jeden z następujących komunikatów o błędach przez callback.updateWith.

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

changeShippingOption

Powiadamia sprzedawcę o zmianach w opcji dostawy wybranej przez użytkownika. shippingOptionId powinien być identyfikatorem jednej z opcji dostawy określonych przez sprzedawcę. Chrome wyszuka niepuste pole shippingOptionId i w przypadku niepowodzenia weryfikacji wyśle updatePaymentDetails z poniższym komunikatem 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, 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 informujący o nieprawidłowym stanie

Jeśli po otrzymaniu żądania zmiany Chrome wykryje nieprawidłowy stan, wywoła 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 podany w aplikacji 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 odpowiednika słownika PaymentRequestDetailsUpdate WebIDL (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 tekstowy zawierający ogólny komunikat o błędzie (np.gdy changeShippingOption nie podaje prawidłowego identyfikatora opcji dostawy).
  • stringifiedPaymentMethodErrors – ciąg znaków JSON reprezentujący błędy weryfikacji formy płatności
  • addressErrors – pakiet z opcjonalnymi kluczami identycznymi z adresem dostawy i wartościami w postaci ciągów znaków. Każdy klucz reprezentuje błąd weryfikacji związany z odpowiadającej mu części adresu dostawy.

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