วิธีอัปเดตแอปการชำระเงิน Android เพื่อระบุที่อยู่จัดส่งและข้อมูลติดต่อของผู้ชำระเงินด้วย Web Payments API
เผยแพร่: 17 กรกฎาคม 2020, อัปเดตล่าสุด: 27 พฤษภาคม 2025
การป้อนที่อยู่จัดส่งและข้อมูลติดต่อผ่านแบบฟอร์มบนเว็บอาจเป็นประสบการณ์ที่ยุ่งยากสำหรับลูกค้า ซึ่งอาจทำให้เกิดข้อผิดพลาดและอัตรา Conversion ลดลง
ด้วยเหตุนี้ Payment Request API จึงรองรับฟีเจอร์ในการขอที่อยู่จัดส่ง และข้อมูลติดต่อ ซึ่งมีประโยชน์หลายประการ ดังนี้
- ผู้ใช้เลือกที่อยู่ที่ถูกต้องได้ด้วยการแตะเพียงไม่กี่ครั้ง
- ระบบจะแสดงผลที่อยู่ในรูปแบบมาตรฐาน เสมอ
- โอกาสที่จะส่งที่อยู่ไม่ถูกต้องจะน้อยลง
เบราว์เซอร์สามารถเลื่อนการเก็บรวบรวมที่อยู่จัดส่งและข้อมูลติดต่อไปยัง แอปการชำระเงินเพื่อมอบประสบการณ์การชำระเงินแบบรวม ฟังก์ชันนี้เรียกว่าการมอบสิทธิ์
Chrome จะมอบสิทธิ์ให้แอปการชำระเงิน Android ที่เรียกใช้รวบรวมที่อยู่จัดส่งและข้อมูลติดต่อของลูกค้าทุกครั้งที่ทำได้ การมอบสิทธิ์จะช่วยลดอุปสรรคในระหว่างการชำระเงิน
เว็บไซต์ของผู้ขายสามารถอัปเดตตัวเลือกการจัดส่งและราคารวมแบบไดนามิก โดยขึ้นอยู่กับตัวเลือกที่อยู่จัดส่งและตัวเลือกการจัดส่งที่ลูกค้าเลือก
หากต้องการเพิ่มการรองรับการมอบสิทธิ์ให้กับแอปการชำระเงิน Android ที่มีอยู่แล้ว ให้ทำตามขั้นตอนต่อไปนี้
- ประกาศการมอบสิทธิ์ที่รองรับ
- แยกวิเคราะห์
PAY
ส่วนเพิ่มเติมของ Intent สำหรับตัวเลือกการชำระเงินที่จำเป็น - ระบุข้อมูลที่จำเป็นในการตอบกลับการชำระเงิน
- ไม่บังคับ: รองรับโฟลว์แบบไดนามิก
ประกาศการมอบสิทธิ์ที่รองรับ
เบราว์เซอร์ต้องทราบรายการข้อมูลเพิ่มเติมที่แอปการชำระเงินของคุณระบุได้ เพื่อให้สามารถมอบสิทธิ์ในการเก็บรวบรวมข้อมูลดังกล่าวให้กับแอปของคุณ ประกาศการมอบสิทธิ์ที่รองรับเป็น <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
ที่มีค่าสตริงcurrency
แสดงสกุลเงินของค่าจัดส่งเป็นรหัสตัวอักษร 3 ตัวที่ถูกต้องตามรูปแบบ ISO4217value
แสดงค่าของค่าจัดส่งเป็นค่าทศนิยมทางการเงินที่ถูกต้อง
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 optionserror
- สตริงที่มีข้อความแสดงข้อผิดพลาดทั่วไป (เช่น เมื่อchangeShippingOption
ไม่ได้ระบุตัวระบุตัวเลือกการจัดส่งที่ถูกต้อง)stringifiedPaymentMethodErrors
- สตริง JSON ที่แสดงข้อผิดพลาดในการตรวจสอบ วิธีการชำระเงินaddressErrors
- ชุดที่มีคีย์ที่ไม่บังคับซึ่งเหมือนกับ shipping address และค่าสตริง คีย์แต่ละรายการแสดงข้อผิดพลาดในการตรวจสอบที่เกี่ยวข้องกับส่วนที่สอดคล้องกันของที่อยู่จัดส่งmodifiers
- อาร์เรย์ที่ส่งผ่านได้ของ Bundle แต่ละรายการมีฟิลด์total
และmethodData
ซึ่งเป็น Bundle ด้วย
คีย์ที่ไม่มีหมายความว่าค่าของคีย์นั้นไม่มีการเปลี่ยนแปลง