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

So aktualisieren Sie Ihre Android-App für Zahlungen, damit die Versandadresse und die Kontaktdaten des Zahlungspflichtigen über Web Payments APIs angegeben werden.

Sahel Sharify
Sahel Sharify

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

Aus diesem Grund unterstützt die Payment Request API eine Funktion zum Anfordern von Versandadressen und Kontaktdaten. Dies bietet mehrere Vorteile:

  • Nutzer können in wenigen Schritten die richtige Adresse auswählen.
  • Die Adresse wird immer im standardisierten Format zurückgegeben.
  • Es ist weniger wahrscheinlich, dass Sie eine falsche Adresse angeben.

Browser können die Erfassung von Versandadressen und Kontaktdaten an eine Zahlungs-App verschieben, um eine einheitliche Zahlung zu ermöglichen. 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. Dadurch wird der Bezahlvorgang vereinfacht.

Auf der Händlerwebsite können die Versandoptionen und der Gesamtpreis je nach ausgewählter Versandadresse und Versandoption dynamisch aktualisiert werden.

Versandoption und Versandadresse wurden geändert. Sehen Sie sich an, wie sich dies dynamisch auf die Versandoptionen und den Gesamtpreis auswirkt.

Wenn du einer vorhandenen Android-Zahlungs-App die Delegierung hinzufügen möchtest, musst du die folgenden Schritte ausführen:

  1. Deklarieren Sie unterstützte Delegierungen.
  2. PAY-Intent-Extras für erforderliche Zahlungsoptionen parsen
  3. Gib die erforderlichen Informationen in der Zahlungsantwort an.
  4. [Optional] Unterstützung dynamischer Ablauf:
    1. Den Händler über Änderungen an der vom Nutzer ausgewählten Zahlungsmethode, Versandadresse oder Versandoption informieren:
    2. Aktualisierte Zahlungsdetails vom Händler erhalten (z. B. den angepassten Gesamtbetrag auf Grundlage der Kosten der ausgewählten Versandoption)

Unterstützte Delegierungen deklarieren

Der Browser muss die Liste der zusätzlichen Informationen kennen, die Ihre Zahlungs-App zur Verfügung stellt, damit sie die Erhebung dieser Informationen an Ihre App delegieren kann. Deklarieren Sie die unterstützten Delegierungen in der Datei AndroidManifest.xml Ihrer App als <meta-data>.

<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 für erforderliche Zahlungsoptionen parsen

Weitere erforderliche Informationen kann der Händler mithilfe des Wörterbuchs paymentOptions angeben. Chrome zeigt eine Liste der erforderlichen Optionen an, die deine App bereitstellen kann. Dazu werden die folgenden Parameter als Intent-Extras an die PAY-Aktivität übergeben.

paymentOptions

paymentOptions ist die Teilmenge der vom Händler angegebenen Zahlungsoptionen, für die deine App die Delegation unterstützt 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 können enthalten sein:

  • requestPayerName: Der boolesche Wert, der angibt, ob der Name des Zahlungspflichtigen erforderlich ist.
  • requestPayerPhone: Der boolesche Wert, der angibt, ob die Telefonnummer des Zahlungspflichtigen 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 Versandart angibt Die Versandart kann "shipping", "delivery" oder "pickup" sein. Deine App kann diesen Hinweis in der Benutzeroberfläche verwenden, wenn sie nach der Adresse des Nutzers oder der Auswahl der Versandoptionen fragt.

shippingOptions

shippingOptions ist das Paket-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 der 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 für die Versandkosten als korrekt formatierten, aus drei Buchstaben bestehenden Code gemäß ISO4217 an.
    • value zeigt den Wert der Versandkosten als gültigen dezimalen Geldwert an.
  • selected: Gibt an, ob die Versandoption ausgewählt werden soll, wenn die Versandoptionen in der Zahlungs-App angezeigt werden.

Alle Schlüssel mit Ausnahme von 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

Deine App sollte die erforderlichen zusätzlichen Informationen in der Antwort auf die PAY-Aktivität angeben.

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

  • payerName: der vollständige Name des Zahlungspflichtigen. Dies sollte ein nicht leerer String sein, wenn paymentOptions.requestPayerName wahr ist.
  • payerPhone: die Telefonnummer des Zahlungspflichtigen. Dies sollte ein nicht leerer String sein, wenn paymentOptions.requestPayerPhone wahr ist.
  • payerEmail: die 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 in 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 Kennung 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 Zahlungsantwort, die von der aufgerufenen Zahlungs-App empfangen wurde, auf RESULT_OK gesetzt ist, sucht Chrome in seinen Extras nach erforderlichen zusätzlichen Informationen. Wenn die Validierung fehlschlägt, gibt Chrome ein abgelehntes Versprechen von request.show() mit einer der folgenden für Entwickler sichtbaren Fehlermeldungen 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 die Expressversandoption auswählt oder wenn sich die Liste der verfügbaren Versandoptionen oder deren Preise ändern, wenn der Nutzer eine internationale Versandadresse auswählt. Wenn in deiner App die vom Nutzer ausgewählte Versandadresse oder Option angezeigt wird, sollte sie den Händler über alle Änderungen der Versandadresse oder Option informieren und dem Nutzer die aktualisierten Zahlungsdetails (vom Händler bereitgestellt) anzeigen können.

AIDL

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

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

Den Händler über Änderungen an der vom Nutzer gewä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
        }
    }
}

Der für den Start-Intent des Dienstes verwendete callingPackageName kann je nach Browser, der die Zahlungsanforderung 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 (ein WebLayer-Einbettungscode) "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. Wenn die Validierung fehlschlägt, sendet Chrome eine updatePaymentDetails mit einer der folgenden Fehlermeldungen über callback.updateWith.

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

changeShippingOption

Informiert den Händler über Änderungen an der vom Nutzer ausgewählten Versandoption. shippingOptionId sollte die Kennung einer der vom Händler angegebenen Versandoptionen sein. Chrome sucht nach einem nicht leeren shippingOptionId und sendet ein updatePaymentDetails mit der folgenden Fehlermeldung über callback.updateWith, 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 ein updatePaymentDetails mit der folgenden Fehlermeldung über callback.updateWith, wenn die Validierung fehlschlägt.

'Payment app returned invalid shipping address in response.'

Fehlermeldung zu ungültigem Status

Wenn Chrome beim Empfang einer der Änderungsanfragen auf einen ungültigen Status stößt, 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 Versandoption-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-Äquivalent zum Wörterbuch PaymentRequestDetailsUpdate WebIDL (nach Entfernen des Felds modifiers) und enthält die folgenden optionalen Schlüssel:

  • total: Ein Bundle mit den Schlüsseln currency und value. Beide Schlüssel haben Stringwerte.
  • shippingOptions – Das Paket-Array der Versandoptionen
  • error: ein String mit einer allgemeinen Fehlermeldung (z.B. wenn changeShippingOption keine gültige Kennzeichnung der Versandoption angibt)
  • stringifiedPaymentMethodErrors: ein JSON-String, der Validierungsfehler für die Zahlungsmethode darstellt
  • addressErrors: Ein Set mit optionalen Schlüsseln, die mit der Versandadresse und den Stringwerten identisch sind. Jeder Schlüssel steht für einen Validierungsfehler, der sich auf den entsprechenden Teil der Versandadresse bezieht.

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