Android の支払いアプリから配送先情報と連絡先情報を取得する

Web Payments API で配送先住所と支払者の連絡先情報を提供するために Android 決済アプリを更新する方法。

Sahel Sharify
Sahel Sharify

公開日: 2020 年 7 月 17 日、最終更新日: 2025 年 5 月 27 日

ウェブフォームから配送先住所と連絡先情報を入力するのは、お客様にとって面倒な作業です。エラーが発生し、コンバージョン率が低下する可能性があります。

そのため、Payment Request API は配送先住所と連絡先情報をリクエストする機能をサポートしています。これには次のようなメリットがあります。

  • ユーザーは数回タップするだけで正しい住所を選択できます。
  • 住所は常に標準化された形式で返されます。
  • 間違った住所を送信する可能性は低くなります。

ブラウザは、配送先住所と連絡先情報の収集を支払いアプリに委任して、統一された支払いエクスペリエンスを提供できます。この機能を委任といいます。

可能な場合、Chrome はお客様の配送先住所と連絡先情報の収集を呼び出された Android 決済アプリに委任します。委任により、購入手続き時の摩擦が軽減されます。

販売者のウェブサイトでは、お客様が選択した配送先住所と配送オプションに応じて、配送オプションと合計金額を動的に更新できます。

配送オプションと配送先住所の変更が実行されている。配送オプションと合計金額に動的に影響する様子を確認します。

既存の Android 決済アプリに委任のサポートを追加するには、次の手順を実装します。

  1. サポートされている委任を宣言します
  2. 必要な支払いオプションの PAY インテント エクストラを解析します
  3. 支払いレスポンスで必要な情報を提供する
  4. 省略可: 動的フローをサポート:
    1. ユーザーが選択したお支払い方法、配送先住所、配送オプションの変更について販売者に通知します
    2. 販売者から更新された支払い情報を受け取ります(たとえば、選択した配送オプションの費用に基づいて調整された合計金額など)

サポートされている委任を宣言する

ブラウザは、お支払いアプリが提供できる追加情報のリストを把握し、その情報の収集をお支払いアプリに委任する必要があります。サポートされている委任を、アプリの AndroidManifest.xml<meta-data> として宣言します。

<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 は、PAY アクティビティに paymentOptions Intent エクストラを渡すことで、アプリが提供できる必要なオプションのリストを提供します。

paymentOptions

paymentOptions は、アプリが委任サポートを宣言した、販売者が指定した支払いオプションのサブセットです。

Kotlin

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

Java

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" のいずれかです。アプリは、ユーザーの住所や配送オプションの選択を求める際に、このヒントを UI で使用できます。

shippingOptions

shippingOptions は、販売者が指定した配送オプションの Parcelable 配列です。このパラメータは、paymentOptions.requestShipping == true の場合にのみ存在します。

Kotlin

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

Java

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 キー(文字列値)を含む送料バンドル。
    • currency は、送料の通貨を ISO4217 の整形式の 3 文字のアルファベット コードで示します。
    • value は、有効な 10 進数の金額値として送料の値を示します。
  • selected - 支払いアプリが配送オプションを表示するときに、配送オプションを選択するかどうか。

selected 以外のすべてのキーには文字列値があります。selected はブール値です。

Kotlin

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)

Java

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() から拒否された Promise を返し、次のいずれかのデベロッパー向けエラー メッセージを表示します。

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

次のコードサンプルは、有効なレスポンスの例です。

Kotlin

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

Java

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 インターフェースを実装し、UPDATE_PAYMENT_DETAILS インテント フィルタを使用して AndroidManifest.xml で宣言します。

PAY インテントを呼び出すとすぐに、Chrome は PAY インテントと同じパッケージ内の UPDATE_PAYMENT_DETAILS サービス(存在する場合)に接続し、setPaymentDetailsUpdateService(service) を呼び出して、ユーザーのお支払い方法、配送オプション、配送先住所の変更を通知するための IPaymentDetailsUpdateService エンドポイントをお支払いアプリに提供します。

プロセス間通信(IPC)を受信するときに packageManager.getPackagesForUid(Binder.getCallingUid()) を使用して、PAY インテントを呼び出したアプリのパッケージ名が、IPaymentDetailsUpdateServiceCallback メソッドを呼び出したアプリのパッケージ名と同じであることを検証します。

AIDL

次の内容の AIDL ファイルを 2 つ作成します。

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 サービスを実装します。

Kotlin

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

Java

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

AndroidManifest.xmlIPaymentDetailsUpdateServiceCallback のサービスを公開します。

<service
    android:name=".SampleUpdatePaymentDetailsCallbackService"
    android:exported="true">
    <intent-filter>
        <action android:name="org.chromium.intent.action.UPDATE_PAYMENT_DETAILS" />
    </intent-filter>
</service>

ユーザーが選択したお支払い方法、配送先住所、配送オプションの変更について販売者に通知する

Kotlin

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
}

Java

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 を含む空でないバンドルを確認し、検証に失敗した場合は、callback.updateWith を使用して次のいずれかのエラー メッセージを含む updatePaymentDetails を送信します。

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

changeShippingOption

ユーザーが選択した配送オプションの変更を販売者に通知します。shippingOptionId は、販売者が指定した配送オプションのいずれかの識別子である必要があります。Chrome は空でない shippingOptionId をチェックし、検証に失敗した場合は callback.updateWith を使用して次のエラー メッセージを含む updatePaymentDetails を送信します。

'Shipping option identifier required.'

changeShippingAddress

ユーザーが指定した配送先住所の変更を販売者に通知します。Chrome は、有効な countryCode を含む空でない shippingAddress バンドルを確認し、検証に失敗した場合は callback.updateWith を使用して次のエラー メッセージを含む updatePaymentDetails を送信します。

'Payment app returned invalid shipping address in response.'

無効な状態のエラー メッセージ

Chrome は、変更リクエストのいずれかを受信したときに無効な状態を検出すると、編集された updatePaymentDetails バンドルを使用して callback.updateWith を呼び出します。バンドルには、"Invalid state" を含む error キーのみが含まれます。無効な状態の例:

  • Chrome が、以前の変更(進行中の変更イベントなど)に対する販売者のレスポンスを待機している場合。
  • 支払いアプリから提供された配送オプションの識別子が、販売者が指定した配送オプションのいずれにも属していません。

販売者から更新されたお支払い情報を受け取る

Kotlin

override fun updateWith(updatedPaymentDetails: Bundle) {}

override fun paymentDetailsNotUpdated() {}

Java

@Override
public void updateWith(Bundle updatedPaymentDetails) {}

@Override
public void paymentDetailsNotUpdated() {}

updatedPaymentDetailsPaymentRequestDetailsUpdate WebIDL 辞書と同等のバンドルで、次の省略可能なキーが含まれています。

  • total - currencyvalue のキーを含むバンドル。両方のキーに文字列値があります。
  • shippingOptions - 配送オプションの Parcelable 配列
  • error - 一般的なエラー メッセージを含む文字列(changeShippingOption が有効な配送オプション ID を提供していない場合など)
  • stringifiedPaymentMethodErrors - 支払い方法の検証エラーを表す JSON 文字列
  • addressErrors - 配送先住所と同一のオプション キーと文字列値を含むバンドル。各キーは、配送先住所の対応する部分に関連する検証エラーを表します。
  • modifiers - total フィールドと methodData フィールド(どちらも Bundle)を含む Bundle の Parcelable 配列。

キーがない場合は、値が変更されていないことを意味します。