Предоставление информации о доставке и контактной информации из платежного приложения Android.

Как обновить платежное приложение Android, чтобы оно предоставляло адрес доставки и контактную информацию плательщика с помощью API веб-платежей.

Сахель Шарифи
Sahel Sharify

Опубликовано: 17 июля 2020 г., Последнее обновление: 27 мая 2025 г.

Ввод адреса доставки и контактной информации через веб-форму может быть обременительным для клиентов. Это может привести к ошибкам и снижению коэффициента конверсии.

Вот почему API запроса платежа поддерживает функцию запроса адреса доставки и контактной информации. Это дает множество преимуществ:

  • Пользователи могут выбрать нужный адрес всего за несколько нажатий.
  • Адрес всегда возвращается в стандартизированном формате .
  • Указание неправильного адреса менее вероятно.

Браузеры могут отложить сбор адреса доставки и контактной информации платежному приложению, чтобы обеспечить унифицированный платежный опыт. Эта функциональность называется делегированием .

По возможности Chrome делегирует сбор адреса доставки и контактной информации клиента вызванному платежному приложению Android. Делегирование уменьшает трение во время оформления заказа.

Сайт продавца может динамически обновлять варианты доставки и общую стоимость в зависимости от выбора покупателем адреса доставки и варианта доставки.

Изменение варианта доставки и адреса доставки в действии. Посмотрите, как это влияет на варианты доставки и общую стоимость динамически.

Чтобы добавить поддержку делегирования в уже существующее платежное приложение Android, выполните следующие действия:

  1. Объявить поддерживаемые делегации .
  2. Анализ дополнительных сведений о намерении PAY для поиска необходимых вариантов оплаты .
  3. Укажите необходимую информацию в ответе на платеж .
  4. [Необязательно] Поддержка динамического потока :
    1. Уведомить продавца об изменениях в выбранном пользователем способе оплаты, адресе доставки или варианте доставки .
    2. Получите обновленные реквизиты платежа от продавца (например, скорректированную общую сумму на основе стоимости выбранного варианта доставки) .

Объявить поддерживаемые делегации

Браузеру необходимо знать список дополнительной информации, которую может предоставить ваше платежное приложение, чтобы он мог делегировать сбор этой информации вашему приложению. Объявите поддерживаемые делегирования как <meta-data> в AndroidManifest.xml вашего приложения.

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

android:resource должен указывать на <string-array> , содержащий все или подмножество следующих значений:

  • payerName
  • payerEmail
  • payerPhone
  • shippingAddress

В следующем примере можно указать только адрес доставки и адрес электронной почты плательщика.

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

Анализ дополнительных сведений о намерении PAY для необходимых вариантов оплаты

Торговец может указать дополнительную требуемую информацию с помощью словаря paymentOptions . Chrome предоставит список требуемых параметров, которые может предоставить ваше приложение, передав дополнительные параметры намерения paymentOptions в действие PAY .

paymentOptions

paymentOptions — это подмножество указанных продавцом вариантов оплаты, для которых ваше приложение заявило о поддержке делегирования.

Котлин

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

Ява

Bundle paymentOptions = extras.getBundle("paymentOptions");
if (paymentOptions != null) {
    Boolean requestPayerName = paymentOptions.getBoolean("requestPayerName");
    Boolean requestPayerPhone = paymentOptions.getBoolean("requestPayerPhone");
    Boolean requestPayerEmail = paymentOptions.getBoolean("requestPayerEmail");
    Boolean requestShipping = paymentOptions.getBoolean("requestShipping");
    String shippingType = paymentOptions.getString("shippingType");
}

Он может включать в себя следующие параметры:

  • requestPayerName — логическое значение, указывающее, требуется ли указывать имя плательщика.
  • requestPayerPhone — логическое значение, указывающее, требуется ли номер телефона плательщика.
  • requestPayerEmail — логическое значение, указывающее, требуется ли указывать адрес электронной почты плательщика.
  • requestShipping — логическое значение, указывающее, требуется ли информация о доставке.
  • shippingType — строка, показывающая тип доставки. Тип доставки может быть "shipping" , "delivery" или "pickup" . Ваше приложение может использовать эту подсказку в своем пользовательском интерфейсе при запросе адреса пользователя или выборе вариантов доставки.

shippingOptions

shippingOptions — это массив parcelable указанных продавцом вариантов доставки. Этот параметр будет существовать только при paymentOptions.requestShipping == true .

Котлин

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

Ява

Parcelable[] shippingOptions = extras.getParcelableArray("shippingOptions");
for (Parcelable it : shippingOptions) {
  if (it != null && it instanceof Bundle) {
    Bundle shippingOption = (Bundle) it;
  }
}

Каждый вариант доставки представляет собой Bundle со следующими ключами.

  • id — идентификатор варианта доставки.
  • label — этикетка варианта доставки, показываемая пользователю.
  • amount — пакет стоимости доставки, содержащий ключи currency и value со строковыми значениями.
  • selected — следует ли выбирать вариант доставки, когда платежное приложение отображает варианты доставки.

