ระบุข้อมูลการจัดส่งและข้อมูลติดต่อจากแอปการชำระเงิน Android

วิธีอัปเดตแอปการชำระเงิน Android เพื่อระบุที่อยู่จัดส่งและข้อมูลติดต่อของผู้ชำระเงินด้วย Web Payments API

Sahel Sharify
Sahel Sharify

เผยแพร่: 17 กรกฎาคม 2020, อัปเดตล่าสุด: 27 พฤษภาคม 2025

การป้อนที่อยู่จัดส่งและข้อมูลติดต่อผ่านแบบฟอร์มบนเว็บอาจเป็นประสบการณ์ที่ยุ่งยากสำหรับลูกค้า ซึ่งอาจทำให้เกิดข้อผิดพลาดและอัตรา Conversion ลดลง

ด้วยเหตุนี้ Payment Request API จึงรองรับฟีเจอร์ในการขอที่อยู่จัดส่ง และข้อมูลติดต่อ ซึ่งมีประโยชน์หลายประการ ดังนี้

  • ผู้ใช้เลือกที่อยู่ที่ถูกต้องได้ด้วยการแตะเพียงไม่กี่ครั้ง
  • ระบบจะแสดงผลที่อยู่ในรูปแบบมาตรฐาน เสมอ
  • โอกาสที่จะส่งที่อยู่ไม่ถูกต้องจะน้อยลง

เบราว์เซอร์สามารถเลื่อนการเก็บรวบรวมที่อยู่จัดส่งและข้อมูลติดต่อไปยัง แอปการชำระเงินเพื่อมอบประสบการณ์การชำระเงินแบบรวม ฟังก์ชันนี้เรียกว่าการมอบสิทธิ์

Chrome จะมอบสิทธิ์ให้แอปการชำระเงิน Android ที่เรียกใช้รวบรวมที่อยู่จัดส่งและข้อมูลติดต่อของลูกค้าทุกครั้งที่ทำได้ การมอบสิทธิ์จะช่วยลดอุปสรรคในระหว่างการชำระเงิน

เว็บไซต์ของผู้ขายสามารถอัปเดตตัวเลือกการจัดส่งและราคารวมแบบไดนามิก โดยขึ้นอยู่กับตัวเลือกที่อยู่จัดส่งและตัวเลือกการจัดส่งที่ลูกค้าเลือก

ตัวเลือกการจัดส่งและการเปลี่ยนที่อยู่สำหรับจัดส่งในการดำเนินการ ดูว่าการตั้งค่านี้ส่งผลต่อตัวเลือกการจัดส่งและราคารวมแบบไดนามิกอย่างไร

หากต้องการเพิ่มการรองรับการมอบสิทธิ์ให้กับแอปการชำระเงิน Android ที่มีอยู่แล้ว ให้ทำตามขั้นตอนต่อไปนี้

  1. ประกาศการมอบสิทธิ์ที่รองรับ
  2. แยกวิเคราะห์ PAY ส่วนเพิ่มเติมของ Intent สำหรับตัวเลือกการชำระเงินที่จำเป็น
  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 Extras ของ Intent ไปยังกิจกรรม PAY

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 คืออาร์เรย์ที่แยกวิเคราะห์ได้ของตัวเลือกการจัดส่งที่ผู้ขายระบุ พารามิเตอร์นี้จะใช้ได้เฉพาะเมื่อ 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 ที่มีค่าสตริง
  • 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 เป็นจริง
  • payerPhone - หมายเลขโทรศัพท์ของผู้ชำระเงิน ควรเป็นสตริงที่ไม่ว่างเปล่าเมื่อ paymentOptions.requestPayerPhone เป็นจริง
  • payerEmail - อีเมลของผู้ชำระเงิน ควรเป็นสตริงที่ไม่ว่างเปล่า เมื่อ paymentOptions.requestPayerEmail เป็นจริง
  • shippingAddress - ที่อยู่สำหรับจัดส่งที่ผู้ใช้ระบุ ควรเป็น ชุดข้อมูลที่ไม่ว่างเมื่อ paymentOptions.requestShipping เป็นจริง แพ็กเกจ ควรมีคีย์ต่อไปนี้ซึ่งแสดงส่วนต่างๆ ในที่อยู่จริง
    • countryCode
    • postalCode
    • sortingCode
    • region
    • city
    • dependentLocality
    • addressLine
    • organization
    • recipient
    • phone คีย์อื่นๆ ทั้งหมดนอกเหนือจาก addressLine มีค่าเป็นสตริง addressLine คืออาร์เรย์ของสตริง
  • shippingOptionId - ตัวระบุของตัวเลือกการจัดส่งที่ผู้ใช้เลือก ค่านี้ ควรเป็นสตริงที่ไม่ว่างเปล่าเมื่อ paymentOptions.requestShipping เป็นจริง

