Versand- und Kontaktdaten über eine Android-Zahlungs-App angeben

So aktualisieren Sie Ihre Android-Zahlungs-App mit Web Payments APIs, um die Versandadresse und Kontaktdaten des Zahlungspflichtigen anzugeben.

Sahel-Sharify
Sahel-Sharify

Die Eingabe der Versandadresse und Kontaktdaten über ein Webformular kann für Kunden mühsam sein. Dies kann zu Fehlern und einer niedrigeren Conversion-Rate führen.

Die Payment Request API unterstützt daher eine Funktion zum Anfordern von Versandadresse und Kontaktdaten. Das bietet mehrere Vorteile:

  • Nutzer können die richtige Adresse mit wenigen Fingertipps auswählen.
  • Die Adresse wird immer im standardisierten Format zurückgegeben.
  • Wenn Sie eine falsche Adresse angeben, ist die Wahrscheinlichkeit geringer, dass Sie eine falsche Adresse angeben.

Browser können die Erfassung von Versandadressen und Kontaktdaten zu einer Zahlungsanwendung verschieben, um eine einheitliche Zahlungsfunktion zu gewährleisten. Diese Funktion wird als Delegierung bezeichnet.

Wann immer möglich, delegiert Chrome die Erfassung der Versandadresse und Kontaktdaten eines Kunden an die aufgerufene Android-Zahlungs-App. Die Delegierung vereinfacht den Bezahlvorgang.

Die Versandoptionen und der Gesamtpreis können auf der Händlerwebsite je nach ausgewählter Versandadresse und Versandoption durch den Kunden dynamisch aktualisiert werden.

Änderung von Versandoption und Versandadresse in Aktion. Erfahren Sie, wie sich dies auf Versandoptionen und den Gesamtpreis auswirkt.

Wenn Sie einer bereits vorhandenen Android-Zahlungs-App die Unterstützung für die Delegierung hinzufügen möchten, führen Sie die folgenden Schritte aus:

  1. Deklarieren Sie unterstützte Delegierungen.
  2. Parse PAY-Intent-Extras nach erforderlichen Zahlungsoptionen.
  3. Geben Sie die erforderlichen Informationen in der Zahlungsantwort an.
  4. [Optional] Dynamischen Ablauf unterstützen:
    1. Den Händler über Änderungen der vom Nutzer ausgewählten Zahlungsmethode, Versandadresse oder Versandoption informieren.
    2. Aktualisierte Zahlungsdetails vom Händler erhalten (z. B. den angepassten Gesamtpreis basierend auf den Kosten der ausgewählten Versandoption).

Unterstützte Delegierungen deklarieren

Der Browser muss die Liste der zusätzlichen Informationen kennen, die deine Zahlungs-App bereitstellen kann, damit er die Erfassung dieser Informationen an deine App delegieren kann. Deklariere die unterstützten Delegierungen als <meta-data> in der Datei AndroidManifest.xml deiner App.

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

<resource> muss eine Liste von Strings sein, die aus den folgenden gültigen Werten ausgewählt werden:

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

Im folgenden Beispiel können nur eine Versandadresse und die E-Mail-Adresse des Zahlungspflichtigen angegeben werden.

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

PAY Intent-Extras nach erforderlichen Zahlungsoptionen parsen

Der Händler kann zusätzliche erforderliche Informationen mithilfe des paymentOptions-Wörterbuchs angeben. Chrome stellt eine Liste der erforderlichen Optionen bereit, die deine App bereitstellen kann. Dazu übergibst du die folgenden Parameter als Intent-Extras an die Aktivität PAY.

paymentOptions

paymentOptions ist die Teilmenge der vom Händler angegebenen Zahlungsoptionen, für die deine App die Unterstützung der Delegierung deklariert hat.

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