Все ключи, кроме selected , имеют строковые значения. selected имеет логическое значение.

Котлин

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)

Ява

String id = bundle.getString("id");
String label = bundle.getString("label");
Bundle amount = bundle.getBundle("amount");
Boolean selected = bundle.getBoolean("selected", false);

Предоставьте требуемую информацию в ответе на платеж

Ваше приложение должно включать необходимую дополнительную информацию в ответ на действие PAY .

Для этого необходимо указать следующие параметры в качестве дополнительных параметров Intent:

  • payerName - Полное имя плательщика. Это должна быть непустая строка, если paymentOptions.requestPayerName имеет значение true.
  • payerPhone - Номер телефона плательщика. Это должна быть непустая строка, если paymentOptions.requestPayerPhone имеет значение true.
  • payerEmail - Адрес электронной почты плательщика. Это должна быть непустая строка, если paymentOptions.requestPayerEmail имеет значение true.
  • shippingAddress — указанный пользователем адрес доставки. Это должен быть непустой пакет, если paymentOptions.requestShipping имеет значение true. Пакет должен иметь следующие ключи, которые представляют различные части физического адреса .
    • countryCode
    • postalCode
    • sortingCode
    • region
    • city
    • dependentLocality
    • addressLine
    • organization
    • recipient
    • phone Все ключи, кроме addressLine , имеют строковые значения. addressLine — это массив строк.
  • shippingOptionId — идентификатор выбранного пользователем варианта доставки. Это должна быть непустая строка, если paymentOptions.requestShipping имеет значение true.

Подтвердить ответ на платеж

Если результат действия платежного ответа, полученного от вызванного платежного приложения, установлен на RESULT_OK , то Chrome проверит наличие необходимой дополнительной информации в своих дополнительных данных. Если проверка не пройдена, Chrome вернет отклоненное обещание из request.show() с одним из следующих сообщений об ошибках для разработчика:

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

Следующий пример кода является примером допустимого ответа:

Котлин

fun Intent.populateRequestedPaymentOptions() {
    if (requestPayerName) {
        putExtra("payerName", "John Smith")
    }
    if (requestPayerPhone) {
        putExtra("payerPhone", "5555555555")
    }
    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", "5555555555")
        putExtra("shippingAddress", address)
        putExtra("shippingOptionId", "standard")
    }
}

Ява

private Intent populateRequestedPaymentOptions() {
    Intent result = new Intent();
    if (requestPayerName) {
        result.putExtra("payerName", "John Smith");
    }
    if (requestPayerPhone) {
        presult.utExtra("payerPhone", "5555555555");
    }
    if (requestPayerEmail) {
        result.putExtra("payerEmail", "john.smith@gmail.com");
    }
    if (requestShipping) {
        Bundle address = new Bundle();
        address.putExtra("countryCode", "CA");
        address.putExtra("postalCode", "M5H2G4");
        address.putExtra("region", "Ontario");
        address.putExtra("city", "Toronto");
        String[] addressLines = new String[] {"111 Richmond st. West"};
        address.putExtra("addressLines", addressLines);
        address.putExtra("recipient", "John Smith");
        address.putExtra("phone", "5555555555");
        result.putExtra("shippingAddress", address);
        result.putExtra("shippingOptionId", "standard");
    }
    return result;
}

Дополнительно: Поддержка динамического потока

Иногда общая стоимость транзакции увеличивается, например, когда пользователь выбирает вариант экспресс-доставки или когда список доступных вариантов доставки или их цены изменяются, когда пользователь выбирает международный адрес доставки. Когда ваше приложение предоставляет выбранный пользователем адрес доставки или вариант, оно должно иметь возможность уведомлять продавца о любых изменениях адреса доставки или варианта и показывать пользователю обновленные платежные реквизиты (предоставленные продавцом).

Чтобы уведомить продавца о новых изменениях, реализуйте интерфейс IPaymentDetailsUpdateServiceCallback и объявите его в AndroidManifest.xml с фильтром намерений UPDATE_PAYMENT_DETAILS .

Сразу после вызова намерения PAY Chrome подключится к службе UPDATE_PAYMENT_DETAILS (если она существует) в том же пакете, что и намерение PAY , и вызовет setPaymentDetailsUpdateService(service) , чтобы предоставить вашему платежному приложению конечную точку IPaymentDetailsUpdateService для уведомления об изменениях в способе оплаты пользователя, варианте доставки или адресе доставки.

Используйте packageManager.getPackagesForUid(Binder.getCallingUid()) при получении межпроцессного взаимодействия (IPC), чтобы проверить, что приложение, вызвавшее намерение PAY , имеет то же имя пакета, что и приложение, вызвавшее методы IPaymentDetailsUpdateServiceCallback .

АЙДЛ

Создайте два файла AIDL со следующим содержимым:

org/chromium/components/payments/IPaymentDetailsUpdateServiceCallback.aidl

package org.chromium.components.payments;

import android.os.Bundle;
import org.chromium.components.payments.IPaymentDetailsUpdateService;

interface IPaymentDetailsUpdateServiceCallback {
    oneway void updateWith(in Bundle updatedPaymentDetails);