ตรวจสอบการตอบกลับการชำระเงิน

หากตั้งค่าผลลัพธ์ของกิจกรรมการตอบกลับการชำระเงินที่ได้รับจากแอปการชำระเงินที่เรียกใช้เป็น RESULT_OK Chrome จะตรวจสอบข้อมูลเพิ่มเติมที่จำเป็นในส่วน "Extras" หากการตรวจสอบไม่สำเร็จ Chrome จะแสดงผล Promise ที่ถูกปฏิเสธ จาก 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".'

ตัวอย่างโค้ดต่อไปนี้เป็นตัวอย่างการตอบกลับที่ถูกต้อง

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 และประกาศใน AndroidManifest.xml ด้วยตัวกรอง Intent UPDATE_PAYMENT_DETAILS

ทันทีหลังจากเรียกใช้ Intent PAY แล้ว Chrome จะเชื่อมต่อกับบริการ UPDATE_PAYMENT_DETAILS (หากมี) ในแพ็กเกจเดียวกันกับ Intent PAY และจะเรียกใช้ setPaymentDetailsUpdateService(service) เพื่อระบุปลายทาง IPaymentDetailsUpdateService ให้แอปการชำระเงินของคุณเพื่อแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลงวิธีการชำระเงิน ตัวเลือกการจัดส่ง หรือที่อยู่จัดส่งของผู้ใช้

ใช้ packageManager.getPackagesForUid(Binder.getCallingUid()) เมื่อรับ การสื่อสารระหว่างกระบวนการ (IPC) เพื่อตรวจสอบว่าแอปที่เรียกใช้ Intent 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

เปิดเผยบริการสำหรับ 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>

แจ้งให้ผู้ขายทราบเกี่ยวกับการเปลี่ยนแปลงวิธีการชำระเงิน ที่อยู่สำหรับจัดส่ง หรือตัวเลือกการจัดส่งที่ผู้ใช้เลือก

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 ที่ไม่ว่าง และส่ง 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 พบสถานะที่ไม่ถูกต้องเมื่อได้รับคำขอเปลี่ยนแปลง Chrome จะเรียกใช้ callback.updateWith พร้อมกับชุดข้อมูล updatePaymentDetails ที่มีการปกปิดข้อมูลบางส่วน โดยกลุ่มจะมีเฉพาะคีย์ error ที่มี "Invalid state" ตัวอย่างของสถานะที่ไม่ถูกต้องมีดังนี้

  • เมื่อ Chrome ยังคงรอการตอบกลับของผู้ขายสำหรับการเปลี่ยนแปลงก่อนหน้า (เช่น เหตุการณ์การเปลี่ยนแปลงที่กำลังดำเนินการ)
  • ตัวระบุตัวเลือกการจัดส่งที่แอปการชำระเงินระบุไม่ได้เป็นของตัวเลือกการจัดส่งที่ผู้ขายระบุ

รับรายละเอียดการชำระเงินที่อัปเดตจากผู้ขาย

Kotlin

override fun updateWith(updatedPaymentDetails: Bundle) {}

override fun paymentDetailsNotUpdated() {}

Java

@Override
public void updateWith(Bundle updatedPaymentDetails) {}

@Override
public void paymentDetailsNotUpdated() {}

updatedPaymentDetails คือเทียบเท่าของพจนานุกรม PaymentRequestDetailsUpdate WebIDL และมีคีย์ต่อไปนี้ (ไม่บังคับ)

  • total - ชุดที่มีคีย์ currency และ value โดยทั้ง 2 คีย์มีค่าสตริง
  • shippingOptions - อาร์เรย์ที่ส่งผ่านได้ของ shipping options
  • error - สตริงที่มีข้อความแสดงข้อผิดพลาดทั่วไป (เช่น เมื่อ changeShippingOption ไม่ได้ระบุตัวระบุตัวเลือกการจัดส่งที่ถูกต้อง)
  • stringifiedPaymentMethodErrors - สตริง JSON ที่แสดงข้อผิดพลาดในการตรวจสอบ วิธีการชำระเงิน
  • addressErrors - ชุดที่มีคีย์ที่ไม่บังคับซึ่งเหมือนกับ shipping address และค่าสตริง คีย์แต่ละรายการแสดงข้อผิดพลาดในการตรวจสอบที่เกี่ยวข้องกับส่วนที่สอดคล้องกันของที่อยู่จัดส่ง
  • modifiers - อาร์เรย์ที่ส่งผ่านได้ของ Bundle แต่ละรายการมีฟิลด์ total และ methodData ซึ่งเป็น Bundle ด้วย

คีย์ที่ไม่มีหมายความว่าค่าของคีย์นั้นไม่มีการเปลี่ยนแปลง