Folgende Parameter sind möglich:

  • requestPayerName: Der boolesche Wert, der angibt, ob der Name des Zahlungspflichtigen erforderlich ist.
  • requestPayerPhone: Der boolesche Wert, der angibt, ob das Smartphone des Zahlenden erforderlich ist.
  • requestPayerEmail: Der boolesche Wert, der angibt, ob die E-Mail-Adresse des Zahlungspflichtigen erforderlich ist.
  • requestShipping: der boolesche Wert, der angibt, ob Versandinformationen erforderlich sind.
  • shippingType: String, der die Art des Versands angibt. Als Versandtyp kann "shipping", "delivery" oder "pickup" ausgewählt werden. Ihre App kann diesen Hinweis auf der Benutzeroberfläche verwenden, wenn sie nach der Adresse des Nutzers oder den ausgewählten Versandoptionen fragt.

shippingOptions

shippingOptions ist das parcelable Array der vom Händler angegebenen Versandoptionen. Dieser Parameter ist nur vorhanden, wenn paymentOptions.requestShipping == true.

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

Jede Versandoption ist ein Bundle mit den folgenden Schlüsseln.

  • id: die Kennung der Versandoption.
  • label: das Label für die Versandoption, das dem Nutzer angezeigt wird.
  • amount: Das Versandkostenset, das die Schlüssel currency und value mit Stringwerten enthält.
    • currency gibt die Währung der Versandkosten als korrekt formatierter ISO4217-Buchstaben mit drei Buchstaben an.
    • value gibt den Wert der Versandkosten als gültiger dezimaler Geldwert an.
  • selected: Gibt an, ob die Versandoption ausgewählt werden soll, wenn die Zahlungs-App die Versandoptionen anzeigt.

Alle Schlüssel außer selected haben Stringwerte. selected hat einen booleschen Wert.

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)

Erforderliche Informationen in einer Zahlungsantwort angeben

Ihre App sollte die erforderlichen zusätzlichen Informationen in ihrer Antwort auf die Aktivität PAY enthalten.

Dazu müssen die folgenden Parameter als Intent-Extras angegeben werden:

  • payerName: Vollständiger Name des Zahlungspflichtigen Dies sollte ein nicht leerer String sein, wenn paymentOptions.requestPayerName wahr ist.
  • payerPhone: Telefonnummer des Zahlungspflichtigen Dies sollte ein nicht leerer String sein, wenn paymentOptions.requestPayerPhone wahr ist.
  • payerEmail: E-Mail-Adresse des Zahlungspflichtigen Dies sollte ein nicht leerer String sein, wenn paymentOptions.requestPayerEmail wahr ist.
  • shippingAddress: die vom Nutzer angegebene Versandadresse Dies sollte ein nicht leeres Bundle sein, wenn paymentOptions.requestShipping wahr ist. Das Bundle sollte die folgenden Schlüssel enthalten, die verschiedene Teile einer physischen Adresse darstellen.
    • city
    • countryCode
    • dependentLocality
    • organization
    • phone
    • postalCode
    • recipient
    • region
    • sortingCode
    • addressLine Alle Schlüssel mit Ausnahme von addressLine haben Stringwerte. addressLine ist ein Array von Strings.
  • shippingOptionId: die Kennzeichnung der vom Nutzer ausgewählten Versandoption. Dies sollte ein nicht leerer String sein, wenn paymentOptions.requestShipping „wahr“ ist.

Zahlungsantwort validieren

Wenn das Aktivitätsergebnis einer von der aufgerufenen Zahlungs-App empfangenen Zahlungsantwort auf RESULT_OK gesetzt ist, sucht Chrome in den Extras nach erforderlichen zusätzlichen Informationen. Wenn die Überprüfung fehlschlägt, gibt Chrome ein abgelehntes Promise von request.show() mit einer der folgenden Fehlermeldungen für Entwickler zurück:

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

Das folgende Codebeispiel ist ein Beispiel für eine gültige Antwort:

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

Optional: Dynamischen Ablauf unterstützen

Manchmal steigen die Gesamtkosten einer Transaktion, z. B. wenn der Nutzer den Expressversand wählt oder wenn sich die Liste der verfügbaren Versandoptionen oder die Preise ändern, wenn der Nutzer eine internationale Versandadresse wählt. Wenn in deiner App die vom Nutzer ausgewählte Versandadresse oder Option zur Verfügung gestellt wird, sollte der Händler in der Lage sein, den Händler über eventuelle Änderungen der Versandadresse oder Option zu informieren und ihm die aktualisierten, vom Händler bereitgestellten Zahlungsdetails anzuzeigen.