    oneway void paymentDetailsNotUpdated();

    oneway void setPaymentDetailsUpdateService(IPaymentDetailsUpdateService service);
}

org/chromium/components/payments/IPaymentDetailsUpdateService.aidl

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

Услуга

Реализуйте службу IPaymentDetailsUpdateServiceCallback .

Котлин

class SampleUpdatePaymentDetailsCallbackService : Service() {
    private val binder = object : IPaymentDetailsUpdateServiceCallback.Stub() {
        override fun updateWith(updatedPaymentDetails: Bundle) {}

        override fun paymentDetailsNotUpdated() {}

        override fun setPaymentDetailsUpdateService(service: IPaymentDetailsUpdateService) {}
    }

    override fun onBind(intent: Intent?): IBinder? {
        return binder
    }
}

Ява

import org.chromium.components.paymsnts.IPaymentDetailsUpdateServiceCallback;

public class SampleUpdatePaymentDetailsCallbackService extends Service {
    private final IPaymentDetailsUpdateServiceCallback.Stub mBinder =
        new IPaymentDetailsUpdateServiceCallback.Stub() {
            @Override
            public void updateWith(Bundle updatedPaymentDetails) {}

            @Override
            public void paymentDetailsNotUpdated() {}

            @Override
            public void setPaymentDetailsUpdateService(IPaymentDetailsUpdateService service) {}
        };

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

AndroidManifest.xml

Предоставьте доступ к службе IPaymentDetailsUpdateServiceCallback в вашем AndroidManifest.xml .

<service
    android:name=".SampleUpdatePaymentDetailsCallbackService"
    android:exported="true">
    <intent-filter>
        <action android:name="org.chromium.intent.action.UPDATE_PAYMENT_DETAILS" />
    </intent-filter>
</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
}

Ява

if (service == null) {
  return;
}

try {
    if (isOptionChange) {
        service.changeShippingOption(selectedOptionId, callback);
    } else (isAddressChange) {
        service.changeShippingAddress(selectedAddress, callback);
    } else {
        service.changePaymentMethod(methodData, callback);
    }
} catch (RemoteException e) {
    // Handle the remote exception
}

changePaymentMethod

Уведомляет продавца об изменениях в выбранном пользователем способе оплаты. Пакет paymentHandlerMethodData содержит ключи methodName и необязательные details , оба со строковыми значениями. Chrome проверит наличие непустого пакета с непустым methodName и отправит updatePaymentDetails с одним из следующих сообщений об ошибке через callback.updateWith , если проверка не пройдена.

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

changeShippingOption

Уведомляет продавца об изменениях в выбранном пользователем варианте доставки. shippingOptionId должен быть идентификатором одного из указанных продавцом вариантов доставки. Chrome проверит наличие непустого shippingOptionId и отправит updatePaymentDetails со следующим сообщением об ошибке через callback.updateWith , если проверка не пройдена.

'Shipping option identifier required.'

changeShippingAddress

Уведомляет продавца об изменениях в указанном пользователем адресе доставки. Chrome проверит наличие непустого пакета shippingAddress с действительным countryCode и отправит updatePaymentDetails со следующим сообщением об ошибке через callback.updateWith , если проверка не пройдена.

'Payment app returned invalid shipping address in response.'

Сообщение об ошибке «Недопустимое состояние»

Если Chrome обнаруживает недопустимое состояние при получении любого из запросов на изменение, он вызовет callback.updateWith с отредактированным пакетом updatePaymentDetails . Пакет будет содержать только ключ error с "Invalid state" . Примеры недопустимого состояния:

  • Когда Chrome все еще ожидает ответа продавца на предыдущее изменение (например, текущее событие изменения).
  • Идентификатор способа доставки, предоставленный платежным приложением, не принадлежит ни одному из способов доставки, указанных продавцом.

Получите обновленные платежные реквизиты от продавца

Котлин

override fun updateWith(updatedPaymentDetails: Bundle) {}

override fun paymentDetailsNotUpdated() {}

Ява

@Override
public void updateWith(Bundle updatedPaymentDetails) {}

@Override
public void paymentDetailsNotUpdated() {}

updatedPaymentDetails — это пакет, эквивалентный словарю PaymentRequestDetailsUpdate WebIDL , который содержит следующие необязательные ключи:

  • total - Пакет, содержащий ключи currency и value , оба ключа имеют строковые значения
  • shippingOptions — множество вариантов доставки, подлежащих отправке
  • error — строка, содержащая общее сообщение об ошибке (например, когда changeShippingOption не предоставляет действительный идентификатор варианта доставки)
  • stringifiedPaymentMethodErrors — строка JSON, представляющая ошибки проверки для способа оплаты.
  • addressErrors - Пакет с необязательными ключами, идентичными адресу доставки и строковым значениям. Каждый ключ представляет собой ошибку проверки, связанную с соответствующей частью адреса доставки.
  • modifiers — разделяемый массив пакетов, каждый из которых имеет поля total и methodData , которые также являются пакетами.

Отсутствие ключа означает, что его значение не изменилось.