AIDL

Wenn du den Händler über neue Änderungen informieren möchtest, verwende den Dienst PaymentDetailsUpdateService, der in der Chrome-Datei „AndroidManifest.xml“ deklariert ist. Erstellen Sie zwei AIDL-Dateien mit folgendem Inhalt, um diesen Dienst zu verwenden:

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

Händler über Änderungen der vom Nutzer ausgewählten Zahlungsmethode, Versandadresse oder Versandoption informieren

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

Die für den Start-Intent des Dienstes verwendete callingPackageName kann je nach Browser, der die Zahlungsanfrage initiiert hat, einen der folgenden Werte haben.

Chrome-Version Paketname
Stabil "com.android.chrome"
Beta "com.chrome.beta"
Dev "com.chrome.dev"
Canary "com.chrome.canary"
Chromium "org.chromium.chrome"
Google-Schnellsuchfeld (WebLayer-Einbettung) "com.google.android.googlequicksearchbox"

changePaymentMethod

Informiert den Händler über Änderungen an der vom Nutzer ausgewählten Zahlungsmethode. Das Bundle paymentHandlerMethodData enthält methodName- und optionale details-Schlüssel mit Stringwerten. Chrome sucht nach einem nicht leeren Bundle mit einem nicht leeren methodName und sendet ein updatePaymentDetails mit einer der folgenden Fehlermeldungen über callback.updateWith, wenn die Validierung fehlschlägt.

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

changeShippingOption

Informiert den Händler über Änderungen an der vom Nutzer ausgewählten Versandoption. shippingOptionId sollte die Kennzeichnung einer der vom Händler angegebenen Versandoptionen sein. Chrome sucht nach einem nicht leeren shippingOptionId und sendet über callback.updateWith eine updatePaymentDetails mit der folgenden Fehlermeldung, wenn die Validierung fehlschlägt.

'Shipping option identifier required.'

changeShippingAddress

Informiert den Händler über Änderungen an der vom Nutzer angegebenen Versandadresse. Chrome sucht nach einem nicht leeren shippingAddress-Bundle mit einem gültigen countryCode und sendet eine updatePaymentDetails mit der folgenden Fehlermeldung über callback.updateWith, wenn die Validierung fehlschlägt.

'Payment app returned invalid shipping address in response.'

Fehlermeldung „Ungültiger Status“

Wenn Chrome beim Empfang einer der Änderungsanfragen einen ungültigen Status feststellt, wird callback.updateWith mit einem entfernten updatePaymentDetails-Bundle aufgerufen. Das Bundle enthält nur den Schlüssel error mit "Invalid state". Beispiele für einen ungültigen Status:

  • Wenn Chrome noch auf die Antwort des Händlers auf eine vorherige Änderung (z. B. ein laufendes Änderungsereignis) wartet.
  • Die von der Zahlungs-App bereitgestellte Versandoptions-ID gehört zu keiner der vom Händler angegebenen Versandoptionen.

Aktualisierte Zahlungsdetails vom Händler erhalten

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 ist das Bundle, das dem WebIDL PaymentRequestDetailsUpdate entspricht (nach dem Entfernen des Felds modifiers) und enthält die folgenden optionalen Schlüssel:

  • total: Ein Bundle mit den Schlüsseln currency und value, wobei beide Schlüssel Stringwerte haben
  • shippingOptions: das parcelable Array der Versandoptionen
  • error: ein String mit einer allgemeinen Fehlermeldung, z.B. wenn changeShippingOption keine gültige Kennzeichnung für die Versandoption bereitstellt
  • stringifiedPaymentMethodErrors: Ein JSON-String, der Validierungsfehler für die Zahlungsmethode darstellt
  • addressErrors: Ein Set mit optionalen Schlüsseln, die mit Versandadresse und Stringwerten identisch sind. Jeder Schlüssel steht für einen Validierungsfehler im Zusammenhang mit dem entsprechenden Teil der Versandadresse.

Ein fehlender Schlüssel bedeutet, dass sich sein Wert nicht geändert hat.